commit 764b6034e3ae4efc694da366fbcd566ba7e68047 Author: PartyDonut <42371342+PartyDonut@users.noreply.github.com> Date: Sun Sep 15 14:12:28 2024 +0200 Init repo diff --git a/.fvmrc b/.fvmrc new file mode 100644 index 0000000..4efffa7 --- /dev/null +++ b/.fvmrc @@ -0,0 +1,3 @@ +{ + "flutter": "3.22.1" +} \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..b087aa8 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,201 @@ +name: Build Fladder + +on: + push: + branches: + - develop + pull_request: + branches: + - develop + +jobs: + #Implement linting/tests here first + flutter-checks: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4.1.1 + + - name: Set up Flutter + uses: subosito/flutter-action@v2.12.0 + with: + channel: "stable" + cache: true + cache-key: "flutter-:os:-:channel:-:version:-:arch:-:hash:" # optional, change this to force refresh cache + cache-path: "${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:" # optional, change this to specify the cache path + + - name: Get dependencies + run: flutter pub get + + build-android: + needs: flutter-checks + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4.1.1 + + - name: Set up Flutter + uses: subosito/flutter-action@v2.12.0 + with: + channel: "stable" + cache: true + cache-key: "flutter-:os:-:channel:-:version:-:arch:-:hash:" # optional, change this to force refresh cache + cache-path: "${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:" # optional, change this to specify the cache path + + - name: Get dependencies + run: flutter pub get + + - name: Build Android APK + run: flutter build apk + + - name: Archive Android artifact + uses: actions/upload-artifact@v4.0.0 + with: + name: Android + path: build/app/outputs/apk/release/app-release.apk + + build-windows: + needs: flutter-checks + runs-on: windows-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4.1.1 + + - name: Set up Flutter + uses: subosito/flutter-action@v2.12.0 + with: + channel: "stable" + cache: true + cache-key: "flutter-:os:-:channel:-:version:-:arch:-:hash:" # optional, change this to force refresh cache + cache-path: "${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:" # optional, change this to specify the cache path + + - name: Get dependencies + run: flutter pub get + + - name: Build Windows EXE + run: flutter build windows + + - name: Archive Windows artifact + uses: actions/upload-artifact@v4.0.0 + with: + name: Windows + path: build\windows\x64\runner\Release\ + + # build-ios: + # runs-on: macos-latest + + # steps: + # - name: Checkout repository + # uses: actions/checkout@v4.1.1 + + # - name: Set up Flutter + # uses: subosito/flutter-action@v2.12.0 + # with: + # channel: "stable" + # cache: true + # cache-key: "flutter-:os:-:channel:-:version:-:arch:-:hash:" # optional, change this to force refresh cache + # cache-path: "${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:" # optional, change this to specify the cache path + + # - name: Get dependencies + # run: flutter pub get + + # - name: Build iOS app + # run: flutter build ios + + # - name: Archive iOS artifact + # uses: actions/upload-artifact@v2 + # with: + # name: ios + # path: build/ios/iphoneos/Runner.app + + build-macos: + needs: flutter-checks + runs-on: macos-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4.1.1 + + - name: Set up Flutter + uses: subosito/flutter-action@v2.12.0 + with: + channel: "stable" + cache: true + cache-key: "flutter-:os:-:channel:-:version:-:arch:-:hash:" # optional, change this to force refresh cache + cache-path: "${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:" # optional, change this to specify the cache path + + - name: Get dependencies + run: flutter pub get + + - name: Build macOS app + run: flutter build macos + + - name: Archive macOS artifact + uses: actions/upload-artifact@v4.0.0 + with: + name: macOS + path: build/macos/Build/Products/Release/fladder.app + + # build-linux: + # needs: flutter-checks + # runs-on: ubuntu-latest + + # steps: + # - name: Checkout repository + # uses: actions/checkout@v4.1.1 + + # - name: Set up Flutter + # uses: subosito/flutter-action@v2.12.0 + # with: + # channel: "stable" + # cache: true + # cache-key: "flutter-:os:-:channel:-:version:-:arch:-:hash:" # optional, change this to force refresh cache + # cache-path: "${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:" # optional, change this to specify the cache path + + # - name: Get dependencies + # run: flutter pub get + + # - name: Get packages + # run: | + # sudo apt-get update -y + # sudo apt-get install -y ninja-build libgtk-3-dev + + # - name: Build Linux app + # run: flutter build linux + + # - name: Archive Linux artifact + # uses: actions/upload-artifact@v2 + # with: + # name: linux + # path: build/linux/x64/release/bundle + + build-web: + needs: flutter-checks + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4.1.1 + + - name: Set up Flutter + uses: subosito/flutter-action@v2.12.0 + with: + channel: "stable" + cache: true + cache-key: "flutter-:os:-:channel:-:version:-:arch:-:hash:" # optional, change this to force refresh cache + cache-path: "${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:" # optional, change this to specify the cache path + + - name: Get dependencies + run: flutter pub get + + - name: Build web app + run: flutter build web + + - name: Archive web artifact + uses: actions/upload-artifact@v4.0.0 + with: + name: Web + path: build/web diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..43ae556 --- /dev/null +++ b/.gitignore @@ -0,0 +1,47 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release + +# FVM Version Cache +.fvm/ \ No newline at end of file diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..fce676f --- /dev/null +++ b/.metadata @@ -0,0 +1,30 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "2f708eb8396e362e280fac22cf171c2cb467343c" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 2f708eb8396e362e280fac22cf171c2cb467343c + base_revision: 2f708eb8396e362e280fac22cf171c2cb467343c + - platform: android + create_revision: 2f708eb8396e362e280fac22cf171c2cb467343c + base_revision: 2f708eb8396e362e280fac22cf171c2cb467343c + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..ee0f98d --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,91 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "fladder", + "request": "launch", + "type": "dart", + "args": [ + "--web-port", + "8096" + ], + }, + { + "name": "fladder (profile mode)", + "request": "launch", + "type": "dart", + "flutterMode": "profile", + "args": [ + "--web-port", + "9090" + ], + }, + { + "name": "fladder (release mode)", + "request": "launch", + "type": "dart", + "flutterMode": "release", + "args": [ + "--web-port", + "9090" + ], + }, + { + "name": "Android", + "request": "launch", + "type": "dart", + }, + { + "name": "iPhone", + "request": "launch", + "type": "dart", + "deviceId": "iphone" + }, + { + "name": "Windows", + "request": "launch", + "type": "dart", + "flutterMode": "debug", + "deviceId": "windows" + }, + { + "name": "Web", + "request": "launch", + "type": "dart", + "deviceId": "chrome", + "args": [ + "--web-port", + "9090" + ], + }, + { + "name": "Web (release mode)", + "request": "launch", + "type": "dart", + "deviceId": "chrome", + "flutterMode": "release", + "args": [ + "--web-port", + "9090" + ], + }, + { + "name": "AndroidTV", + "request": "launch", + "program": "lib/android_tv/main.dart", + "type": "dart", + }, + ], + "compounds": [ + { + "name": "All Devices", + "configurations": [ + "Windows", + "Android" + ], + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..26a7a6d --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,12 @@ +{ + "cSpell.words": [ + "Jellyfin" + ], + "dart.flutterSdkPath": ".fvm/versions/3.22.1", + "search.exclude": { + "**/.fvm": true + }, + "files.watcherExclude": { + "**/.fvm": true + } +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..e4930d3 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,86 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Generate Localization", + "type": "dart", + "command": "flutter", + "args": [ + "gen-l10n" + ], + "isBackground": true, + "presentation": { + "reveal": "never", + "revealProblems": "onProblem", + "panel": "dedicated", + "showReuseMessage": false, + "clear": true, + "focus": false + }, + "problemMatcher": [] + }, + { + "type": "flutter", + "command": "flutter", + "args": [ + "build", + "windows" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [], + "label": "flutter: flutter build windows", + "detail": "" + }, + { + "type": "flutter", + "command": "flutter", + "args": [ + "build", + "macos" + ], + "group": "build", + "problemMatcher": [], + "label": "flutter: flutter build macos", + "detail": "" + }, + { + "type": "flutter", + "command": "flutter", + "args": [ + "build", + "apk" + ], + "group": "build", + "problemMatcher": [], + "label": "flutter: flutter build apk", + "detail": "" + }, + { + "type": "flutter", + "command": "flutter", + "args": [ + "build", + "aab" + ], + "group": "build", + "problemMatcher": [], + "label": "flutter: flutter build aab", + "detail": "" + }, + { + "type": "flutter", + "command": "dart", + "args": [ + "run", + "flutter_launcher_icons" + ], + "group": "build", + "problemMatcher": [], + "label": "flutter: flutter create launcher icons", + "detail": "" + } + ], +} \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md new file mode 100644 index 0000000..6483cdd --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# fladder + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..615795d --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,19 @@ +include: package:lints/recommended.yaml + +analyzer: + exclude: [build/**, lib/jellyfin/**] + language: + # strict-casts: false + # strict-raw-types: true + plugins: + - custom_lint + +linter: + rules: + cancel_subscriptions: true + avoid_print: false # Uncomment to disable the `avoid_print` rule + no_logic_in_create_state: true + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + prefer_relative_imports: false + avoid_relative_lib_imports: true + eol_at_end_of_file: true diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..6f56801 --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..bd80375 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,77 @@ +plugins { + id "com.android.application" + id "kotlin-android" + id "dev.flutter.flutter-gradle-plugin" +} + +def keystoreProperties = new Properties() +def keystorePropertiesFile = rootProject.file('key.properties') +if (keystorePropertiesFile.exists()) { + keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) +} + +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +android { + compileSdkVersion flutter.compileSdkVersion + ndkVersion flutter.ndkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + applicationId "nl.jknaapen.fladder" + minSdkVersion 26 + targetSdkVersion flutter.targetSdkVersion + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + signingConfigs { + release { + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null + storePassword keystoreProperties['storePassword'] + } + } + + buildTypes { + release { + signingConfig signingConfigs.release + } + debug{ + applicationIdSuffix = ".debug" + } + } +} + +flutter { + source '../..' +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..16f7f90 --- /dev/null +++ b/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..09ec338 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/ic_launcher-playstore.png b/android/app/src/main/ic_launcher-playstore.png new file mode 100644 index 0000000..8c9490f Binary files /dev/null and b/android/app/src/main/ic_launcher-playstore.png differ diff --git a/android/app/src/main/kotlin/nl/jknaapen/fladder/MainActivity.kt b/android/app/src/main/kotlin/nl/jknaapen/fladder/MainActivity.kt new file mode 100644 index 0000000..9726f5e --- /dev/null +++ b/android/app/src/main/kotlin/nl/jknaapen/fladder/MainActivity.kt @@ -0,0 +1,7 @@ +package nl.jknaapen.fladder + +import io.flutter.embedding.android.FlutterFragmentActivity +import com.ryanheise.audioservice.AudioServiceFragmentActivity; + +class MainActivity: AudioServiceFragmentActivity () { +} diff --git a/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png b/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..641a97c Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png b/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..765a506 Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/drawable-v21/launch_background.xml b/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f74085f --- /dev/null +++ b/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png b/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..1a07d08 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..4254570 Binary files /dev/null and b/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..ff00efd Binary files /dev/null and b/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/drawable/ic_launcher_monochrome.png b/android/app/src/main/res/drawable/ic_launcher_monochrome.png new file mode 100644 index 0000000..c1e3c0d Binary files /dev/null and b/android/app/src/main/res/drawable/ic_launcher_monochrome.png differ diff --git a/android/app/src/main/res/drawable/ic_notification_icon.png b/android/app/src/main/res/drawable/ic_notification_icon.png new file mode 100644 index 0000000..b23b7d3 Binary files /dev/null and b/android/app/src/main/res/drawable/ic_notification_icon.png differ diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..2060ce9 --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..7154733 --- /dev/null +++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/android/app/src/main/res/mipmap-anydpi-v26/launcher_icon.xml b/android/app/src/main/res/mipmap-anydpi-v26/launcher_icon.xml new file mode 100644 index 0000000..5f349f7 --- /dev/null +++ b/android/app/src/main/res/mipmap-anydpi-v26/launcher_icon.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..7d20580 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..27f9d10 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..0f00592 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png differ diff --git a/android/app/src/main/res/mipmap-hdpi/launcher_icon.png b/android/app/src/main/res/mipmap-hdpi/launcher_icon.png new file mode 100644 index 0000000..72aa3ba Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..04ef308 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..e8c6939 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..a559866 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/launcher_icon.png b/android/app/src/main/res/mipmap-mdpi/launcher_icon.png new file mode 100644 index 0000000..834d3e7 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..03e68cd Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..4c67c8b Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..271201c Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png new file mode 100644 index 0000000..63834a7 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..438a6cd Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..1e555af Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..e9bc336 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png new file mode 100644 index 0000000..a01c718 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..fa7e110 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..5134d01 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..45cbe4a Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png new file mode 100644 index 0000000..bbdedaa Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..5f897b6 --- /dev/null +++ b/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,19 @@ + + + + + + + diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..2418954 --- /dev/null +++ b/android/app/src/main/res/values/colors.xml @@ -0,0 +1,4 @@ + + + #FF3A2101 + \ No newline at end of file diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..43cc1f9 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,19 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..16f7f90 --- /dev/null +++ b/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..8f31e8c --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,18 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} \ No newline at end of file diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..94adc3a --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..3c472b9 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5292beb --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,26 @@ +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + } + settings.ext.flutterSdkPath = flutterSdkPath() + + includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version "7.2.0" apply false + id "org.jetbrains.kotlin.android" version "1.9.0" apply false +} + +include ":app" \ No newline at end of file diff --git a/assets/fonts/mp-font.ttf b/assets/fonts/mp-font.ttf new file mode 100644 index 0000000..56d013f Binary files /dev/null and b/assets/fonts/mp-font.ttf differ diff --git a/assets/marketing/banner.afphoto b/assets/marketing/banner.afphoto new file mode 100644 index 0000000..1539318 Binary files /dev/null and b/assets/marketing/banner.afphoto differ diff --git a/assets/marketing/banner.png b/assets/marketing/banner.png new file mode 100644 index 0000000..46a5774 Binary files /dev/null and b/assets/marketing/banner.png differ diff --git a/assets/marketing/screenshots/Mobile/Dashboard.png b/assets/marketing/screenshots/Mobile/Dashboard.png new file mode 100644 index 0000000..9ad9c74 Binary files /dev/null and b/assets/marketing/screenshots/Mobile/Dashboard.png differ diff --git a/assets/marketing/screenshots/Mobile/Dashboard_2.png b/assets/marketing/screenshots/Mobile/Dashboard_2.png new file mode 100644 index 0000000..0fe0459 Binary files /dev/null and b/assets/marketing/screenshots/Mobile/Dashboard_2.png differ diff --git a/assets/marketing/screenshots/Mobile/Details.png b/assets/marketing/screenshots/Mobile/Details.png new file mode 100644 index 0000000..c56ccfd Binary files /dev/null and b/assets/marketing/screenshots/Mobile/Details.png differ diff --git a/assets/marketing/screenshots/Mobile/Details_2.png b/assets/marketing/screenshots/Mobile/Details_2.png new file mode 100644 index 0000000..e551f3e Binary files /dev/null and b/assets/marketing/screenshots/Mobile/Details_2.png differ diff --git a/assets/marketing/screenshots/Mobile/Favourites.png b/assets/marketing/screenshots/Mobile/Favourites.png new file mode 100644 index 0000000..585f1bb Binary files /dev/null and b/assets/marketing/screenshots/Mobile/Favourites.png differ diff --git a/assets/marketing/screenshots/Mobile/Library.png b/assets/marketing/screenshots/Mobile/Library.png new file mode 100644 index 0000000..e990197 Binary files /dev/null and b/assets/marketing/screenshots/Mobile/Library.png differ diff --git a/assets/marketing/screenshots/Mobile/Player.png b/assets/marketing/screenshots/Mobile/Player.png new file mode 100644 index 0000000..151a834 Binary files /dev/null and b/assets/marketing/screenshots/Mobile/Player.png differ diff --git a/assets/marketing/screenshots/Mobile/Resume_Tab.png b/assets/marketing/screenshots/Mobile/Resume_Tab.png new file mode 100644 index 0000000..2b918b1 Binary files /dev/null and b/assets/marketing/screenshots/Mobile/Resume_Tab.png differ diff --git a/assets/marketing/screenshots/Mobile/Settings.png b/assets/marketing/screenshots/Mobile/Settings.png new file mode 100644 index 0000000..6faa578 Binary files /dev/null and b/assets/marketing/screenshots/Mobile/Settings.png differ diff --git a/assets/marketing/screenshots/Mobile/Sync.png b/assets/marketing/screenshots/Mobile/Sync.png new file mode 100644 index 0000000..04f22fe Binary files /dev/null and b/assets/marketing/screenshots/Mobile/Sync.png differ diff --git a/assets/marketing/screenshots/Tablet/Dashboard.png b/assets/marketing/screenshots/Tablet/Dashboard.png new file mode 100644 index 0000000..ff361cd Binary files /dev/null and b/assets/marketing/screenshots/Tablet/Dashboard.png differ diff --git a/assets/marketing/screenshots/Tablet/Details.png b/assets/marketing/screenshots/Tablet/Details.png new file mode 100644 index 0000000..4944efe Binary files /dev/null and b/assets/marketing/screenshots/Tablet/Details.png differ diff --git a/assets/marketing/screenshots/Tablet/Settings.png b/assets/marketing/screenshots/Tablet/Settings.png new file mode 100644 index 0000000..5663fea Binary files /dev/null and b/assets/marketing/screenshots/Tablet/Settings.png differ diff --git a/assets/marketing/screenshots/Tablet/Sync.png b/assets/marketing/screenshots/Tablet/Sync.png new file mode 100644 index 0000000..8a2b677 Binary files /dev/null and b/assets/marketing/screenshots/Tablet/Sync.png differ diff --git a/build.yaml b/build.yaml new file mode 100644 index 0000000..27608e5 --- /dev/null +++ b/build.yaml @@ -0,0 +1,34 @@ +targets: + $default: + sources: + - lib/$lib$ + - "**/models/**.dart" # Matches models folder at any depth in lib + - "**/providers/**.dart" # Matches providers folder at any depth in lib + - lib/util/**.dart + - lib/jellyfin/**.dart + - swagger/** + - $package$ + builders: + freezed|freezed: + options: + generate_for: + - "**/**.f.dart" + - "**/**.g.dart" + dart_mappable_builder: + options: + ignoreNull: true + discriminatorKey: type + generateMethods: [decode, encode, copy, stringify] + swagger_dart_code_generator: + options: + input_folder: "swagger/" + output_folder: "lib/jellyfin/" + with_converter: true + build_only_models: false + with_base_url: false + include_if_null: false + auto_apply: dependents + chopper_generator: + options: + header: "//Generated jellyfin api code" + include_if_null: false diff --git a/devtools_options.yaml b/devtools_options.yaml new file mode 100644 index 0000000..7e7e7f6 --- /dev/null +++ b/devtools_options.yaml @@ -0,0 +1 @@ +extensions: diff --git a/icons/fladder_adaptive_icon.png b/icons/fladder_adaptive_icon.png new file mode 100644 index 0000000..97a0d01 Binary files /dev/null and b/icons/fladder_adaptive_icon.png differ diff --git a/icons/fladder_icon.png b/icons/fladder_icon.png new file mode 100644 index 0000000..8f7af8d Binary files /dev/null and b/icons/fladder_icon.png differ diff --git a/icons/fladder_icon.svg b/icons/fladder_icon.svg new file mode 100644 index 0000000..1c33805 --- /dev/null +++ b/icons/fladder_icon.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/icons/fladder_icon_desktop.png b/icons/fladder_icon_desktop.png new file mode 100644 index 0000000..3c9d073 Binary files /dev/null and b/icons/fladder_icon_desktop.png differ diff --git a/icons/fladder_icon_grayscale.svg b/icons/fladder_icon_grayscale.svg new file mode 100644 index 0000000..b1d06ef --- /dev/null +++ b/icons/fladder_icon_grayscale.svg @@ -0,0 +1,19 @@ + + + + icon-transparent-white + + + + + diff --git a/icons/fladder_icon_outline.svg b/icons/fladder_icon_outline.svg new file mode 100644 index 0000000..5141bd6 --- /dev/null +++ b/icons/fladder_icon_outline.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/icons/fladder_store_icon.jpg b/icons/fladder_store_icon.jpg new file mode 100644 index 0000000..d49113e Binary files /dev/null and b/icons/fladder_store_icon.jpg differ diff --git a/icons_launcher.yaml b/icons_launcher.yaml new file mode 100644 index 0000000..56d59ab --- /dev/null +++ b/icons_launcher.yaml @@ -0,0 +1,23 @@ +icons_launcher: + image_path: "icons/fladder_icon.png" + platforms: + android: + adaptive_foreground_image: "icons/fladder_icon.png" + adaptive_background_color: "#3a2101" + adaptive_monochrome_image: "icons/fladder_adaptive_icon.png" + enable: true + ios: + image_path: "icons/fladder_icon.png" + enable: true + windows: + image_path: "icons/fladder_icon_desktop.png" + enable: true + macos: + image_path: "icons/fladder_icon_desktop.png" + enable: true + linux: + image_path: "icons/fladder_icon_desktop.png" + enable: true + web: + favicon_path: "icons/fladder_icon.png" + enable: true diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..7a7f987 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..9625e10 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 11.0 + + diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..ec97fc6 --- /dev/null +++ b/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..c4855bf --- /dev/null +++ b/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/ios/Podfile b/ios/Podfile new file mode 100644 index 0000000..6f0819c --- /dev/null +++ b/ios/Podfile @@ -0,0 +1,44 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '11.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +# target 'RunnerTests' do +# inherit! :search_paths +# end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/ios/Podfile.lock b/ios/Podfile.lock new file mode 100644 index 0000000..04805e4 --- /dev/null +++ b/ios/Podfile.lock @@ -0,0 +1,123 @@ +PODS: + - Flutter (1.0.0) + - flutter_custom_tabs (0.0.1): + - Flutter + - flutter_keyboard_visibility (0.0.1): + - Flutter + - FMDB (2.7.5): + - FMDB/standard (= 2.7.5) + - FMDB/standard (2.7.5) + - local_auth_ios (0.0.1): + - Flutter + - media_kit_libs_ios_video (1.0.4): + - Flutter + - media_kit_native_event_loop (1.0.0): + - Flutter + - media_kit_video (0.0.1): + - Flutter + - open_app_file (3.2.2): + - Flutter + - package_info_plus (0.4.5): + - Flutter + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - screen_brightness_ios (0.1.0): + - Flutter + - share_plus (0.0.1): + - Flutter + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + - sqflite (0.0.3): + - Flutter + - FMDB (>= 2.7.5) + - url_launcher_ios (0.0.1): + - Flutter + - volume_controller (0.0.1): + - Flutter + - wakelock_plus (0.0.1): + - Flutter + +DEPENDENCIES: + - Flutter (from `Flutter`) + - flutter_custom_tabs (from `.symlinks/plugins/flutter_custom_tabs/ios`) + - flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`) + - local_auth_ios (from `.symlinks/plugins/local_auth_ios/ios`) + - media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`) + - media_kit_native_event_loop (from `.symlinks/plugins/media_kit_native_event_loop/ios`) + - media_kit_video (from `.symlinks/plugins/media_kit_video/ios`) + - open_app_file (from `.symlinks/plugins/open_app_file/ios`) + - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) + - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) + - screen_brightness_ios (from `.symlinks/plugins/screen_brightness_ios/ios`) + - share_plus (from `.symlinks/plugins/share_plus/ios`) + - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) + - sqflite (from `.symlinks/plugins/sqflite/ios`) + - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) + - volume_controller (from `.symlinks/plugins/volume_controller/ios`) + - wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`) + +SPEC REPOS: + trunk: + - FMDB + +EXTERNAL SOURCES: + Flutter: + :path: Flutter + flutter_custom_tabs: + :path: ".symlinks/plugins/flutter_custom_tabs/ios" + flutter_keyboard_visibility: + :path: ".symlinks/plugins/flutter_keyboard_visibility/ios" + local_auth_ios: + :path: ".symlinks/plugins/local_auth_ios/ios" + media_kit_libs_ios_video: + :path: ".symlinks/plugins/media_kit_libs_ios_video/ios" + media_kit_native_event_loop: + :path: ".symlinks/plugins/media_kit_native_event_loop/ios" + media_kit_video: + :path: ".symlinks/plugins/media_kit_video/ios" + open_app_file: + :path: ".symlinks/plugins/open_app_file/ios" + package_info_plus: + :path: ".symlinks/plugins/package_info_plus/ios" + path_provider_foundation: + :path: ".symlinks/plugins/path_provider_foundation/darwin" + screen_brightness_ios: + :path: ".symlinks/plugins/screen_brightness_ios/ios" + share_plus: + :path: ".symlinks/plugins/share_plus/ios" + shared_preferences_foundation: + :path: ".symlinks/plugins/shared_preferences_foundation/darwin" + sqflite: + :path: ".symlinks/plugins/sqflite/ios" + url_launcher_ios: + :path: ".symlinks/plugins/url_launcher_ios/ios" + volume_controller: + :path: ".symlinks/plugins/volume_controller/ios" + wakelock_plus: + :path: ".symlinks/plugins/wakelock_plus/ios" + +SPEC CHECKSUMS: + Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 + flutter_custom_tabs: 7a10a08686955cb748e5d26e0ae586d30689bf89 + flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069 + FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a + local_auth_ios: c6cf091ded637a88f24f86a8875d8b0f526e2605 + media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1 + media_kit_native_event_loop: e6b2ab20cf0746eb1c33be961fcf79667304fa2a + media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e + open_app_file: 205f73051668bfbd68356005fef8a62e620f0a77 + package_info_plus: fd030dabf36271f146f1f3beacd48f564b0f17f7 + path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 + screen_brightness_ios: 715ca807df953bf676d339f11464e438143ee625 + share_plus: 599aa54e4ea31d4b4c0e9c911bcc26c55e791028 + shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126 + sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a + url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4 + volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9 + wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47 + +PODFILE CHECKSUM: b17e1ecfe97aba85f3997d462fe23d9e4313a8d8 + +COCOAPODS: 1.12.1 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..b218f13 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,552 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + AF256235717D541C6829FCCA /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6491C6E6EEFED2BFC7A6FC05 /* Pods_Runner.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 2BF4D6238D8B78527D21C6CB /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 5DF199BABDE44234F6FCA67E /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 6491C6E6EEFED2BFC7A6FC05 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + FD72D79B55DE51CBA804286B /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + AF256235717D541C6829FCCA /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 2E0CCE82F6B1858285D1A2E5 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 6491C6E6EEFED2BFC7A6FC05 /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + D63BCD4D095DD80EE68A45ED /* Pods */, + 2E0CCE82F6B1858285D1A2E5 /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + D63BCD4D095DD80EE68A45ED /* Pods */ = { + isa = PBXGroup; + children = ( + 5DF199BABDE44234F6FCA67E /* Pods-Runner.debug.xcconfig */, + 2BF4D6238D8B78527D21C6CB /* Pods-Runner.release.xcconfig */, + FD72D79B55DE51CBA804286B /* Pods-Runner.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + CA81B010B7E6F27F7998D87E /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 421CFF88976D64EECF7D5F00 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1430; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 421CFF88976D64EECF7D5F00 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; + CA81B010B7E6F27F7998D87E /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = nl.jknaapen.fladder; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = nl.jknaapen.fladder; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = nl.jknaapen.fladder; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..a6b826d --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..21a3cc1 --- /dev/null +++ b/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..70693e4 --- /dev/null +++ b/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..eabd851 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images": [ + { + "filename": "Icon-App-20x20@2x.png", + "idiom": "iphone", + "scale": "2x", + "size": "20x20" + }, + { + "filename": "Icon-App-20x20@3x.png", + "idiom": "iphone", + "scale": "3x", + "size": "20x20" + }, + { + "filename": "Icon-App-29x29@1x.png", + "idiom": "iphone", + "scale": "1x", + "size": "29x29" + }, + { + "filename": "Icon-App-29x29@2x.png", + "idiom": "iphone", + "scale": "2x", + "size": "29x29" + }, + { + "filename": "Icon-App-29x29@3x.png", + "idiom": "iphone", + "scale": "3x", + "size": "29x29" + }, + { + "filename": "Icon-App-40x40@2x.png", + "idiom": "iphone", + "scale": "2x", + "size": "40x40" + }, + { + "filename": "Icon-App-40x40@3x.png", + "idiom": "iphone", + "scale": "3x", + "size": "40x40" + }, + { + "filename": "Icon-App-60x60@2x.png", + "idiom": "iphone", + "scale": "2x", + "size": "60x60" + }, + { + "filename": "Icon-App-60x60@3x.png", + "idiom": "iphone", + "scale": "3x", + "size": "60x60" + }, + { + "filename": "Icon-App-20x20@1x.png", + "idiom": "ipad", + "scale": "1x", + "size": "20x20" + }, + { + "filename": "Icon-App-20x20@2x.png", + "idiom": "ipad", + "scale": "2x", + "size": "20x20" + }, + { + "filename": "Icon-App-29x29@1x.png", + "idiom": "ipad", + "scale": "1x", + "size": "29x29" + }, + { + "filename": "Icon-App-29x29@2x.png", + "idiom": "ipad", + "scale": "2x", + "size": "29x29" + }, + { + "filename": "Icon-App-40x40@1x.png", + "idiom": "ipad", + "scale": "1x", + "size": "40x40" + }, + { + "filename": "Icon-App-40x40@2x.png", + "idiom": "ipad", + "scale": "2x", + "size": "40x40" + }, + { + "filename": "Icon-App-76x76@1x.png", + "idiom": "ipad", + "scale": "1x", + "size": "76x76" + }, + { + "filename": "Icon-App-76x76@2x.png", + "idiom": "ipad", + "scale": "2x", + "size": "76x76" + }, + { + "filename": "Icon-App-83.5x83.5@2x.png", + "idiom": "ipad", + "scale": "2x", + "size": "83.5x83.5" + }, + { + "filename": "Icon-App-1024x1024@1x.png", + "idiom": "ios-marketing", + "scale": "1x", + "size": "1024x1024" + } + ], + "info": { + "author": "icons_launcher", + "version": 1 + } +} \ No newline at end of file diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000..a690e5b Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..42e1291 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..065029f Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..b06d38c Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..191514f Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..dd9fe9a Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..7bbe2d2 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..065029f Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..2576a08 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..f2f0310 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png new file mode 100644 index 0000000..8868e07 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png new file mode 100644 index 0000000..22764a5 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png new file mode 100644 index 0000000..5d5ee48 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png new file mode 100644 index 0000000..d35c6d4 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000..f2f0310 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..0cb29ab Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png new file mode 100644 index 0000000..7e3c8f2 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png new file mode 100644 index 0000000..dec6ce9 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..edc5e73 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..0df8d7b Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..b86794e Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/ios/Runner/Base.lproj/LaunchScreen.storyboard b/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner/Base.lproj/Main.storyboard b/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist new file mode 100644 index 0000000..b6d932b --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,51 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Fladder + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Fladder + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + + diff --git a/ios/Runner/Runner-Bridging-Header.h b/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..308a2a5 --- /dev/null +++ b/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/l10n.yaml b/l10n.yaml new file mode 100644 index 0000000..1d24c57 --- /dev/null +++ b/l10n.yaml @@ -0,0 +1,5 @@ +arb-dir: lib/l10n +template-arb-file: app_en.arb +output-localization-file: app_localizations.dart +nullable-getter: false +untranslated-messages-file: lib/l10n/l10n_errors.txt diff --git a/lib/android_tv/main.dart b/lib/android_tv/main.dart new file mode 100644 index 0000000..7e72d46 --- /dev/null +++ b/lib/android_tv/main.dart @@ -0,0 +1,53 @@ +import 'package:fladder/providers/shared_provider.dart'; +import 'package:fladder/util/application_info.dart'; +import 'package:fladder/util/string_extensions.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:logging/logging.dart'; +import 'package:media_kit/media_kit.dart'; +import 'package:package_info_plus/package_info_plus.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +void main() async { + _setupLogging(); + WidgetsFlutterBinding.ensureInitialized(); + MediaKit.ensureInitialized(); + + final sharedPreferences = await SharedPreferences.getInstance(); + + PackageInfo packageInfo = await PackageInfo.fromPlatform(); + + runApp( + ProviderScope( + overrides: [ + sharedPreferencesProvider.overrideWith((ref) => sharedPreferences), + applicationInfoProvider.overrideWith((ref) => ApplicationInfo( + name: packageInfo.appName, version: packageInfo.version, os: defaultTargetPlatform.name.capitalize())), + ], + child: const Main(), + ), + ); +} + +void _setupLogging() { + Logger.root.level = Level.ALL; + Logger.root.onRecord.listen((rec) { + if (kDebugMode) { + print('${rec.level.name}: ${rec.time}: ${rec.message}'); + } + }); +} + +class Main extends ConsumerWidget { + const Main({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return const MaterialApp( + home: Scaffold( + body: Center(child: Text("AndroidTV")), + ), + ); + } +} diff --git a/lib/jellyfin/client_index.dart b/lib/jellyfin/client_index.dart new file mode 100644 index 0000000..692ce91 --- /dev/null +++ b/lib/jellyfin/client_index.dart @@ -0,0 +1 @@ +export 'jellyfin_open_api.swagger.dart' show JellyfinOpenApi; diff --git a/lib/jellyfin/client_mapping.dart b/lib/jellyfin/client_mapping.dart new file mode 100644 index 0000000..1b4bf0d --- /dev/null +++ b/lib/jellyfin/client_mapping.dart @@ -0,0 +1 @@ +final Map)> generatedMapping = {}; diff --git a/lib/jellyfin/enum_models.dart b/lib/jellyfin/enum_models.dart new file mode 100644 index 0000000..44b634f --- /dev/null +++ b/lib/jellyfin/enum_models.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; +import 'package:collection/collection.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/util/localization_helper.dart'; + +enum MetadataRefresh { + defaultRefresh(MetadataRefreshMode.$default), + validation(MetadataRefreshMode.validationonly), + fullRefresh(MetadataRefreshMode.fullrefresh); + + const MetadataRefresh(this.api); + + final MetadataRefreshMode api; + String label(BuildContext context) { + return switch (this) { + defaultRefresh => context.localized.metadataRefreshDefault, + validation => context.localized.metadataRefreshValidation, + fullRefresh => context.localized.metadataRefreshFull, + }; + } + + ItemsItemIdRefreshPostMetadataRefreshMode? get metadataRefreshMode => switch (this) { + MetadataRefresh.fullRefresh => ItemsItemIdRefreshPostMetadataRefreshMode.fullrefresh, + MetadataRefresh.validation => ItemsItemIdRefreshPostMetadataRefreshMode.validationonly, + _ => ItemsItemIdRefreshPostMetadataRefreshMode.$default + }; + + ItemsItemIdRefreshPostImageRefreshMode? get imageRefreshMode => switch (this) { + MetadataRefresh.fullRefresh => ItemsItemIdRefreshPostImageRefreshMode.fullrefresh, + MetadataRefresh.validation => ItemsItemIdRefreshPostImageRefreshMode.validationonly, + _ => ItemsItemIdRefreshPostImageRefreshMode.$default + }; +} + +enum ItemLocation { + filesystem('FileSystem'), + remote('Remote'), + virtual('Virtual'), + offline('Offline'); + + final String? value; + + factory ItemLocation.fromDto(LocationType? type) => + ItemLocation.values.firstWhereOrNull((element) => type?.value == element.value) ?? ItemLocation.filesystem; + + const ItemLocation(this.value); +} diff --git a/lib/jellyfin/jellyfin_open_api.enums.swagger.dart b/lib/jellyfin/jellyfin_open_api.enums.swagger.dart new file mode 100644 index 0000000..68809e0 --- /dev/null +++ b/lib/jellyfin/jellyfin_open_api.enums.swagger.dart @@ -0,0 +1,5318 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:collection/collection.dart'; + +enum AnalysisMode { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Introduction') + introduction('Introduction'), + @JsonValue('Credits') + credits('Credits'); + + final String? value; + + const AnalysisMode(this.value); +} + +enum AudioSpatialFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('None') + none('None'), + @JsonValue('DolbyAtmos') + dolbyatmos('DolbyAtmos'), + @JsonValue('DTSX') + dtsx('DTSX'); + + final String? value; + + const AudioSpatialFormat(this.value); +} + +enum BaseItemKind { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('AggregateFolder') + aggregatefolder('AggregateFolder'), + @JsonValue('Audio') + audio('Audio'), + @JsonValue('AudioBook') + audiobook('AudioBook'), + @JsonValue('BasePluginFolder') + basepluginfolder('BasePluginFolder'), + @JsonValue('Book') + book('Book'), + @JsonValue('BoxSet') + boxset('BoxSet'), + @JsonValue('Channel') + channel('Channel'), + @JsonValue('ChannelFolderItem') + channelfolderitem('ChannelFolderItem'), + @JsonValue('CollectionFolder') + collectionfolder('CollectionFolder'), + @JsonValue('Episode') + episode('Episode'), + @JsonValue('Folder') + folder('Folder'), + @JsonValue('Genre') + genre('Genre'), + @JsonValue('ManualPlaylistsFolder') + manualplaylistsfolder('ManualPlaylistsFolder'), + @JsonValue('Movie') + movie('Movie'), + @JsonValue('LiveTvChannel') + livetvchannel('LiveTvChannel'), + @JsonValue('LiveTvProgram') + livetvprogram('LiveTvProgram'), + @JsonValue('MusicAlbum') + musicalbum('MusicAlbum'), + @JsonValue('MusicArtist') + musicartist('MusicArtist'), + @JsonValue('MusicGenre') + musicgenre('MusicGenre'), + @JsonValue('MusicVideo') + musicvideo('MusicVideo'), + @JsonValue('Person') + person('Person'), + @JsonValue('Photo') + photo('Photo'), + @JsonValue('PhotoAlbum') + photoalbum('PhotoAlbum'), + @JsonValue('Playlist') + playlist('Playlist'), + @JsonValue('PlaylistsFolder') + playlistsfolder('PlaylistsFolder'), + @JsonValue('Program') + program('Program'), + @JsonValue('Recording') + recording('Recording'), + @JsonValue('Season') + season('Season'), + @JsonValue('Series') + series('Series'), + @JsonValue('Studio') + studio('Studio'), + @JsonValue('Trailer') + trailer('Trailer'), + @JsonValue('TvChannel') + tvchannel('TvChannel'), + @JsonValue('TvProgram') + tvprogram('TvProgram'), + @JsonValue('UserRootFolder') + userrootfolder('UserRootFolder'), + @JsonValue('UserView') + userview('UserView'), + @JsonValue('Video') + video('Video'), + @JsonValue('Year') + year('Year'); + + final String? value; + + const BaseItemKind(this.value); +} + +enum ChannelItemSortField { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Name') + name('Name'), + @JsonValue('CommunityRating') + communityrating('CommunityRating'), + @JsonValue('PremiereDate') + premieredate('PremiereDate'), + @JsonValue('DateCreated') + datecreated('DateCreated'), + @JsonValue('Runtime') + runtime('Runtime'), + @JsonValue('PlayCount') + playcount('PlayCount'), + @JsonValue('CommunityPlayCount') + communityplaycount('CommunityPlayCount'); + + final String? value; + + const ChannelItemSortField(this.value); +} + +enum ChannelMediaContentType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Clip') + clip('Clip'), + @JsonValue('Podcast') + podcast('Podcast'), + @JsonValue('Trailer') + trailer('Trailer'), + @JsonValue('Movie') + movie('Movie'), + @JsonValue('Episode') + episode('Episode'), + @JsonValue('Song') + song('Song'), + @JsonValue('MovieExtra') + movieextra('MovieExtra'), + @JsonValue('TvExtra') + tvextra('TvExtra'); + + final String? value; + + const ChannelMediaContentType(this.value); +} + +enum ChannelMediaType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Audio') + audio('Audio'), + @JsonValue('Video') + video('Video'), + @JsonValue('Photo') + photo('Photo'); + + final String? value; + + const ChannelMediaType(this.value); +} + +enum ChannelType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('TV') + tv('TV'), + @JsonValue('Radio') + radio('Radio'); + + final String? value; + + const ChannelType(this.value); +} + +enum CodecType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Video') + video('Video'), + @JsonValue('VideoAudio') + videoaudio('VideoAudio'), + @JsonValue('Audio') + audio('Audio'); + + final String? value; + + const CodecType(this.value); +} + +enum CollectionType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('unknown') + unknown('unknown'), + @JsonValue('movies') + movies('movies'), + @JsonValue('tvshows') + tvshows('tvshows'), + @JsonValue('music') + music('music'), + @JsonValue('musicvideos') + musicvideos('musicvideos'), + @JsonValue('trailers') + trailers('trailers'), + @JsonValue('homevideos') + homevideos('homevideos'), + @JsonValue('boxsets') + boxsets('boxsets'), + @JsonValue('books') + books('books'), + @JsonValue('photos') + photos('photos'), + @JsonValue('livetv') + livetv('livetv'), + @JsonValue('playlists') + playlists('playlists'), + @JsonValue('folders') + folders('folders'); + + final String? value; + + const CollectionType(this.value); +} + +enum CollectionTypeOptions { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('movies') + movies('movies'), + @JsonValue('tvshows') + tvshows('tvshows'), + @JsonValue('music') + music('music'), + @JsonValue('musicvideos') + musicvideos('musicvideos'), + @JsonValue('homevideos') + homevideos('homevideos'), + @JsonValue('boxsets') + boxsets('boxsets'), + @JsonValue('books') + books('books'), + @JsonValue('mixed') + mixed('mixed'); + + final String? value; + + const CollectionTypeOptions(this.value); +} + +enum DayOfWeek { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Sunday') + sunday('Sunday'), + @JsonValue('Monday') + monday('Monday'), + @JsonValue('Tuesday') + tuesday('Tuesday'), + @JsonValue('Wednesday') + wednesday('Wednesday'), + @JsonValue('Thursday') + thursday('Thursday'), + @JsonValue('Friday') + friday('Friday'), + @JsonValue('Saturday') + saturday('Saturday'); + + final String? value; + + const DayOfWeek(this.value); +} + +enum DayPattern { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Daily') + daily('Daily'), + @JsonValue('Weekdays') + weekdays('Weekdays'), + @JsonValue('Weekends') + weekends('Weekends'); + + final String? value; + + const DayPattern(this.value); +} + +enum DlnaProfileType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Audio') + audio('Audio'), + @JsonValue('Video') + video('Video'), + @JsonValue('Photo') + photo('Photo'), + @JsonValue('Subtitle') + subtitle('Subtitle'), + @JsonValue('Lyric') + lyric('Lyric'); + + final String? value; + + const DlnaProfileType(this.value); +} + +enum DownMixStereoAlgorithms { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('None') + none('None'), + @JsonValue('Dave750') + dave750('Dave750'), + @JsonValue('NightmodeDialogue') + nightmodedialogue('NightmodeDialogue'); + + final String? value; + + const DownMixStereoAlgorithms(this.value); +} + +enum DynamicDayOfWeek { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Sunday') + sunday('Sunday'), + @JsonValue('Monday') + monday('Monday'), + @JsonValue('Tuesday') + tuesday('Tuesday'), + @JsonValue('Wednesday') + wednesday('Wednesday'), + @JsonValue('Thursday') + thursday('Thursday'), + @JsonValue('Friday') + friday('Friday'), + @JsonValue('Saturday') + saturday('Saturday'), + @JsonValue('Everyday') + everyday('Everyday'), + @JsonValue('Weekday') + weekday('Weekday'), + @JsonValue('Weekend') + weekend('Weekend'); + + final String? value; + + const DynamicDayOfWeek(this.value); +} + +enum EmbeddedSubtitleOptions { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('AllowAll') + allowall('AllowAll'), + @JsonValue('AllowText') + allowtext('AllowText'), + @JsonValue('AllowImage') + allowimage('AllowImage'), + @JsonValue('AllowNone') + allownone('AllowNone'); + + final String? value; + + const EmbeddedSubtitleOptions(this.value); +} + +enum EncodingContext { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Streaming') + streaming('Streaming'), + @JsonValue('Static') + $static('Static'); + + final String? value; + + const EncodingContext(this.value); +} + +enum ExternalIdMediaType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Album') + album('Album'), + @JsonValue('AlbumArtist') + albumartist('AlbumArtist'), + @JsonValue('Artist') + artist('Artist'), + @JsonValue('BoxSet') + boxset('BoxSet'), + @JsonValue('Episode') + episode('Episode'), + @JsonValue('Movie') + movie('Movie'), + @JsonValue('OtherArtist') + otherartist('OtherArtist'), + @JsonValue('Person') + person('Person'), + @JsonValue('ReleaseGroup') + releasegroup('ReleaseGroup'), + @JsonValue('Season') + season('Season'), + @JsonValue('Series') + series('Series'), + @JsonValue('Track') + track('Track'), + @JsonValue('Book') + book('Book'); + + final String? value; + + const ExternalIdMediaType(this.value); +} + +enum ExtraType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Unknown') + unknown('Unknown'), + @JsonValue('Clip') + clip('Clip'), + @JsonValue('Trailer') + trailer('Trailer'), + @JsonValue('BehindTheScenes') + behindthescenes('BehindTheScenes'), + @JsonValue('DeletedScene') + deletedscene('DeletedScene'), + @JsonValue('Interview') + interview('Interview'), + @JsonValue('Scene') + scene('Scene'), + @JsonValue('Sample') + sample('Sample'), + @JsonValue('ThemeSong') + themesong('ThemeSong'), + @JsonValue('ThemeVideo') + themevideo('ThemeVideo'), + @JsonValue('Featurette') + featurette('Featurette'), + @JsonValue('Short') + short('Short'); + + final String? value; + + const ExtraType(this.value); +} + +enum FileSystemEntryType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('File') + file('File'), + @JsonValue('Directory') + directory('Directory'), + @JsonValue('NetworkComputer') + networkcomputer('NetworkComputer'), + @JsonValue('NetworkShare') + networkshare('NetworkShare'); + + final String? value; + + const FileSystemEntryType(this.value); +} + +enum ForgotPasswordAction { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('ContactAdmin') + contactadmin('ContactAdmin'), + @JsonValue('PinCode') + pincode('PinCode'), + @JsonValue('InNetworkRequired') + innetworkrequired('InNetworkRequired'); + + final String? value; + + const ForgotPasswordAction(this.value); +} + +enum GeneralCommandType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('MoveUp') + moveup('MoveUp'), + @JsonValue('MoveDown') + movedown('MoveDown'), + @JsonValue('MoveLeft') + moveleft('MoveLeft'), + @JsonValue('MoveRight') + moveright('MoveRight'), + @JsonValue('PageUp') + pageup('PageUp'), + @JsonValue('PageDown') + pagedown('PageDown'), + @JsonValue('PreviousLetter') + previousletter('PreviousLetter'), + @JsonValue('NextLetter') + nextletter('NextLetter'), + @JsonValue('ToggleOsd') + toggleosd('ToggleOsd'), + @JsonValue('ToggleContextMenu') + togglecontextmenu('ToggleContextMenu'), + @JsonValue('Select') + select('Select'), + @JsonValue('Back') + back('Back'), + @JsonValue('TakeScreenshot') + takescreenshot('TakeScreenshot'), + @JsonValue('SendKey') + sendkey('SendKey'), + @JsonValue('SendString') + sendstring('SendString'), + @JsonValue('GoHome') + gohome('GoHome'), + @JsonValue('GoToSettings') + gotosettings('GoToSettings'), + @JsonValue('VolumeUp') + volumeup('VolumeUp'), + @JsonValue('VolumeDown') + volumedown('VolumeDown'), + @JsonValue('Mute') + mute('Mute'), + @JsonValue('Unmute') + unmute('Unmute'), + @JsonValue('ToggleMute') + togglemute('ToggleMute'), + @JsonValue('SetVolume') + setvolume('SetVolume'), + @JsonValue('SetAudioStreamIndex') + setaudiostreamindex('SetAudioStreamIndex'), + @JsonValue('SetSubtitleStreamIndex') + setsubtitlestreamindex('SetSubtitleStreamIndex'), + @JsonValue('ToggleFullscreen') + togglefullscreen('ToggleFullscreen'), + @JsonValue('DisplayContent') + displaycontent('DisplayContent'), + @JsonValue('GoToSearch') + gotosearch('GoToSearch'), + @JsonValue('DisplayMessage') + displaymessage('DisplayMessage'), + @JsonValue('SetRepeatMode') + setrepeatmode('SetRepeatMode'), + @JsonValue('ChannelUp') + channelup('ChannelUp'), + @JsonValue('ChannelDown') + channeldown('ChannelDown'), + @JsonValue('Guide') + guide('Guide'), + @JsonValue('ToggleStats') + togglestats('ToggleStats'), + @JsonValue('PlayMediaSource') + playmediasource('PlayMediaSource'), + @JsonValue('PlayTrailers') + playtrailers('PlayTrailers'), + @JsonValue('SetShuffleQueue') + setshufflequeue('SetShuffleQueue'), + @JsonValue('PlayState') + playstate('PlayState'), + @JsonValue('PlayNext') + playnext('PlayNext'), + @JsonValue('ToggleOsdMenu') + toggleosdmenu('ToggleOsdMenu'), + @JsonValue('Play') + play('Play'), + @JsonValue('SetMaxStreamingBitrate') + setmaxstreamingbitrate('SetMaxStreamingBitrate'), + @JsonValue('SetPlaybackOrder') + setplaybackorder('SetPlaybackOrder'); + + final String? value; + + const GeneralCommandType(this.value); +} + +enum GroupQueueMode { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Queue') + queue('Queue'), + @JsonValue('QueueNext') + queuenext('QueueNext'); + + final String? value; + + const GroupQueueMode(this.value); +} + +enum GroupRepeatMode { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('RepeatOne') + repeatone('RepeatOne'), + @JsonValue('RepeatAll') + repeatall('RepeatAll'), + @JsonValue('RepeatNone') + repeatnone('RepeatNone'); + + final String? value; + + const GroupRepeatMode(this.value); +} + +enum GroupShuffleMode { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Sorted') + sorted('Sorted'), + @JsonValue('Shuffle') + shuffle('Shuffle'); + + final String? value; + + const GroupShuffleMode(this.value); +} + +enum GroupStateType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Idle') + idle('Idle'), + @JsonValue('Waiting') + waiting('Waiting'), + @JsonValue('Paused') + paused('Paused'), + @JsonValue('Playing') + playing('Playing'); + + final String? value; + + const GroupStateType(this.value); +} + +enum GroupUpdateType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('UserJoined') + userjoined('UserJoined'), + @JsonValue('UserLeft') + userleft('UserLeft'), + @JsonValue('GroupJoined') + groupjoined('GroupJoined'), + @JsonValue('GroupLeft') + groupleft('GroupLeft'), + @JsonValue('StateUpdate') + stateupdate('StateUpdate'), + @JsonValue('PlayQueue') + playqueue('PlayQueue'), + @JsonValue('NotInGroup') + notingroup('NotInGroup'), + @JsonValue('GroupDoesNotExist') + groupdoesnotexist('GroupDoesNotExist'), + @JsonValue('CreateGroupDenied') + creategroupdenied('CreateGroupDenied'), + @JsonValue('JoinGroupDenied') + joingroupdenied('JoinGroupDenied'), + @JsonValue('LibraryAccessDenied') + libraryaccessdenied('LibraryAccessDenied'); + + final String? value; + + const GroupUpdateType(this.value); +} + +enum HardwareEncodingType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('AMF') + amf('AMF'), + @JsonValue('QSV') + qsv('QSV'), + @JsonValue('NVENC') + nvenc('NVENC'), + @JsonValue('V4L2M2M') + v4l2m2m('V4L2M2M'), + @JsonValue('VAAPI') + vaapi('VAAPI'), + @JsonValue('VideoToolBox') + videotoolbox('VideoToolBox'), + @JsonValue('RKMPP') + rkmpp('RKMPP'); + + final String? value; + + const HardwareEncodingType(this.value); +} + +enum ImageFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const ImageFormat(this.value); +} + +enum ImageOrientation { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('TopLeft') + topleft('TopLeft'), + @JsonValue('TopRight') + topright('TopRight'), + @JsonValue('BottomRight') + bottomright('BottomRight'), + @JsonValue('BottomLeft') + bottomleft('BottomLeft'), + @JsonValue('LeftTop') + lefttop('LeftTop'), + @JsonValue('RightTop') + righttop('RightTop'), + @JsonValue('RightBottom') + rightbottom('RightBottom'), + @JsonValue('LeftBottom') + leftbottom('LeftBottom'); + + final String? value; + + const ImageOrientation(this.value); +} + +enum ImageResolution { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('MatchSource') + matchsource('MatchSource'), + @JsonValue('P144') + p144('P144'), + @JsonValue('P240') + p240('P240'), + @JsonValue('P360') + p360('P360'), + @JsonValue('P480') + p480('P480'), + @JsonValue('P720') + p720('P720'), + @JsonValue('P1080') + p1080('P1080'), + @JsonValue('P1440') + p1440('P1440'), + @JsonValue('P2160') + p2160('P2160'); + + final String? value; + + const ImageResolution(this.value); +} + +enum ImageSavingConvention { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Legacy') + legacy('Legacy'), + @JsonValue('Compatible') + compatible('Compatible'); + + final String? value; + + const ImageSavingConvention(this.value); +} + +enum ImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const ImageType(this.value); +} + +enum IsoType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Dvd') + dvd('Dvd'), + @JsonValue('BluRay') + bluray('BluRay'); + + final String? value; + + const IsoType(this.value); +} + +enum ItemFields { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('AirTime') + airtime('AirTime'), + @JsonValue('CanDelete') + candelete('CanDelete'), + @JsonValue('CanDownload') + candownload('CanDownload'), + @JsonValue('ChannelInfo') + channelinfo('ChannelInfo'), + @JsonValue('Chapters') + chapters('Chapters'), + @JsonValue('Trickplay') + trickplay('Trickplay'), + @JsonValue('ChildCount') + childcount('ChildCount'), + @JsonValue('CumulativeRunTimeTicks') + cumulativeruntimeticks('CumulativeRunTimeTicks'), + @JsonValue('CustomRating') + customrating('CustomRating'), + @JsonValue('DateCreated') + datecreated('DateCreated'), + @JsonValue('DateLastMediaAdded') + datelastmediaadded('DateLastMediaAdded'), + @JsonValue('DisplayPreferencesId') + displaypreferencesid('DisplayPreferencesId'), + @JsonValue('Etag') + etag('Etag'), + @JsonValue('ExternalUrls') + externalurls('ExternalUrls'), + @JsonValue('Genres') + genres('Genres'), + @JsonValue('HomePageUrl') + homepageurl('HomePageUrl'), + @JsonValue('ItemCounts') + itemcounts('ItemCounts'), + @JsonValue('MediaSourceCount') + mediasourcecount('MediaSourceCount'), + @JsonValue('MediaSources') + mediasources('MediaSources'), + @JsonValue('OriginalTitle') + originaltitle('OriginalTitle'), + @JsonValue('Overview') + overview('Overview'), + @JsonValue('ParentId') + parentid('ParentId'), + @JsonValue('Path') + path('Path'), + @JsonValue('People') + people('People'), + @JsonValue('PlayAccess') + playaccess('PlayAccess'), + @JsonValue('ProductionLocations') + productionlocations('ProductionLocations'), + @JsonValue('ProviderIds') + providerids('ProviderIds'), + @JsonValue('PrimaryImageAspectRatio') + primaryimageaspectratio('PrimaryImageAspectRatio'), + @JsonValue('RecursiveItemCount') + recursiveitemcount('RecursiveItemCount'), + @JsonValue('Settings') + settings('Settings'), + @JsonValue('ScreenshotImageTags') + screenshotimagetags('ScreenshotImageTags'), + @JsonValue('SeriesPrimaryImage') + seriesprimaryimage('SeriesPrimaryImage'), + @JsonValue('SeriesStudio') + seriesstudio('SeriesStudio'), + @JsonValue('SortName') + sortname('SortName'), + @JsonValue('SpecialEpisodeNumbers') + specialepisodenumbers('SpecialEpisodeNumbers'), + @JsonValue('Studios') + studios('Studios'), + @JsonValue('Taglines') + taglines('Taglines'), + @JsonValue('Tags') + tags('Tags'), + @JsonValue('RemoteTrailers') + remotetrailers('RemoteTrailers'), + @JsonValue('MediaStreams') + mediastreams('MediaStreams'), + @JsonValue('SeasonUserData') + seasonuserdata('SeasonUserData'), + @JsonValue('ServiceName') + servicename('ServiceName'), + @JsonValue('ThemeSongIds') + themesongids('ThemeSongIds'), + @JsonValue('ThemeVideoIds') + themevideoids('ThemeVideoIds'), + @JsonValue('ExternalEtag') + externaletag('ExternalEtag'), + @JsonValue('PresentationUniqueKey') + presentationuniquekey('PresentationUniqueKey'), + @JsonValue('InheritedParentalRatingValue') + inheritedparentalratingvalue('InheritedParentalRatingValue'), + @JsonValue('ExternalSeriesId') + externalseriesid('ExternalSeriesId'), + @JsonValue('SeriesPresentationUniqueKey') + seriespresentationuniquekey('SeriesPresentationUniqueKey'), + @JsonValue('DateLastRefreshed') + datelastrefreshed('DateLastRefreshed'), + @JsonValue('DateLastSaved') + datelastsaved('DateLastSaved'), + @JsonValue('RefreshState') + refreshstate('RefreshState'), + @JsonValue('ChannelImage') + channelimage('ChannelImage'), + @JsonValue('EnableMediaSourceDisplay') + enablemediasourcedisplay('EnableMediaSourceDisplay'), + @JsonValue('Width') + width('Width'), + @JsonValue('Height') + height('Height'), + @JsonValue('ExtraIds') + extraids('ExtraIds'), + @JsonValue('LocalTrailerCount') + localtrailercount('LocalTrailerCount'), + @JsonValue('IsHD') + ishd('IsHD'), + @JsonValue('SpecialFeatureCount') + specialfeaturecount('SpecialFeatureCount'); + + final String? value; + + const ItemFields(this.value); +} + +enum ItemFilter { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('IsFolder') + isfolder('IsFolder'), + @JsonValue('IsNotFolder') + isnotfolder('IsNotFolder'), + @JsonValue('IsUnplayed') + isunplayed('IsUnplayed'), + @JsonValue('IsPlayed') + isplayed('IsPlayed'), + @JsonValue('IsFavorite') + isfavorite('IsFavorite'), + @JsonValue('IsResumable') + isresumable('IsResumable'), + @JsonValue('Likes') + likes('Likes'), + @JsonValue('Dislikes') + dislikes('Dislikes'), + @JsonValue('IsFavoriteOrLikes') + isfavoriteorlikes('IsFavoriteOrLikes'); + + final String? value; + + const ItemFilter(this.value); +} + +enum ItemSortBy { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Default') + $default('Default'), + @JsonValue('AiredEpisodeOrder') + airedepisodeorder('AiredEpisodeOrder'), + @JsonValue('Album') + album('Album'), + @JsonValue('AlbumArtist') + albumartist('AlbumArtist'), + @JsonValue('Artist') + artist('Artist'), + @JsonValue('DateCreated') + datecreated('DateCreated'), + @JsonValue('OfficialRating') + officialrating('OfficialRating'), + @JsonValue('DatePlayed') + dateplayed('DatePlayed'), + @JsonValue('PremiereDate') + premieredate('PremiereDate'), + @JsonValue('StartDate') + startdate('StartDate'), + @JsonValue('SortName') + sortname('SortName'), + @JsonValue('Name') + name('Name'), + @JsonValue('Random') + random('Random'), + @JsonValue('Runtime') + runtime('Runtime'), + @JsonValue('CommunityRating') + communityrating('CommunityRating'), + @JsonValue('ProductionYear') + productionyear('ProductionYear'), + @JsonValue('PlayCount') + playcount('PlayCount'), + @JsonValue('CriticRating') + criticrating('CriticRating'), + @JsonValue('IsFolder') + isfolder('IsFolder'), + @JsonValue('IsUnplayed') + isunplayed('IsUnplayed'), + @JsonValue('IsPlayed') + isplayed('IsPlayed'), + @JsonValue('SeriesSortName') + seriessortname('SeriesSortName'), + @JsonValue('VideoBitRate') + videobitrate('VideoBitRate'), + @JsonValue('AirTime') + airtime('AirTime'), + @JsonValue('Studio') + studio('Studio'), + @JsonValue('IsFavoriteOrLiked') + isfavoriteorliked('IsFavoriteOrLiked'), + @JsonValue('DateLastContentAdded') + datelastcontentadded('DateLastContentAdded'), + @JsonValue('SeriesDatePlayed') + seriesdateplayed('SeriesDatePlayed'), + @JsonValue('ParentIndexNumber') + parentindexnumber('ParentIndexNumber'), + @JsonValue('IndexNumber') + indexnumber('IndexNumber'), + @JsonValue('SimilarityScore') + similarityscore('SimilarityScore'), + @JsonValue('SearchScore') + searchscore('SearchScore'); + + final String? value; + + const ItemSortBy(this.value); +} + +enum KeepUntil { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('UntilDeleted') + untildeleted('UntilDeleted'), + @JsonValue('UntilSpaceNeeded') + untilspaceneeded('UntilSpaceNeeded'), + @JsonValue('UntilWatched') + untilwatched('UntilWatched'), + @JsonValue('UntilDate') + untildate('UntilDate'); + + final String? value; + + const KeepUntil(this.value); +} + +enum LiveTvServiceStatus { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Ok') + ok('Ok'), + @JsonValue('Unavailable') + unavailable('Unavailable'); + + final String? value; + + const LiveTvServiceStatus(this.value); +} + +enum LocationType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('FileSystem') + filesystem('FileSystem'), + @JsonValue('Remote') + remote('Remote'), + @JsonValue('Virtual') + virtual('Virtual'), + @JsonValue('Offline') + offline('Offline'); + + final String? value; + + const LocationType(this.value); +} + +enum LogLevel { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Trace') + trace('Trace'), + @JsonValue('Debug') + debug('Debug'), + @JsonValue('Information') + information('Information'), + @JsonValue('Warning') + warning('Warning'), + @JsonValue('Error') + error('Error'), + @JsonValue('Critical') + critical('Critical'), + @JsonValue('None') + none('None'); + + final String? value; + + const LogLevel(this.value); +} + +enum MediaProtocol { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('File') + file('File'), + @JsonValue('Http') + http('Http'), + @JsonValue('Rtmp') + rtmp('Rtmp'), + @JsonValue('Rtsp') + rtsp('Rtsp'), + @JsonValue('Udp') + udp('Udp'), + @JsonValue('Rtp') + rtp('Rtp'), + @JsonValue('Ftp') + ftp('Ftp'); + + final String? value; + + const MediaProtocol(this.value); +} + +enum MediaSourceType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Default') + $default('Default'), + @JsonValue('Grouping') + grouping('Grouping'), + @JsonValue('Placeholder') + placeholder('Placeholder'); + + final String? value; + + const MediaSourceType(this.value); +} + +enum MediaStreamProtocol { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('http') + http('http'), + @JsonValue('hls') + hls('hls'); + + final String? value; + + const MediaStreamProtocol(this.value); +} + +enum MediaStreamType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Audio') + audio('Audio'), + @JsonValue('Video') + video('Video'), + @JsonValue('Subtitle') + subtitle('Subtitle'), + @JsonValue('EmbeddedImage') + embeddedimage('EmbeddedImage'), + @JsonValue('Data') + data('Data'), + @JsonValue('Lyric') + lyric('Lyric'); + + final String? value; + + const MediaStreamType(this.value); +} + +enum MediaType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Unknown') + unknown('Unknown'), + @JsonValue('Video') + video('Video'), + @JsonValue('Audio') + audio('Audio'), + @JsonValue('Photo') + photo('Photo'), + @JsonValue('Book') + book('Book'); + + final String? value; + + const MediaType(this.value); +} + +enum MetadataField { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Cast') + cast('Cast'), + @JsonValue('Genres') + genres('Genres'), + @JsonValue('ProductionLocations') + productionlocations('ProductionLocations'), + @JsonValue('Studios') + studios('Studios'), + @JsonValue('Tags') + tags('Tags'), + @JsonValue('Name') + name('Name'), + @JsonValue('Overview') + overview('Overview'), + @JsonValue('Runtime') + runtime('Runtime'), + @JsonValue('OfficialRating') + officialrating('OfficialRating'); + + final String? value; + + const MetadataField(this.value); +} + +enum MetadataRefreshMode { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('None') + none('None'), + @JsonValue('ValidationOnly') + validationonly('ValidationOnly'), + @JsonValue('Default') + $default('Default'), + @JsonValue('FullRefresh') + fullrefresh('FullRefresh'); + + final String? value; + + const MetadataRefreshMode(this.value); +} + +enum PersonKind { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Unknown') + unknown('Unknown'), + @JsonValue('Actor') + actor('Actor'), + @JsonValue('Director') + director('Director'), + @JsonValue('Composer') + composer('Composer'), + @JsonValue('Writer') + writer('Writer'), + @JsonValue('GuestStar') + gueststar('GuestStar'), + @JsonValue('Producer') + producer('Producer'), + @JsonValue('Conductor') + conductor('Conductor'), + @JsonValue('Lyricist') + lyricist('Lyricist'), + @JsonValue('Arranger') + arranger('Arranger'), + @JsonValue('Engineer') + engineer('Engineer'), + @JsonValue('Mixer') + mixer('Mixer'), + @JsonValue('Remixer') + remixer('Remixer'), + @JsonValue('Creator') + creator('Creator'), + @JsonValue('Artist') + artist('Artist'), + @JsonValue('AlbumArtist') + albumartist('AlbumArtist'), + @JsonValue('Author') + author('Author'), + @JsonValue('Illustrator') + illustrator('Illustrator'), + @JsonValue('Penciller') + penciller('Penciller'), + @JsonValue('Inker') + inker('Inker'), + @JsonValue('Colorist') + colorist('Colorist'), + @JsonValue('Letterer') + letterer('Letterer'), + @JsonValue('CoverArtist') + coverartist('CoverArtist'), + @JsonValue('Editor') + editor('Editor'), + @JsonValue('Translator') + translator('Translator'); + + final String? value; + + const PersonKind(this.value); +} + +enum PlayAccess { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Full') + full('Full'), + @JsonValue('None') + none('None'); + + final String? value; + + const PlayAccess(this.value); +} + +enum PlaybackErrorCode { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('NotAllowed') + notallowed('NotAllowed'), + @JsonValue('NoCompatibleStream') + nocompatiblestream('NoCompatibleStream'), + @JsonValue('RateLimitExceeded') + ratelimitexceeded('RateLimitExceeded'); + + final String? value; + + const PlaybackErrorCode(this.value); +} + +enum PlaybackOrder { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Default') + $default('Default'), + @JsonValue('Shuffle') + shuffle('Shuffle'); + + final String? value; + + const PlaybackOrder(this.value); +} + +enum PlaybackRequestType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Play') + play('Play'), + @JsonValue('SetPlaylistItem') + setplaylistitem('SetPlaylistItem'), + @JsonValue('RemoveFromPlaylist') + removefromplaylist('RemoveFromPlaylist'), + @JsonValue('MovePlaylistItem') + moveplaylistitem('MovePlaylistItem'), + @JsonValue('Queue') + queue('Queue'), + @JsonValue('Unpause') + unpause('Unpause'), + @JsonValue('Pause') + pause('Pause'), + @JsonValue('Stop') + stop('Stop'), + @JsonValue('Seek') + seek('Seek'), + @JsonValue('Buffer') + buffer('Buffer'), + @JsonValue('Ready') + ready('Ready'), + @JsonValue('NextItem') + nextitem('NextItem'), + @JsonValue('PreviousItem') + previousitem('PreviousItem'), + @JsonValue('SetRepeatMode') + setrepeatmode('SetRepeatMode'), + @JsonValue('SetShuffleMode') + setshufflemode('SetShuffleMode'), + @JsonValue('Ping') + ping('Ping'), + @JsonValue('IgnoreWait') + ignorewait('IgnoreWait'); + + final String? value; + + const PlaybackRequestType(this.value); +} + +enum PlayCommand { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('PlayNow') + playnow('PlayNow'), + @JsonValue('PlayNext') + playnext('PlayNext'), + @JsonValue('PlayLast') + playlast('PlayLast'), + @JsonValue('PlayInstantMix') + playinstantmix('PlayInstantMix'), + @JsonValue('PlayShuffle') + playshuffle('PlayShuffle'); + + final String? value; + + const PlayCommand(this.value); +} + +enum PlayMethod { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Transcode') + transcode('Transcode'), + @JsonValue('DirectStream') + directstream('DirectStream'), + @JsonValue('DirectPlay') + directplay('DirectPlay'); + + final String? value; + + const PlayMethod(this.value); +} + +enum PlayQueueUpdateReason { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('NewPlaylist') + newplaylist('NewPlaylist'), + @JsonValue('SetCurrentItem') + setcurrentitem('SetCurrentItem'), + @JsonValue('RemoveItems') + removeitems('RemoveItems'), + @JsonValue('MoveItem') + moveitem('MoveItem'), + @JsonValue('Queue') + queue('Queue'), + @JsonValue('QueueNext') + queuenext('QueueNext'), + @JsonValue('NextItem') + nextitem('NextItem'), + @JsonValue('PreviousItem') + previousitem('PreviousItem'), + @JsonValue('RepeatMode') + repeatmode('RepeatMode'), + @JsonValue('ShuffleMode') + shufflemode('ShuffleMode'); + + final String? value; + + const PlayQueueUpdateReason(this.value); +} + +enum PlaystateCommand { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Stop') + stop('Stop'), + @JsonValue('Pause') + pause('Pause'), + @JsonValue('Unpause') + unpause('Unpause'), + @JsonValue('NextTrack') + nexttrack('NextTrack'), + @JsonValue('PreviousTrack') + previoustrack('PreviousTrack'), + @JsonValue('Seek') + seek('Seek'), + @JsonValue('Rewind') + rewind('Rewind'), + @JsonValue('FastForward') + fastforward('FastForward'), + @JsonValue('PlayPause') + playpause('PlayPause'); + + final String? value; + + const PlaystateCommand(this.value); +} + +enum PluginStatus { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Active') + active('Active'), + @JsonValue('Restart') + restart('Restart'), + @JsonValue('Deleted') + deleted('Deleted'), + @JsonValue('Superceded') + superceded('Superceded'), + @JsonValue('Malfunctioned') + malfunctioned('Malfunctioned'), + @JsonValue('NotSupported') + notsupported('NotSupported'), + @JsonValue('Disabled') + disabled('Disabled'); + + final String? value; + + const PluginStatus(this.value); +} + +enum ProcessPriorityClass { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Normal') + normal('Normal'), + @JsonValue('Idle') + idle('Idle'), + @JsonValue('High') + high('High'), + @JsonValue('RealTime') + realtime('RealTime'), + @JsonValue('BelowNormal') + belownormal('BelowNormal'), + @JsonValue('AboveNormal') + abovenormal('AboveNormal'); + + final String? value; + + const ProcessPriorityClass(this.value); +} + +enum ProfileConditionType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Equals') + equals('Equals'), + @JsonValue('NotEquals') + notequals('NotEquals'), + @JsonValue('LessThanEqual') + lessthanequal('LessThanEqual'), + @JsonValue('GreaterThanEqual') + greaterthanequal('GreaterThanEqual'), + @JsonValue('EqualsAny') + equalsany('EqualsAny'); + + final String? value; + + const ProfileConditionType(this.value); +} + +enum ProfileConditionValue { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('AudioChannels') + audiochannels('AudioChannels'), + @JsonValue('AudioBitrate') + audiobitrate('AudioBitrate'), + @JsonValue('AudioProfile') + audioprofile('AudioProfile'), + @JsonValue('Width') + width('Width'), + @JsonValue('Height') + height('Height'), + @JsonValue('Has64BitOffsets') + has64bitoffsets('Has64BitOffsets'), + @JsonValue('PacketLength') + packetlength('PacketLength'), + @JsonValue('VideoBitDepth') + videobitdepth('VideoBitDepth'), + @JsonValue('VideoBitrate') + videobitrate('VideoBitrate'), + @JsonValue('VideoFramerate') + videoframerate('VideoFramerate'), + @JsonValue('VideoLevel') + videolevel('VideoLevel'), + @JsonValue('VideoProfile') + videoprofile('VideoProfile'), + @JsonValue('VideoTimestamp') + videotimestamp('VideoTimestamp'), + @JsonValue('IsAnamorphic') + isanamorphic('IsAnamorphic'), + @JsonValue('RefFrames') + refframes('RefFrames'), + @JsonValue('NumAudioStreams') + numaudiostreams('NumAudioStreams'), + @JsonValue('NumVideoStreams') + numvideostreams('NumVideoStreams'), + @JsonValue('IsSecondaryAudio') + issecondaryaudio('IsSecondaryAudio'), + @JsonValue('VideoCodecTag') + videocodectag('VideoCodecTag'), + @JsonValue('IsAvc') + isavc('IsAvc'), + @JsonValue('IsInterlaced') + isinterlaced('IsInterlaced'), + @JsonValue('AudioSampleRate') + audiosamplerate('AudioSampleRate'), + @JsonValue('AudioBitDepth') + audiobitdepth('AudioBitDepth'), + @JsonValue('VideoRangeType') + videorangetype('VideoRangeType'); + + final String? value; + + const ProfileConditionValue(this.value); +} + +enum ProgramAudio { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Mono') + mono('Mono'), + @JsonValue('Stereo') + stereo('Stereo'), + @JsonValue('Dolby') + dolby('Dolby'), + @JsonValue('DolbyDigital') + dolbydigital('DolbyDigital'), + @JsonValue('Thx') + thx('Thx'), + @JsonValue('Atmos') + atmos('Atmos'); + + final String? value; + + const ProgramAudio(this.value); +} + +enum RatingType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Score') + score('Score'), + @JsonValue('Likes') + likes('Likes'); + + final String? value; + + const RatingType(this.value); +} + +enum RecommendationType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('SimilarToRecentlyPlayed') + similartorecentlyplayed('SimilarToRecentlyPlayed'), + @JsonValue('SimilarToLikedItem') + similartolikeditem('SimilarToLikedItem'), + @JsonValue('HasDirectorFromRecentlyPlayed') + hasdirectorfromrecentlyplayed('HasDirectorFromRecentlyPlayed'), + @JsonValue('HasActorFromRecentlyPlayed') + hasactorfromrecentlyplayed('HasActorFromRecentlyPlayed'), + @JsonValue('HasLikedDirector') + haslikeddirector('HasLikedDirector'), + @JsonValue('HasLikedActor') + haslikedactor('HasLikedActor'); + + final String? value; + + const RecommendationType(this.value); +} + +enum RecordingStatus { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('New') + $new('New'), + @JsonValue('InProgress') + inprogress('InProgress'), + @JsonValue('Completed') + completed('Completed'), + @JsonValue('Cancelled') + cancelled('Cancelled'), + @JsonValue('ConflictedOk') + conflictedok('ConflictedOk'), + @JsonValue('ConflictedNotOk') + conflictednotok('ConflictedNotOk'), + @JsonValue('Error') + error('Error'); + + final String? value; + + const RecordingStatus(this.value); +} + +enum RepeatMode { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('RepeatNone') + repeatnone('RepeatNone'), + @JsonValue('RepeatAll') + repeatall('RepeatAll'), + @JsonValue('RepeatOne') + repeatone('RepeatOne'); + + final String? value; + + const RepeatMode(this.value); +} + +enum ScrollDirection { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Horizontal') + horizontal('Horizontal'), + @JsonValue('Vertical') + vertical('Vertical'); + + final String? value; + + const ScrollDirection(this.value); +} + +enum SendCommandType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Unpause') + unpause('Unpause'), + @JsonValue('Pause') + pause('Pause'), + @JsonValue('Stop') + stop('Stop'), + @JsonValue('Seek') + seek('Seek'); + + final String? value; + + const SendCommandType(this.value); +} + +enum SeriesStatus { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Continuing') + continuing('Continuing'), + @JsonValue('Ended') + ended('Ended'), + @JsonValue('Unreleased') + unreleased('Unreleased'); + + final String? value; + + const SeriesStatus(this.value); +} + +enum SessionMessageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('ForceKeepAlive') + forcekeepalive('ForceKeepAlive'), + @JsonValue('GeneralCommand') + generalcommand('GeneralCommand'), + @JsonValue('UserDataChanged') + userdatachanged('UserDataChanged'), + @JsonValue('Sessions') + sessions('Sessions'), + @JsonValue('Play') + play('Play'), + @JsonValue('SyncPlayCommand') + syncplaycommand('SyncPlayCommand'), + @JsonValue('SyncPlayGroupUpdate') + syncplaygroupupdate('SyncPlayGroupUpdate'), + @JsonValue('Playstate') + playstate('Playstate'), + @JsonValue('RestartRequired') + restartrequired('RestartRequired'), + @JsonValue('ServerShuttingDown') + servershuttingdown('ServerShuttingDown'), + @JsonValue('ServerRestarting') + serverrestarting('ServerRestarting'), + @JsonValue('LibraryChanged') + librarychanged('LibraryChanged'), + @JsonValue('UserDeleted') + userdeleted('UserDeleted'), + @JsonValue('UserUpdated') + userupdated('UserUpdated'), + @JsonValue('SeriesTimerCreated') + seriestimercreated('SeriesTimerCreated'), + @JsonValue('TimerCreated') + timercreated('TimerCreated'), + @JsonValue('SeriesTimerCancelled') + seriestimercancelled('SeriesTimerCancelled'), + @JsonValue('TimerCancelled') + timercancelled('TimerCancelled'), + @JsonValue('RefreshProgress') + refreshprogress('RefreshProgress'), + @JsonValue('ScheduledTaskEnded') + scheduledtaskended('ScheduledTaskEnded'), + @JsonValue('PackageInstallationCancelled') + packageinstallationcancelled('PackageInstallationCancelled'), + @JsonValue('PackageInstallationFailed') + packageinstallationfailed('PackageInstallationFailed'), + @JsonValue('PackageInstallationCompleted') + packageinstallationcompleted('PackageInstallationCompleted'), + @JsonValue('PackageInstalling') + packageinstalling('PackageInstalling'), + @JsonValue('PackageUninstalled') + packageuninstalled('PackageUninstalled'), + @JsonValue('ActivityLogEntry') + activitylogentry('ActivityLogEntry'), + @JsonValue('ScheduledTasksInfo') + scheduledtasksinfo('ScheduledTasksInfo'), + @JsonValue('ActivityLogEntryStart') + activitylogentrystart('ActivityLogEntryStart'), + @JsonValue('ActivityLogEntryStop') + activitylogentrystop('ActivityLogEntryStop'), + @JsonValue('SessionsStart') + sessionsstart('SessionsStart'), + @JsonValue('SessionsStop') + sessionsstop('SessionsStop'), + @JsonValue('ScheduledTasksInfoStart') + scheduledtasksinfostart('ScheduledTasksInfoStart'), + @JsonValue('ScheduledTasksInfoStop') + scheduledtasksinfostop('ScheduledTasksInfoStop'), + @JsonValue('KeepAlive') + keepalive('KeepAlive'); + + final String? value; + + const SessionMessageType(this.value); +} + +enum SortOrder { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Ascending') + ascending('Ascending'), + @JsonValue('Descending') + descending('Descending'); + + final String? value; + + const SortOrder(this.value); +} + +enum SubtitleDeliveryMethod { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Encode') + encode('Encode'), + @JsonValue('Embed') + embed('Embed'), + @JsonValue('External') + $external('External'), + @JsonValue('Hls') + hls('Hls'), + @JsonValue('Drop') + drop('Drop'); + + final String? value; + + const SubtitleDeliveryMethod(this.value); +} + +enum SubtitlePlaybackMode { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Default') + $default('Default'), + @JsonValue('Always') + always('Always'), + @JsonValue('OnlyForced') + onlyforced('OnlyForced'), + @JsonValue('None') + none('None'), + @JsonValue('Smart') + smart('Smart'); + + final String? value; + + const SubtitlePlaybackMode(this.value); +} + +enum SyncPlayUserAccessType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('CreateAndJoinGroups') + createandjoingroups('CreateAndJoinGroups'), + @JsonValue('JoinGroups') + joingroups('JoinGroups'), + @JsonValue('None') + none('None'); + + final String? value; + + const SyncPlayUserAccessType(this.value); +} + +enum TaskCompletionStatus { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Completed') + completed('Completed'), + @JsonValue('Failed') + failed('Failed'), + @JsonValue('Cancelled') + cancelled('Cancelled'), + @JsonValue('Aborted') + aborted('Aborted'); + + final String? value; + + const TaskCompletionStatus(this.value); +} + +enum TaskState { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Idle') + idle('Idle'), + @JsonValue('Cancelling') + cancelling('Cancelling'), + @JsonValue('Running') + running('Running'); + + final String? value; + + const TaskState(this.value); +} + +enum TranscodeReason { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('ContainerNotSupported') + containernotsupported('ContainerNotSupported'), + @JsonValue('VideoCodecNotSupported') + videocodecnotsupported('VideoCodecNotSupported'), + @JsonValue('AudioCodecNotSupported') + audiocodecnotsupported('AudioCodecNotSupported'), + @JsonValue('SubtitleCodecNotSupported') + subtitlecodecnotsupported('SubtitleCodecNotSupported'), + @JsonValue('AudioIsExternal') + audioisexternal('AudioIsExternal'), + @JsonValue('SecondaryAudioNotSupported') + secondaryaudionotsupported('SecondaryAudioNotSupported'), + @JsonValue('VideoProfileNotSupported') + videoprofilenotsupported('VideoProfileNotSupported'), + @JsonValue('VideoLevelNotSupported') + videolevelnotsupported('VideoLevelNotSupported'), + @JsonValue('VideoResolutionNotSupported') + videoresolutionnotsupported('VideoResolutionNotSupported'), + @JsonValue('VideoBitDepthNotSupported') + videobitdepthnotsupported('VideoBitDepthNotSupported'), + @JsonValue('VideoFramerateNotSupported') + videoframeratenotsupported('VideoFramerateNotSupported'), + @JsonValue('RefFramesNotSupported') + refframesnotsupported('RefFramesNotSupported'), + @JsonValue('AnamorphicVideoNotSupported') + anamorphicvideonotsupported('AnamorphicVideoNotSupported'), + @JsonValue('InterlacedVideoNotSupported') + interlacedvideonotsupported('InterlacedVideoNotSupported'), + @JsonValue('AudioChannelsNotSupported') + audiochannelsnotsupported('AudioChannelsNotSupported'), + @JsonValue('AudioProfileNotSupported') + audioprofilenotsupported('AudioProfileNotSupported'), + @JsonValue('AudioSampleRateNotSupported') + audiosampleratenotsupported('AudioSampleRateNotSupported'), + @JsonValue('AudioBitDepthNotSupported') + audiobitdepthnotsupported('AudioBitDepthNotSupported'), + @JsonValue('ContainerBitrateExceedsLimit') + containerbitrateexceedslimit('ContainerBitrateExceedsLimit'), + @JsonValue('VideoBitrateNotSupported') + videobitratenotsupported('VideoBitrateNotSupported'), + @JsonValue('AudioBitrateNotSupported') + audiobitratenotsupported('AudioBitrateNotSupported'), + @JsonValue('UnknownVideoStreamInfo') + unknownvideostreaminfo('UnknownVideoStreamInfo'), + @JsonValue('UnknownAudioStreamInfo') + unknownaudiostreaminfo('UnknownAudioStreamInfo'), + @JsonValue('DirectPlayError') + directplayerror('DirectPlayError'), + @JsonValue('VideoRangeTypeNotSupported') + videorangetypenotsupported('VideoRangeTypeNotSupported'); + + final String? value; + + const TranscodeReason(this.value); +} + +enum TranscodeSeekInfo { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Auto') + auto('Auto'), + @JsonValue('Bytes') + bytes('Bytes'); + + final String? value; + + const TranscodeSeekInfo(this.value); +} + +enum TranscodingInfoTranscodeReasons { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('ContainerNotSupported') + containernotsupported('ContainerNotSupported'), + @JsonValue('VideoCodecNotSupported') + videocodecnotsupported('VideoCodecNotSupported'), + @JsonValue('AudioCodecNotSupported') + audiocodecnotsupported('AudioCodecNotSupported'), + @JsonValue('SubtitleCodecNotSupported') + subtitlecodecnotsupported('SubtitleCodecNotSupported'), + @JsonValue('AudioIsExternal') + audioisexternal('AudioIsExternal'), + @JsonValue('SecondaryAudioNotSupported') + secondaryaudionotsupported('SecondaryAudioNotSupported'), + @JsonValue('VideoProfileNotSupported') + videoprofilenotsupported('VideoProfileNotSupported'), + @JsonValue('VideoLevelNotSupported') + videolevelnotsupported('VideoLevelNotSupported'), + @JsonValue('VideoResolutionNotSupported') + videoresolutionnotsupported('VideoResolutionNotSupported'), + @JsonValue('VideoBitDepthNotSupported') + videobitdepthnotsupported('VideoBitDepthNotSupported'), + @JsonValue('VideoFramerateNotSupported') + videoframeratenotsupported('VideoFramerateNotSupported'), + @JsonValue('RefFramesNotSupported') + refframesnotsupported('RefFramesNotSupported'), + @JsonValue('AnamorphicVideoNotSupported') + anamorphicvideonotsupported('AnamorphicVideoNotSupported'), + @JsonValue('InterlacedVideoNotSupported') + interlacedvideonotsupported('InterlacedVideoNotSupported'), + @JsonValue('AudioChannelsNotSupported') + audiochannelsnotsupported('AudioChannelsNotSupported'), + @JsonValue('AudioProfileNotSupported') + audioprofilenotsupported('AudioProfileNotSupported'), + @JsonValue('AudioSampleRateNotSupported') + audiosampleratenotsupported('AudioSampleRateNotSupported'), + @JsonValue('AudioBitDepthNotSupported') + audiobitdepthnotsupported('AudioBitDepthNotSupported'), + @JsonValue('ContainerBitrateExceedsLimit') + containerbitrateexceedslimit('ContainerBitrateExceedsLimit'), + @JsonValue('VideoBitrateNotSupported') + videobitratenotsupported('VideoBitrateNotSupported'), + @JsonValue('AudioBitrateNotSupported') + audiobitratenotsupported('AudioBitrateNotSupported'), + @JsonValue('UnknownVideoStreamInfo') + unknownvideostreaminfo('UnknownVideoStreamInfo'), + @JsonValue('UnknownAudioStreamInfo') + unknownaudiostreaminfo('UnknownAudioStreamInfo'), + @JsonValue('DirectPlayError') + directplayerror('DirectPlayError'), + @JsonValue('VideoRangeTypeNotSupported') + videorangetypenotsupported('VideoRangeTypeNotSupported'); + + final String? value; + + const TranscodingInfoTranscodeReasons(this.value); +} + +enum TransportStreamTimestamp { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('None') + none('None'), + @JsonValue('Zero') + zero('Zero'), + @JsonValue('Valid') + valid('Valid'); + + final String? value; + + const TransportStreamTimestamp(this.value); +} + +enum TrickplayScanBehavior { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Blocking') + blocking('Blocking'), + @JsonValue('NonBlocking') + nonblocking('NonBlocking'); + + final String? value; + + const TrickplayScanBehavior(this.value); +} + +enum UnratedItem { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Movie') + movie('Movie'), + @JsonValue('Trailer') + trailer('Trailer'), + @JsonValue('Series') + series('Series'), + @JsonValue('Music') + music('Music'), + @JsonValue('Book') + book('Book'), + @JsonValue('LiveTvChannel') + livetvchannel('LiveTvChannel'), + @JsonValue('LiveTvProgram') + livetvprogram('LiveTvProgram'), + @JsonValue('ChannelContent') + channelcontent('ChannelContent'), + @JsonValue('Other') + other('Other'); + + final String? value; + + const UnratedItem(this.value); +} + +enum Video3DFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('HalfSideBySide') + halfsidebyside('HalfSideBySide'), + @JsonValue('FullSideBySide') + fullsidebyside('FullSideBySide'), + @JsonValue('FullTopAndBottom') + fulltopandbottom('FullTopAndBottom'), + @JsonValue('HalfTopAndBottom') + halftopandbottom('HalfTopAndBottom'), + @JsonValue('MVC') + mvc('MVC'); + + final String? value; + + const Video3DFormat(this.value); +} + +enum VideoRange { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Unknown') + unknown('Unknown'), + @JsonValue('SDR') + sdr('SDR'), + @JsonValue('HDR') + hdr('HDR'); + + final String? value; + + const VideoRange(this.value); +} + +enum VideoRangeType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Unknown') + unknown('Unknown'), + @JsonValue('SDR') + sdr('SDR'), + @JsonValue('HDR10') + hdr10('HDR10'), + @JsonValue('HLG') + hlg('HLG'), + @JsonValue('DOVI') + dovi('DOVI'), + @JsonValue('DOVIWithHDR10') + doviwithhdr10('DOVIWithHDR10'), + @JsonValue('DOVIWithHLG') + doviwithhlg('DOVIWithHLG'), + @JsonValue('DOVIWithSDR') + doviwithsdr('DOVIWithSDR'), + @JsonValue('HDR10Plus') + hdr10plus('HDR10Plus'); + + final String? value; + + const VideoRangeType(this.value); +} + +enum VideoType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('VideoFile') + videofile('VideoFile'), + @JsonValue('Iso') + iso('Iso'), + @JsonValue('Dvd') + dvd('Dvd'), + @JsonValue('BluRay') + bluray('BluRay'); + + final String? value; + + const VideoType(this.value); +} + +enum AudioItemIdStreamGetSubtitleMethod { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Encode') + encode('Encode'), + @JsonValue('Embed') + embed('Embed'), + @JsonValue('External') + $external('External'), + @JsonValue('Hls') + hls('Hls'), + @JsonValue('Drop') + drop('Drop'); + + final String? value; + + const AudioItemIdStreamGetSubtitleMethod(this.value); +} + +enum AudioItemIdStreamGetContext { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Streaming') + streaming('Streaming'), + @JsonValue('Static') + $static('Static'); + + final String? value; + + const AudioItemIdStreamGetContext(this.value); +} + +enum AudioItemIdStreamHeadSubtitleMethod { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Encode') + encode('Encode'), + @JsonValue('Embed') + embed('Embed'), + @JsonValue('External') + $external('External'), + @JsonValue('Hls') + hls('Hls'), + @JsonValue('Drop') + drop('Drop'); + + final String? value; + + const AudioItemIdStreamHeadSubtitleMethod(this.value); +} + +enum AudioItemIdStreamHeadContext { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Streaming') + streaming('Streaming'), + @JsonValue('Static') + $static('Static'); + + final String? value; + + const AudioItemIdStreamHeadContext(this.value); +} + +enum AudioItemIdStreamContainerGetSubtitleMethod { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Encode') + encode('Encode'), + @JsonValue('Embed') + embed('Embed'), + @JsonValue('External') + $external('External'), + @JsonValue('Hls') + hls('Hls'), + @JsonValue('Drop') + drop('Drop'); + + final String? value; + + const AudioItemIdStreamContainerGetSubtitleMethod(this.value); +} + +enum AudioItemIdStreamContainerGetContext { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Streaming') + streaming('Streaming'), + @JsonValue('Static') + $static('Static'); + + final String? value; + + const AudioItemIdStreamContainerGetContext(this.value); +} + +enum AudioItemIdStreamContainerHeadSubtitleMethod { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Encode') + encode('Encode'), + @JsonValue('Embed') + embed('Embed'), + @JsonValue('External') + $external('External'), + @JsonValue('Hls') + hls('Hls'), + @JsonValue('Drop') + drop('Drop'); + + final String? value; + + const AudioItemIdStreamContainerHeadSubtitleMethod(this.value); +} + +enum AudioItemIdStreamContainerHeadContext { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Streaming') + streaming('Streaming'), + @JsonValue('Static') + $static('Static'); + + final String? value; + + const AudioItemIdStreamContainerHeadContext(this.value); +} + +enum AudioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Encode') + encode('Encode'), + @JsonValue('Embed') + embed('Embed'), + @JsonValue('External') + $external('External'), + @JsonValue('Hls') + hls('Hls'), + @JsonValue('Drop') + drop('Drop'); + + final String? value; + + const AudioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod( + this.value); +} + +enum AudioItemIdHls1PlaylistIdSegmentIdContainerGetContext { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Streaming') + streaming('Streaming'), + @JsonValue('Static') + $static('Static'); + + final String? value; + + const AudioItemIdHls1PlaylistIdSegmentIdContainerGetContext(this.value); +} + +enum AudioItemIdMainM3u8GetSubtitleMethod { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Encode') + encode('Encode'), + @JsonValue('Embed') + embed('Embed'), + @JsonValue('External') + $external('External'), + @JsonValue('Hls') + hls('Hls'), + @JsonValue('Drop') + drop('Drop'); + + final String? value; + + const AudioItemIdMainM3u8GetSubtitleMethod(this.value); +} + +enum AudioItemIdMainM3u8GetContext { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Streaming') + streaming('Streaming'), + @JsonValue('Static') + $static('Static'); + + final String? value; + + const AudioItemIdMainM3u8GetContext(this.value); +} + +enum AudioItemIdMasterM3u8GetSubtitleMethod { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Encode') + encode('Encode'), + @JsonValue('Embed') + embed('Embed'), + @JsonValue('External') + $external('External'), + @JsonValue('Hls') + hls('Hls'), + @JsonValue('Drop') + drop('Drop'); + + final String? value; + + const AudioItemIdMasterM3u8GetSubtitleMethod(this.value); +} + +enum AudioItemIdMasterM3u8GetContext { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Streaming') + streaming('Streaming'), + @JsonValue('Static') + $static('Static'); + + final String? value; + + const AudioItemIdMasterM3u8GetContext(this.value); +} + +enum AudioItemIdMasterM3u8HeadSubtitleMethod { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Encode') + encode('Encode'), + @JsonValue('Embed') + embed('Embed'), + @JsonValue('External') + $external('External'), + @JsonValue('Hls') + hls('Hls'), + @JsonValue('Drop') + drop('Drop'); + + final String? value; + + const AudioItemIdMasterM3u8HeadSubtitleMethod(this.value); +} + +enum AudioItemIdMasterM3u8HeadContext { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Streaming') + streaming('Streaming'), + @JsonValue('Static') + $static('Static'); + + final String? value; + + const AudioItemIdMasterM3u8HeadContext(this.value); +} + +enum VideosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Encode') + encode('Encode'), + @JsonValue('Embed') + embed('Embed'), + @JsonValue('External') + $external('External'), + @JsonValue('Hls') + hls('Hls'), + @JsonValue('Drop') + drop('Drop'); + + final String? value; + + const VideosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod( + this.value); +} + +enum VideosItemIdHls1PlaylistIdSegmentIdContainerGetContext { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Streaming') + streaming('Streaming'), + @JsonValue('Static') + $static('Static'); + + final String? value; + + const VideosItemIdHls1PlaylistIdSegmentIdContainerGetContext(this.value); +} + +enum VideosItemIdLiveM3u8GetSubtitleMethod { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Encode') + encode('Encode'), + @JsonValue('Embed') + embed('Embed'), + @JsonValue('External') + $external('External'), + @JsonValue('Hls') + hls('Hls'), + @JsonValue('Drop') + drop('Drop'); + + final String? value; + + const VideosItemIdLiveM3u8GetSubtitleMethod(this.value); +} + +enum VideosItemIdLiveM3u8GetContext { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Streaming') + streaming('Streaming'), + @JsonValue('Static') + $static('Static'); + + final String? value; + + const VideosItemIdLiveM3u8GetContext(this.value); +} + +enum VideosItemIdMainM3u8GetSubtitleMethod { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Encode') + encode('Encode'), + @JsonValue('Embed') + embed('Embed'), + @JsonValue('External') + $external('External'), + @JsonValue('Hls') + hls('Hls'), + @JsonValue('Drop') + drop('Drop'); + + final String? value; + + const VideosItemIdMainM3u8GetSubtitleMethod(this.value); +} + +enum VideosItemIdMainM3u8GetContext { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Streaming') + streaming('Streaming'), + @JsonValue('Static') + $static('Static'); + + final String? value; + + const VideosItemIdMainM3u8GetContext(this.value); +} + +enum VideosItemIdMasterM3u8GetSubtitleMethod { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Encode') + encode('Encode'), + @JsonValue('Embed') + embed('Embed'), + @JsonValue('External') + $external('External'), + @JsonValue('Hls') + hls('Hls'), + @JsonValue('Drop') + drop('Drop'); + + final String? value; + + const VideosItemIdMasterM3u8GetSubtitleMethod(this.value); +} + +enum VideosItemIdMasterM3u8GetContext { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Streaming') + streaming('Streaming'), + @JsonValue('Static') + $static('Static'); + + final String? value; + + const VideosItemIdMasterM3u8GetContext(this.value); +} + +enum VideosItemIdMasterM3u8HeadSubtitleMethod { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Encode') + encode('Encode'), + @JsonValue('Embed') + embed('Embed'), + @JsonValue('External') + $external('External'), + @JsonValue('Hls') + hls('Hls'), + @JsonValue('Drop') + drop('Drop'); + + final String? value; + + const VideosItemIdMasterM3u8HeadSubtitleMethod(this.value); +} + +enum VideosItemIdMasterM3u8HeadContext { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Streaming') + streaming('Streaming'), + @JsonValue('Static') + $static('Static'); + + final String? value; + + const VideosItemIdMasterM3u8HeadContext(this.value); +} + +enum ArtistsNameImagesImageTypeImageIndexGetImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const ArtistsNameImagesImageTypeImageIndexGetImageType(this.value); +} + +enum ArtistsNameImagesImageTypeImageIndexGetFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const ArtistsNameImagesImageTypeImageIndexGetFormat(this.value); +} + +enum ArtistsNameImagesImageTypeImageIndexHeadImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const ArtistsNameImagesImageTypeImageIndexHeadImageType(this.value); +} + +enum ArtistsNameImagesImageTypeImageIndexHeadFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const ArtistsNameImagesImageTypeImageIndexHeadFormat(this.value); +} + +enum BrandingSplashscreenGetFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const BrandingSplashscreenGetFormat(this.value); +} + +enum GenresNameImagesImageTypeGetImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const GenresNameImagesImageTypeGetImageType(this.value); +} + +enum GenresNameImagesImageTypeGetFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const GenresNameImagesImageTypeGetFormat(this.value); +} + +enum GenresNameImagesImageTypeHeadImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const GenresNameImagesImageTypeHeadImageType(this.value); +} + +enum GenresNameImagesImageTypeHeadFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const GenresNameImagesImageTypeHeadFormat(this.value); +} + +enum GenresNameImagesImageTypeImageIndexGetImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const GenresNameImagesImageTypeImageIndexGetImageType(this.value); +} + +enum GenresNameImagesImageTypeImageIndexGetFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const GenresNameImagesImageTypeImageIndexGetFormat(this.value); +} + +enum GenresNameImagesImageTypeImageIndexHeadImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const GenresNameImagesImageTypeImageIndexHeadImageType(this.value); +} + +enum GenresNameImagesImageTypeImageIndexHeadFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const GenresNameImagesImageTypeImageIndexHeadFormat(this.value); +} + +enum ItemsItemIdImagesImageTypeDeleteImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const ItemsItemIdImagesImageTypeDeleteImageType(this.value); +} + +enum ItemsItemIdImagesImageTypePostImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const ItemsItemIdImagesImageTypePostImageType(this.value); +} + +enum ItemsItemIdImagesImageTypeGetImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const ItemsItemIdImagesImageTypeGetImageType(this.value); +} + +enum ItemsItemIdImagesImageTypeGetFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const ItemsItemIdImagesImageTypeGetFormat(this.value); +} + +enum ItemsItemIdImagesImageTypeHeadImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const ItemsItemIdImagesImageTypeHeadImageType(this.value); +} + +enum ItemsItemIdImagesImageTypeHeadFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const ItemsItemIdImagesImageTypeHeadFormat(this.value); +} + +enum ItemsItemIdImagesImageTypeImageIndexDeleteImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const ItemsItemIdImagesImageTypeImageIndexDeleteImageType(this.value); +} + +enum ItemsItemIdImagesImageTypeImageIndexPostImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const ItemsItemIdImagesImageTypeImageIndexPostImageType(this.value); +} + +enum ItemsItemIdImagesImageTypeImageIndexGetImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const ItemsItemIdImagesImageTypeImageIndexGetImageType(this.value); +} + +enum ItemsItemIdImagesImageTypeImageIndexGetFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const ItemsItemIdImagesImageTypeImageIndexGetFormat(this.value); +} + +enum ItemsItemIdImagesImageTypeImageIndexHeadImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const ItemsItemIdImagesImageTypeImageIndexHeadImageType(this.value); +} + +enum ItemsItemIdImagesImageTypeImageIndexHeadFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const ItemsItemIdImagesImageTypeImageIndexHeadFormat(this.value); +} + +enum ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType( + this.value); +} + +enum ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat( + this.value); +} + +enum ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType( + this.value); +} + +enum ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat( + this.value); +} + +enum ItemsItemIdImagesImageTypeImageIndexIndexPostImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const ItemsItemIdImagesImageTypeImageIndexIndexPostImageType(this.value); +} + +enum MusicGenresNameImagesImageTypeGetImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const MusicGenresNameImagesImageTypeGetImageType(this.value); +} + +enum MusicGenresNameImagesImageTypeGetFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const MusicGenresNameImagesImageTypeGetFormat(this.value); +} + +enum MusicGenresNameImagesImageTypeHeadImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const MusicGenresNameImagesImageTypeHeadImageType(this.value); +} + +enum MusicGenresNameImagesImageTypeHeadFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const MusicGenresNameImagesImageTypeHeadFormat(this.value); +} + +enum MusicGenresNameImagesImageTypeImageIndexGetImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const MusicGenresNameImagesImageTypeImageIndexGetImageType(this.value); +} + +enum MusicGenresNameImagesImageTypeImageIndexGetFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const MusicGenresNameImagesImageTypeImageIndexGetFormat(this.value); +} + +enum MusicGenresNameImagesImageTypeImageIndexHeadImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const MusicGenresNameImagesImageTypeImageIndexHeadImageType(this.value); +} + +enum MusicGenresNameImagesImageTypeImageIndexHeadFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const MusicGenresNameImagesImageTypeImageIndexHeadFormat(this.value); +} + +enum PersonsNameImagesImageTypeGetImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const PersonsNameImagesImageTypeGetImageType(this.value); +} + +enum PersonsNameImagesImageTypeGetFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const PersonsNameImagesImageTypeGetFormat(this.value); +} + +enum PersonsNameImagesImageTypeHeadImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const PersonsNameImagesImageTypeHeadImageType(this.value); +} + +enum PersonsNameImagesImageTypeHeadFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const PersonsNameImagesImageTypeHeadFormat(this.value); +} + +enum PersonsNameImagesImageTypeImageIndexGetImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const PersonsNameImagesImageTypeImageIndexGetImageType(this.value); +} + +enum PersonsNameImagesImageTypeImageIndexGetFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const PersonsNameImagesImageTypeImageIndexGetFormat(this.value); +} + +enum PersonsNameImagesImageTypeImageIndexHeadImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const PersonsNameImagesImageTypeImageIndexHeadImageType(this.value); +} + +enum PersonsNameImagesImageTypeImageIndexHeadFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const PersonsNameImagesImageTypeImageIndexHeadFormat(this.value); +} + +enum StudiosNameImagesImageTypeGetImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const StudiosNameImagesImageTypeGetImageType(this.value); +} + +enum StudiosNameImagesImageTypeGetFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const StudiosNameImagesImageTypeGetFormat(this.value); +} + +enum StudiosNameImagesImageTypeHeadImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const StudiosNameImagesImageTypeHeadImageType(this.value); +} + +enum StudiosNameImagesImageTypeHeadFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const StudiosNameImagesImageTypeHeadFormat(this.value); +} + +enum StudiosNameImagesImageTypeImageIndexGetImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const StudiosNameImagesImageTypeImageIndexGetImageType(this.value); +} + +enum StudiosNameImagesImageTypeImageIndexGetFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const StudiosNameImagesImageTypeImageIndexGetFormat(this.value); +} + +enum StudiosNameImagesImageTypeImageIndexHeadImageType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const StudiosNameImagesImageTypeImageIndexHeadImageType(this.value); +} + +enum StudiosNameImagesImageTypeImageIndexHeadFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const StudiosNameImagesImageTypeImageIndexHeadFormat(this.value); +} + +enum UserImageGetFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const UserImageGetFormat(this.value); +} + +enum UserImageHeadFormat { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Bmp') + bmp('Bmp'), + @JsonValue('Gif') + gif('Gif'), + @JsonValue('Jpg') + jpg('Jpg'), + @JsonValue('Png') + png('Png'), + @JsonValue('Webp') + webp('Webp'), + @JsonValue('Svg') + svg('Svg'); + + final String? value; + + const UserImageHeadFormat(this.value); +} + +enum ItemsItemIdRefreshPostMetadataRefreshMode { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('None') + none('None'), + @JsonValue('ValidationOnly') + validationonly('ValidationOnly'), + @JsonValue('Default') + $default('Default'), + @JsonValue('FullRefresh') + fullrefresh('FullRefresh'); + + final String? value; + + const ItemsItemIdRefreshPostMetadataRefreshMode(this.value); +} + +enum ItemsItemIdRefreshPostImageRefreshMode { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('None') + none('None'), + @JsonValue('ValidationOnly') + validationonly('ValidationOnly'), + @JsonValue('Default') + $default('Default'), + @JsonValue('FullRefresh') + fullrefresh('FullRefresh'); + + final String? value; + + const ItemsItemIdRefreshPostImageRefreshMode(this.value); +} + +enum LibrariesAvailableOptionsGetLibraryContentType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('unknown') + unknown('unknown'), + @JsonValue('movies') + movies('movies'), + @JsonValue('tvshows') + tvshows('tvshows'), + @JsonValue('music') + music('music'), + @JsonValue('musicvideos') + musicvideos('musicvideos'), + @JsonValue('trailers') + trailers('trailers'), + @JsonValue('homevideos') + homevideos('homevideos'), + @JsonValue('boxsets') + boxsets('boxsets'), + @JsonValue('books') + books('books'), + @JsonValue('photos') + photos('photos'), + @JsonValue('livetv') + livetv('livetv'), + @JsonValue('playlists') + playlists('playlists'), + @JsonValue('folders') + folders('folders'); + + final String? value; + + const LibrariesAvailableOptionsGetLibraryContentType(this.value); +} + +enum LibraryVirtualFoldersPostCollectionType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('movies') + movies('movies'), + @JsonValue('tvshows') + tvshows('tvshows'), + @JsonValue('music') + music('music'), + @JsonValue('musicvideos') + musicvideos('musicvideos'), + @JsonValue('homevideos') + homevideos('homevideos'), + @JsonValue('boxsets') + boxsets('boxsets'), + @JsonValue('books') + books('books'), + @JsonValue('mixed') + mixed('mixed'); + + final String? value; + + const LibraryVirtualFoldersPostCollectionType(this.value); +} + +enum LiveTvChannelsGetType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('TV') + tv('TV'), + @JsonValue('Radio') + radio('Radio'); + + final String? value; + + const LiveTvChannelsGetType(this.value); +} + +enum LiveTvChannelsGetSortOrder { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Ascending') + ascending('Ascending'), + @JsonValue('Descending') + descending('Descending'); + + final String? value; + + const LiveTvChannelsGetSortOrder(this.value); +} + +enum LiveTvRecordingsGetStatus { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('New') + $new('New'), + @JsonValue('InProgress') + inprogress('InProgress'), + @JsonValue('Completed') + completed('Completed'), + @JsonValue('Cancelled') + cancelled('Cancelled'), + @JsonValue('ConflictedOk') + conflictedok('ConflictedOk'), + @JsonValue('ConflictedNotOk') + conflictednotok('ConflictedNotOk'), + @JsonValue('Error') + error('Error'); + + final String? value; + + const LiveTvRecordingsGetStatus(this.value); +} + +enum LiveTvRecordingsSeriesGetStatus { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('New') + $new('New'), + @JsonValue('InProgress') + inprogress('InProgress'), + @JsonValue('Completed') + completed('Completed'), + @JsonValue('Cancelled') + cancelled('Cancelled'), + @JsonValue('ConflictedOk') + conflictedok('ConflictedOk'), + @JsonValue('ConflictedNotOk') + conflictednotok('ConflictedNotOk'), + @JsonValue('Error') + error('Error'); + + final String? value; + + const LiveTvRecordingsSeriesGetStatus(this.value); +} + +enum LiveTvSeriesTimersGetSortOrder { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Ascending') + ascending('Ascending'), + @JsonValue('Descending') + descending('Descending'); + + final String? value; + + const LiveTvSeriesTimersGetSortOrder(this.value); +} + +enum PlaylistsPostMediaType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Unknown') + unknown('Unknown'), + @JsonValue('Video') + video('Video'), + @JsonValue('Audio') + audio('Audio'), + @JsonValue('Photo') + photo('Photo'), + @JsonValue('Book') + book('Book'); + + final String? value; + + const PlaylistsPostMediaType(this.value); +} + +enum PlayingItemsItemIdPostPlayMethod { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Transcode') + transcode('Transcode'), + @JsonValue('DirectStream') + directstream('DirectStream'), + @JsonValue('DirectPlay') + directplay('DirectPlay'); + + final String? value; + + const PlayingItemsItemIdPostPlayMethod(this.value); +} + +enum PlayingItemsItemIdProgressPostPlayMethod { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Transcode') + transcode('Transcode'), + @JsonValue('DirectStream') + directstream('DirectStream'), + @JsonValue('DirectPlay') + directplay('DirectPlay'); + + final String? value; + + const PlayingItemsItemIdProgressPostPlayMethod(this.value); +} + +enum PlayingItemsItemIdProgressPostRepeatMode { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('RepeatNone') + repeatnone('RepeatNone'), + @JsonValue('RepeatAll') + repeatall('RepeatAll'), + @JsonValue('RepeatOne') + repeatone('RepeatOne'); + + final String? value; + + const PlayingItemsItemIdProgressPostRepeatMode(this.value); +} + +enum ItemsItemIdRemoteImagesGetType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const ItemsItemIdRemoteImagesGetType(this.value); +} + +enum ItemsItemIdRemoteImagesDownloadPostType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Primary') + primary('Primary'), + @JsonValue('Art') + art('Art'), + @JsonValue('Backdrop') + backdrop('Backdrop'), + @JsonValue('Banner') + banner('Banner'), + @JsonValue('Logo') + logo('Logo'), + @JsonValue('Thumb') + thumb('Thumb'), + @JsonValue('Disc') + disc('Disc'), + @JsonValue('Box') + box('Box'), + @JsonValue('Screenshot') + screenshot('Screenshot'), + @JsonValue('Menu') + menu('Menu'), + @JsonValue('Chapter') + chapter('Chapter'), + @JsonValue('BoxRear') + boxrear('BoxRear'), + @JsonValue('Profile') + profile('Profile'); + + final String? value; + + const ItemsItemIdRemoteImagesDownloadPostType(this.value); +} + +enum SessionsSessionIdCommandCommandPostCommand { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('MoveUp') + moveup('MoveUp'), + @JsonValue('MoveDown') + movedown('MoveDown'), + @JsonValue('MoveLeft') + moveleft('MoveLeft'), + @JsonValue('MoveRight') + moveright('MoveRight'), + @JsonValue('PageUp') + pageup('PageUp'), + @JsonValue('PageDown') + pagedown('PageDown'), + @JsonValue('PreviousLetter') + previousletter('PreviousLetter'), + @JsonValue('NextLetter') + nextletter('NextLetter'), + @JsonValue('ToggleOsd') + toggleosd('ToggleOsd'), + @JsonValue('ToggleContextMenu') + togglecontextmenu('ToggleContextMenu'), + @JsonValue('Select') + select('Select'), + @JsonValue('Back') + back('Back'), + @JsonValue('TakeScreenshot') + takescreenshot('TakeScreenshot'), + @JsonValue('SendKey') + sendkey('SendKey'), + @JsonValue('SendString') + sendstring('SendString'), + @JsonValue('GoHome') + gohome('GoHome'), + @JsonValue('GoToSettings') + gotosettings('GoToSettings'), + @JsonValue('VolumeUp') + volumeup('VolumeUp'), + @JsonValue('VolumeDown') + volumedown('VolumeDown'), + @JsonValue('Mute') + mute('Mute'), + @JsonValue('Unmute') + unmute('Unmute'), + @JsonValue('ToggleMute') + togglemute('ToggleMute'), + @JsonValue('SetVolume') + setvolume('SetVolume'), + @JsonValue('SetAudioStreamIndex') + setaudiostreamindex('SetAudioStreamIndex'), + @JsonValue('SetSubtitleStreamIndex') + setsubtitlestreamindex('SetSubtitleStreamIndex'), + @JsonValue('ToggleFullscreen') + togglefullscreen('ToggleFullscreen'), + @JsonValue('DisplayContent') + displaycontent('DisplayContent'), + @JsonValue('GoToSearch') + gotosearch('GoToSearch'), + @JsonValue('DisplayMessage') + displaymessage('DisplayMessage'), + @JsonValue('SetRepeatMode') + setrepeatmode('SetRepeatMode'), + @JsonValue('ChannelUp') + channelup('ChannelUp'), + @JsonValue('ChannelDown') + channeldown('ChannelDown'), + @JsonValue('Guide') + guide('Guide'), + @JsonValue('ToggleStats') + togglestats('ToggleStats'), + @JsonValue('PlayMediaSource') + playmediasource('PlayMediaSource'), + @JsonValue('PlayTrailers') + playtrailers('PlayTrailers'), + @JsonValue('SetShuffleQueue') + setshufflequeue('SetShuffleQueue'), + @JsonValue('PlayState') + playstate('PlayState'), + @JsonValue('PlayNext') + playnext('PlayNext'), + @JsonValue('ToggleOsdMenu') + toggleosdmenu('ToggleOsdMenu'), + @JsonValue('Play') + play('Play'), + @JsonValue('SetMaxStreamingBitrate') + setmaxstreamingbitrate('SetMaxStreamingBitrate'), + @JsonValue('SetPlaybackOrder') + setplaybackorder('SetPlaybackOrder'); + + final String? value; + + const SessionsSessionIdCommandCommandPostCommand(this.value); +} + +enum SessionsSessionIdPlayingPostPlayCommand { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('PlayNow') + playnow('PlayNow'), + @JsonValue('PlayNext') + playnext('PlayNext'), + @JsonValue('PlayLast') + playlast('PlayLast'), + @JsonValue('PlayInstantMix') + playinstantmix('PlayInstantMix'), + @JsonValue('PlayShuffle') + playshuffle('PlayShuffle'); + + final String? value; + + const SessionsSessionIdPlayingPostPlayCommand(this.value); +} + +enum SessionsSessionIdPlayingCommandPostCommand { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Stop') + stop('Stop'), + @JsonValue('Pause') + pause('Pause'), + @JsonValue('Unpause') + unpause('Unpause'), + @JsonValue('NextTrack') + nexttrack('NextTrack'), + @JsonValue('PreviousTrack') + previoustrack('PreviousTrack'), + @JsonValue('Seek') + seek('Seek'), + @JsonValue('Rewind') + rewind('Rewind'), + @JsonValue('FastForward') + fastforward('FastForward'), + @JsonValue('PlayPause') + playpause('PlayPause'); + + final String? value; + + const SessionsSessionIdPlayingCommandPostCommand(this.value); +} + +enum SessionsSessionIdSystemCommandPostCommand { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('MoveUp') + moveup('MoveUp'), + @JsonValue('MoveDown') + movedown('MoveDown'), + @JsonValue('MoveLeft') + moveleft('MoveLeft'), + @JsonValue('MoveRight') + moveright('MoveRight'), + @JsonValue('PageUp') + pageup('PageUp'), + @JsonValue('PageDown') + pagedown('PageDown'), + @JsonValue('PreviousLetter') + previousletter('PreviousLetter'), + @JsonValue('NextLetter') + nextletter('NextLetter'), + @JsonValue('ToggleOsd') + toggleosd('ToggleOsd'), + @JsonValue('ToggleContextMenu') + togglecontextmenu('ToggleContextMenu'), + @JsonValue('Select') + select('Select'), + @JsonValue('Back') + back('Back'), + @JsonValue('TakeScreenshot') + takescreenshot('TakeScreenshot'), + @JsonValue('SendKey') + sendkey('SendKey'), + @JsonValue('SendString') + sendstring('SendString'), + @JsonValue('GoHome') + gohome('GoHome'), + @JsonValue('GoToSettings') + gotosettings('GoToSettings'), + @JsonValue('VolumeUp') + volumeup('VolumeUp'), + @JsonValue('VolumeDown') + volumedown('VolumeDown'), + @JsonValue('Mute') + mute('Mute'), + @JsonValue('Unmute') + unmute('Unmute'), + @JsonValue('ToggleMute') + togglemute('ToggleMute'), + @JsonValue('SetVolume') + setvolume('SetVolume'), + @JsonValue('SetAudioStreamIndex') + setaudiostreamindex('SetAudioStreamIndex'), + @JsonValue('SetSubtitleStreamIndex') + setsubtitlestreamindex('SetSubtitleStreamIndex'), + @JsonValue('ToggleFullscreen') + togglefullscreen('ToggleFullscreen'), + @JsonValue('DisplayContent') + displaycontent('DisplayContent'), + @JsonValue('GoToSearch') + gotosearch('GoToSearch'), + @JsonValue('DisplayMessage') + displaymessage('DisplayMessage'), + @JsonValue('SetRepeatMode') + setrepeatmode('SetRepeatMode'), + @JsonValue('ChannelUp') + channelup('ChannelUp'), + @JsonValue('ChannelDown') + channeldown('ChannelDown'), + @JsonValue('Guide') + guide('Guide'), + @JsonValue('ToggleStats') + togglestats('ToggleStats'), + @JsonValue('PlayMediaSource') + playmediasource('PlayMediaSource'), + @JsonValue('PlayTrailers') + playtrailers('PlayTrailers'), + @JsonValue('SetShuffleQueue') + setshufflequeue('SetShuffleQueue'), + @JsonValue('PlayState') + playstate('PlayState'), + @JsonValue('PlayNext') + playnext('PlayNext'), + @JsonValue('ToggleOsdMenu') + toggleosdmenu('ToggleOsdMenu'), + @JsonValue('Play') + play('Play'), + @JsonValue('SetMaxStreamingBitrate') + setmaxstreamingbitrate('SetMaxStreamingBitrate'), + @JsonValue('SetPlaybackOrder') + setplaybackorder('SetPlaybackOrder'); + + final String? value; + + const SessionsSessionIdSystemCommandPostCommand(this.value); +} + +enum SessionsSessionIdViewingPostItemType { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('AggregateFolder') + aggregatefolder('AggregateFolder'), + @JsonValue('Audio') + audio('Audio'), + @JsonValue('AudioBook') + audiobook('AudioBook'), + @JsonValue('BasePluginFolder') + basepluginfolder('BasePluginFolder'), + @JsonValue('Book') + book('Book'), + @JsonValue('BoxSet') + boxset('BoxSet'), + @JsonValue('Channel') + channel('Channel'), + @JsonValue('ChannelFolderItem') + channelfolderitem('ChannelFolderItem'), + @JsonValue('CollectionFolder') + collectionfolder('CollectionFolder'), + @JsonValue('Episode') + episode('Episode'), + @JsonValue('Folder') + folder('Folder'), + @JsonValue('Genre') + genre('Genre'), + @JsonValue('ManualPlaylistsFolder') + manualplaylistsfolder('ManualPlaylistsFolder'), + @JsonValue('Movie') + movie('Movie'), + @JsonValue('LiveTvChannel') + livetvchannel('LiveTvChannel'), + @JsonValue('LiveTvProgram') + livetvprogram('LiveTvProgram'), + @JsonValue('MusicAlbum') + musicalbum('MusicAlbum'), + @JsonValue('MusicArtist') + musicartist('MusicArtist'), + @JsonValue('MusicGenre') + musicgenre('MusicGenre'), + @JsonValue('MusicVideo') + musicvideo('MusicVideo'), + @JsonValue('Person') + person('Person'), + @JsonValue('Photo') + photo('Photo'), + @JsonValue('PhotoAlbum') + photoalbum('PhotoAlbum'), + @JsonValue('Playlist') + playlist('Playlist'), + @JsonValue('PlaylistsFolder') + playlistsfolder('PlaylistsFolder'), + @JsonValue('Program') + program('Program'), + @JsonValue('Recording') + recording('Recording'), + @JsonValue('Season') + season('Season'), + @JsonValue('Series') + series('Series'), + @JsonValue('Studio') + studio('Studio'), + @JsonValue('Trailer') + trailer('Trailer'), + @JsonValue('TvChannel') + tvchannel('TvChannel'), + @JsonValue('TvProgram') + tvprogram('TvProgram'), + @JsonValue('UserRootFolder') + userrootfolder('UserRootFolder'), + @JsonValue('UserView') + userview('UserView'), + @JsonValue('Video') + video('Video'), + @JsonValue('Year') + year('Year'); + + final String? value; + + const SessionsSessionIdViewingPostItemType(this.value); +} + +enum EpisodeIdIntroTimestampsGetMode { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Introduction') + introduction('Introduction'), + @JsonValue('Credits') + credits('Credits'); + + final String? value; + + const EpisodeIdIntroTimestampsGetMode(this.value); +} + +enum EpisodeIdIntroTimestampsV1GetMode { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Introduction') + introduction('Introduction'), + @JsonValue('Credits') + credits('Credits'); + + final String? value; + + const EpisodeIdIntroTimestampsV1GetMode(this.value); +} + +enum IntrosAllGetMode { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Introduction') + introduction('Introduction'), + @JsonValue('Credits') + credits('Credits'); + + final String? value; + + const IntrosAllGetMode(this.value); +} + +enum IntrosEraseTimestampsPostMode { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Introduction') + introduction('Introduction'), + @JsonValue('Credits') + credits('Credits'); + + final String? value; + + const IntrosEraseTimestampsPostMode(this.value); +} + +enum ShowsSeriesIdEpisodesGetSortBy { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Default') + $default('Default'), + @JsonValue('AiredEpisodeOrder') + airedepisodeorder('AiredEpisodeOrder'), + @JsonValue('Album') + album('Album'), + @JsonValue('AlbumArtist') + albumartist('AlbumArtist'), + @JsonValue('Artist') + artist('Artist'), + @JsonValue('DateCreated') + datecreated('DateCreated'), + @JsonValue('OfficialRating') + officialrating('OfficialRating'), + @JsonValue('DatePlayed') + dateplayed('DatePlayed'), + @JsonValue('PremiereDate') + premieredate('PremiereDate'), + @JsonValue('StartDate') + startdate('StartDate'), + @JsonValue('SortName') + sortname('SortName'), + @JsonValue('Name') + name('Name'), + @JsonValue('Random') + random('Random'), + @JsonValue('Runtime') + runtime('Runtime'), + @JsonValue('CommunityRating') + communityrating('CommunityRating'), + @JsonValue('ProductionYear') + productionyear('ProductionYear'), + @JsonValue('PlayCount') + playcount('PlayCount'), + @JsonValue('CriticRating') + criticrating('CriticRating'), + @JsonValue('IsFolder') + isfolder('IsFolder'), + @JsonValue('IsUnplayed') + isunplayed('IsUnplayed'), + @JsonValue('IsPlayed') + isplayed('IsPlayed'), + @JsonValue('SeriesSortName') + seriessortname('SeriesSortName'), + @JsonValue('VideoBitRate') + videobitrate('VideoBitRate'), + @JsonValue('AirTime') + airtime('AirTime'), + @JsonValue('Studio') + studio('Studio'), + @JsonValue('IsFavoriteOrLiked') + isfavoriteorliked('IsFavoriteOrLiked'), + @JsonValue('DateLastContentAdded') + datelastcontentadded('DateLastContentAdded'), + @JsonValue('SeriesDatePlayed') + seriesdateplayed('SeriesDatePlayed'), + @JsonValue('ParentIndexNumber') + parentindexnumber('ParentIndexNumber'), + @JsonValue('IndexNumber') + indexnumber('IndexNumber'), + @JsonValue('SimilarityScore') + similarityscore('SimilarityScore'), + @JsonValue('SearchScore') + searchscore('SearchScore'); + + final String? value; + + const ShowsSeriesIdEpisodesGetSortBy(this.value); +} + +enum AudioItemIdUniversalGetTranscodingProtocol { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('http') + http('http'), + @JsonValue('hls') + hls('hls'); + + final String? value; + + const AudioItemIdUniversalGetTranscodingProtocol(this.value); +} + +enum AudioItemIdUniversalHeadTranscodingProtocol { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('http') + http('http'), + @JsonValue('hls') + hls('hls'); + + final String? value; + + const AudioItemIdUniversalHeadTranscodingProtocol(this.value); +} + +enum VideosItemIdStreamGetSubtitleMethod { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Encode') + encode('Encode'), + @JsonValue('Embed') + embed('Embed'), + @JsonValue('External') + $external('External'), + @JsonValue('Hls') + hls('Hls'), + @JsonValue('Drop') + drop('Drop'); + + final String? value; + + const VideosItemIdStreamGetSubtitleMethod(this.value); +} + +enum VideosItemIdStreamGetContext { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Streaming') + streaming('Streaming'), + @JsonValue('Static') + $static('Static'); + + final String? value; + + const VideosItemIdStreamGetContext(this.value); +} + +enum VideosItemIdStreamHeadSubtitleMethod { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Encode') + encode('Encode'), + @JsonValue('Embed') + embed('Embed'), + @JsonValue('External') + $external('External'), + @JsonValue('Hls') + hls('Hls'), + @JsonValue('Drop') + drop('Drop'); + + final String? value; + + const VideosItemIdStreamHeadSubtitleMethod(this.value); +} + +enum VideosItemIdStreamHeadContext { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Streaming') + streaming('Streaming'), + @JsonValue('Static') + $static('Static'); + + final String? value; + + const VideosItemIdStreamHeadContext(this.value); +} + +enum VideosItemIdStreamContainerGetSubtitleMethod { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Encode') + encode('Encode'), + @JsonValue('Embed') + embed('Embed'), + @JsonValue('External') + $external('External'), + @JsonValue('Hls') + hls('Hls'), + @JsonValue('Drop') + drop('Drop'); + + final String? value; + + const VideosItemIdStreamContainerGetSubtitleMethod(this.value); +} + +enum VideosItemIdStreamContainerGetContext { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Streaming') + streaming('Streaming'), + @JsonValue('Static') + $static('Static'); + + final String? value; + + const VideosItemIdStreamContainerGetContext(this.value); +} + +enum VideosItemIdStreamContainerHeadSubtitleMethod { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Encode') + encode('Encode'), + @JsonValue('Embed') + embed('Embed'), + @JsonValue('External') + $external('External'), + @JsonValue('Hls') + hls('Hls'), + @JsonValue('Drop') + drop('Drop'); + + final String? value; + + const VideosItemIdStreamContainerHeadSubtitleMethod(this.value); +} + +enum VideosItemIdStreamContainerHeadContext { + @JsonValue(null) + swaggerGeneratedUnknown(null), + + @JsonValue('Streaming') + streaming('Streaming'), + @JsonValue('Static') + $static('Static'); + + final String? value; + + const VideosItemIdStreamContainerHeadContext(this.value); +} diff --git a/lib/jellyfin/jellyfin_open_api.swagger.chopper.dart b/lib/jellyfin/jellyfin_open_api.swagger.chopper.dart new file mode 100644 index 0000000..46037a2 --- /dev/null +++ b/lib/jellyfin/jellyfin_open_api.swagger.chopper.dart @@ -0,0 +1,10335 @@ +//Generated jellyfin api code + +part of 'jellyfin_open_api.swagger.dart'; + +// ************************************************************************** +// ChopperGenerator +// ************************************************************************** + +// coverage:ignore-file +// ignore_for_file: type=lint +final class _$JellyfinOpenApi extends JellyfinOpenApi { + _$JellyfinOpenApi([ChopperClient? client]) { + if (client == null) return; + this.client = client; + } + + @override + final Type definitionType = JellyfinOpenApi; + + @override + Future> _systemActivityLogEntriesGet({ + int? startIndex, + int? limit, + DateTime? minDate, + bool? hasUserId, + }) { + final Uri $url = Uri.parse('/System/ActivityLog/Entries'); + final Map $params = { + 'startIndex': startIndex, + 'limit': limit, + 'minDate': minDate, + 'hasUserId': hasUserId, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _authKeysGet() { + final Uri $url = Uri.parse('/Auth/Keys'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _authKeysPost({required String? app}) { + final Uri $url = Uri.parse('/Auth/Keys'); + final Map $params = {'app': app}; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _authKeysKeyDelete({required String? key}) { + final Uri $url = Uri.parse('/Auth/Keys/${key}'); + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _artistsGet({ + num? minCommunityRating, + int? startIndex, + int? limit, + String? searchTerm, + String? parentId, + List? fields, + List? excludeItemTypes, + List? includeItemTypes, + List? filters, + bool? isFavorite, + List? mediaTypes, + List? genres, + List? genreIds, + List? officialRatings, + List? tags, + List? years, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + String? person, + List? personIds, + List? personTypes, + List? studios, + List? studioIds, + String? userId, + String? nameStartsWithOrGreater, + String? nameStartsWith, + String? nameLessThan, + List? sortBy, + List? sortOrder, + bool? enableImages, + bool? enableTotalRecordCount, + }) { + final Uri $url = Uri.parse('/Artists'); + final Map $params = { + 'minCommunityRating': minCommunityRating, + 'startIndex': startIndex, + 'limit': limit, + 'searchTerm': searchTerm, + 'parentId': parentId, + 'fields': fields, + 'excludeItemTypes': excludeItemTypes, + 'includeItemTypes': includeItemTypes, + 'filters': filters, + 'isFavorite': isFavorite, + 'mediaTypes': mediaTypes, + 'genres': genres, + 'genreIds': genreIds, + 'officialRatings': officialRatings, + 'tags': tags, + 'years': years, + 'enableUserData': enableUserData, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + 'person': person, + 'personIds': personIds, + 'personTypes': personTypes, + 'studios': studios, + 'studioIds': studioIds, + 'userId': userId, + 'nameStartsWithOrGreater': nameStartsWithOrGreater, + 'nameStartsWith': nameStartsWith, + 'nameLessThan': nameLessThan, + 'sortBy': sortBy, + 'sortOrder': sortOrder, + 'enableImages': enableImages, + 'enableTotalRecordCount': enableTotalRecordCount, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _artistsNameGet({ + required String? name, + String? userId, + }) { + final Uri $url = Uri.parse('/Artists/${name}'); + final Map $params = {'userId': userId}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _artistsAlbumArtistsGet({ + num? minCommunityRating, + int? startIndex, + int? limit, + String? searchTerm, + String? parentId, + List? fields, + List? excludeItemTypes, + List? includeItemTypes, + List? filters, + bool? isFavorite, + List? mediaTypes, + List? genres, + List? genreIds, + List? officialRatings, + List? tags, + List? years, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + String? person, + List? personIds, + List? personTypes, + List? studios, + List? studioIds, + String? userId, + String? nameStartsWithOrGreater, + String? nameStartsWith, + String? nameLessThan, + List? sortBy, + List? sortOrder, + bool? enableImages, + bool? enableTotalRecordCount, + }) { + final Uri $url = Uri.parse('/Artists/AlbumArtists'); + final Map $params = { + 'minCommunityRating': minCommunityRating, + 'startIndex': startIndex, + 'limit': limit, + 'searchTerm': searchTerm, + 'parentId': parentId, + 'fields': fields, + 'excludeItemTypes': excludeItemTypes, + 'includeItemTypes': includeItemTypes, + 'filters': filters, + 'isFavorite': isFavorite, + 'mediaTypes': mediaTypes, + 'genres': genres, + 'genreIds': genreIds, + 'officialRatings': officialRatings, + 'tags': tags, + 'years': years, + 'enableUserData': enableUserData, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + 'person': person, + 'personIds': personIds, + 'personTypes': personTypes, + 'studios': studios, + 'studioIds': studioIds, + 'userId': userId, + 'nameStartsWithOrGreater': nameStartsWithOrGreater, + 'nameStartsWith': nameStartsWith, + 'nameLessThan': nameLessThan, + 'sortBy': sortBy, + 'sortOrder': sortOrder, + 'enableImages': enableImages, + 'enableTotalRecordCount': enableTotalRecordCount, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _audioItemIdStreamGet({ + required String? itemId, + String? container, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? videoBitRate, + int? subtitleStreamIndex, + String? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + String? context, + Object? streamOptions, + }) { + final Uri $url = Uri.parse('/Audio/${itemId}/stream'); + final Map $params = { + 'container': container, + 'static': $static, + 'params': params, + 'tag': tag, + 'deviceProfileId': deviceProfileId, + 'playSessionId': playSessionId, + 'segmentContainer': segmentContainer, + 'segmentLength': segmentLength, + 'minSegments': minSegments, + 'mediaSourceId': mediaSourceId, + 'deviceId': deviceId, + 'audioCodec': audioCodec, + 'enableAutoStreamCopy': enableAutoStreamCopy, + 'allowVideoStreamCopy': allowVideoStreamCopy, + 'allowAudioStreamCopy': allowAudioStreamCopy, + 'breakOnNonKeyFrames': breakOnNonKeyFrames, + 'audioSampleRate': audioSampleRate, + 'maxAudioBitDepth': maxAudioBitDepth, + 'audioBitRate': audioBitRate, + 'audioChannels': audioChannels, + 'maxAudioChannels': maxAudioChannels, + 'profile': profile, + 'level': level, + 'framerate': framerate, + 'maxFramerate': maxFramerate, + 'copyTimestamps': copyTimestamps, + 'startTimeTicks': startTimeTicks, + 'width': width, + 'height': height, + 'videoBitRate': videoBitRate, + 'subtitleStreamIndex': subtitleStreamIndex, + 'subtitleMethod': subtitleMethod, + 'maxRefFrames': maxRefFrames, + 'maxVideoBitDepth': maxVideoBitDepth, + 'requireAvc': requireAvc, + 'deInterlace': deInterlace, + 'requireNonAnamorphic': requireNonAnamorphic, + 'transcodingMaxAudioChannels': transcodingMaxAudioChannels, + 'cpuCoreLimit': cpuCoreLimit, + 'liveStreamId': liveStreamId, + 'enableMpegtsM2TsMode': enableMpegtsM2TsMode, + 'videoCodec': videoCodec, + 'subtitleCodec': subtitleCodec, + 'transcodeReasons': transcodeReasons, + 'audioStreamIndex': audioStreamIndex, + 'videoStreamIndex': videoStreamIndex, + 'context': context, + 'streamOptions': streamOptions, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _audioItemIdStreamHead({ + required String? itemId, + String? container, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? videoBitRate, + int? subtitleStreamIndex, + String? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + String? context, + Object? streamOptions, + }) { + final Uri $url = Uri.parse('/Audio/${itemId}/stream'); + final Map $params = { + 'container': container, + 'static': $static, + 'params': params, + 'tag': tag, + 'deviceProfileId': deviceProfileId, + 'playSessionId': playSessionId, + 'segmentContainer': segmentContainer, + 'segmentLength': segmentLength, + 'minSegments': minSegments, + 'mediaSourceId': mediaSourceId, + 'deviceId': deviceId, + 'audioCodec': audioCodec, + 'enableAutoStreamCopy': enableAutoStreamCopy, + 'allowVideoStreamCopy': allowVideoStreamCopy, + 'allowAudioStreamCopy': allowAudioStreamCopy, + 'breakOnNonKeyFrames': breakOnNonKeyFrames, + 'audioSampleRate': audioSampleRate, + 'maxAudioBitDepth': maxAudioBitDepth, + 'audioBitRate': audioBitRate, + 'audioChannels': audioChannels, + 'maxAudioChannels': maxAudioChannels, + 'profile': profile, + 'level': level, + 'framerate': framerate, + 'maxFramerate': maxFramerate, + 'copyTimestamps': copyTimestamps, + 'startTimeTicks': startTimeTicks, + 'width': width, + 'height': height, + 'videoBitRate': videoBitRate, + 'subtitleStreamIndex': subtitleStreamIndex, + 'subtitleMethod': subtitleMethod, + 'maxRefFrames': maxRefFrames, + 'maxVideoBitDepth': maxVideoBitDepth, + 'requireAvc': requireAvc, + 'deInterlace': deInterlace, + 'requireNonAnamorphic': requireNonAnamorphic, + 'transcodingMaxAudioChannels': transcodingMaxAudioChannels, + 'cpuCoreLimit': cpuCoreLimit, + 'liveStreamId': liveStreamId, + 'enableMpegtsM2TsMode': enableMpegtsM2TsMode, + 'videoCodec': videoCodec, + 'subtitleCodec': subtitleCodec, + 'transcodeReasons': transcodeReasons, + 'audioStreamIndex': audioStreamIndex, + 'videoStreamIndex': videoStreamIndex, + 'context': context, + 'streamOptions': streamOptions, + }; + final Request $request = Request( + 'HEAD', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _audioItemIdStreamContainerGet({ + required String? itemId, + required String? container, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? videoBitRate, + int? subtitleStreamIndex, + String? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + String? context, + Object? streamOptions, + }) { + final Uri $url = Uri.parse('/Audio/${itemId}/stream.${container}'); + final Map $params = { + 'static': $static, + 'params': params, + 'tag': tag, + 'deviceProfileId': deviceProfileId, + 'playSessionId': playSessionId, + 'segmentContainer': segmentContainer, + 'segmentLength': segmentLength, + 'minSegments': minSegments, + 'mediaSourceId': mediaSourceId, + 'deviceId': deviceId, + 'audioCodec': audioCodec, + 'enableAutoStreamCopy': enableAutoStreamCopy, + 'allowVideoStreamCopy': allowVideoStreamCopy, + 'allowAudioStreamCopy': allowAudioStreamCopy, + 'breakOnNonKeyFrames': breakOnNonKeyFrames, + 'audioSampleRate': audioSampleRate, + 'maxAudioBitDepth': maxAudioBitDepth, + 'audioBitRate': audioBitRate, + 'audioChannels': audioChannels, + 'maxAudioChannels': maxAudioChannels, + 'profile': profile, + 'level': level, + 'framerate': framerate, + 'maxFramerate': maxFramerate, + 'copyTimestamps': copyTimestamps, + 'startTimeTicks': startTimeTicks, + 'width': width, + 'height': height, + 'videoBitRate': videoBitRate, + 'subtitleStreamIndex': subtitleStreamIndex, + 'subtitleMethod': subtitleMethod, + 'maxRefFrames': maxRefFrames, + 'maxVideoBitDepth': maxVideoBitDepth, + 'requireAvc': requireAvc, + 'deInterlace': deInterlace, + 'requireNonAnamorphic': requireNonAnamorphic, + 'transcodingMaxAudioChannels': transcodingMaxAudioChannels, + 'cpuCoreLimit': cpuCoreLimit, + 'liveStreamId': liveStreamId, + 'enableMpegtsM2TsMode': enableMpegtsM2TsMode, + 'videoCodec': videoCodec, + 'subtitleCodec': subtitleCodec, + 'transcodeReasons': transcodeReasons, + 'audioStreamIndex': audioStreamIndex, + 'videoStreamIndex': videoStreamIndex, + 'context': context, + 'streamOptions': streamOptions, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _audioItemIdStreamContainerHead({ + required String? itemId, + required String? container, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? videoBitRate, + int? subtitleStreamIndex, + String? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + String? context, + Object? streamOptions, + }) { + final Uri $url = Uri.parse('/Audio/${itemId}/stream.${container}'); + final Map $params = { + 'static': $static, + 'params': params, + 'tag': tag, + 'deviceProfileId': deviceProfileId, + 'playSessionId': playSessionId, + 'segmentContainer': segmentContainer, + 'segmentLength': segmentLength, + 'minSegments': minSegments, + 'mediaSourceId': mediaSourceId, + 'deviceId': deviceId, + 'audioCodec': audioCodec, + 'enableAutoStreamCopy': enableAutoStreamCopy, + 'allowVideoStreamCopy': allowVideoStreamCopy, + 'allowAudioStreamCopy': allowAudioStreamCopy, + 'breakOnNonKeyFrames': breakOnNonKeyFrames, + 'audioSampleRate': audioSampleRate, + 'maxAudioBitDepth': maxAudioBitDepth, + 'audioBitRate': audioBitRate, + 'audioChannels': audioChannels, + 'maxAudioChannels': maxAudioChannels, + 'profile': profile, + 'level': level, + 'framerate': framerate, + 'maxFramerate': maxFramerate, + 'copyTimestamps': copyTimestamps, + 'startTimeTicks': startTimeTicks, + 'width': width, + 'height': height, + 'videoBitRate': videoBitRate, + 'subtitleStreamIndex': subtitleStreamIndex, + 'subtitleMethod': subtitleMethod, + 'maxRefFrames': maxRefFrames, + 'maxVideoBitDepth': maxVideoBitDepth, + 'requireAvc': requireAvc, + 'deInterlace': deInterlace, + 'requireNonAnamorphic': requireNonAnamorphic, + 'transcodingMaxAudioChannels': transcodingMaxAudioChannels, + 'cpuCoreLimit': cpuCoreLimit, + 'liveStreamId': liveStreamId, + 'enableMpegtsM2TsMode': enableMpegtsM2TsMode, + 'videoCodec': videoCodec, + 'subtitleCodec': subtitleCodec, + 'transcodeReasons': transcodeReasons, + 'audioStreamIndex': audioStreamIndex, + 'videoStreamIndex': videoStreamIndex, + 'context': context, + 'streamOptions': streamOptions, + }; + final Request $request = Request( + 'HEAD', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _brandingConfigurationGet() { + final Uri $url = Uri.parse('/Branding/Configuration'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _brandingCssGet() { + final Uri $url = Uri.parse('/Branding/Css'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _brandingCssCssGet() { + final Uri $url = Uri.parse('/Branding/Css.css'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _channelsGet({ + String? userId, + int? startIndex, + int? limit, + bool? supportsLatestItems, + bool? supportsMediaDeletion, + bool? isFavorite, + }) { + final Uri $url = Uri.parse('/Channels'); + final Map $params = { + 'userId': userId, + 'startIndex': startIndex, + 'limit': limit, + 'supportsLatestItems': supportsLatestItems, + 'supportsMediaDeletion': supportsMediaDeletion, + 'isFavorite': isFavorite, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _channelsChannelIdFeaturesGet( + {required String? channelId}) { + final Uri $url = Uri.parse('/Channels/${channelId}/Features'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _channelsChannelIdItemsGet({ + required String? channelId, + String? folderId, + String? userId, + int? startIndex, + int? limit, + List? sortOrder, + List? filters, + List? sortBy, + List? fields, + }) { + final Uri $url = Uri.parse('/Channels/${channelId}/Items'); + final Map $params = { + 'folderId': folderId, + 'userId': userId, + 'startIndex': startIndex, + 'limit': limit, + 'sortOrder': sortOrder, + 'filters': filters, + 'sortBy': sortBy, + 'fields': fields, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future>> _channelsFeaturesGet() { + final Uri $url = Uri.parse('/Channels/Features'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send, ChannelFeatures>($request); + } + + @override + Future> _channelsItemsLatestGet({ + String? userId, + int? startIndex, + int? limit, + List? filters, + List? fields, + List? channelIds, + }) { + final Uri $url = Uri.parse('/Channels/Items/Latest'); + final Map $params = { + 'userId': userId, + 'startIndex': startIndex, + 'limit': limit, + 'filters': filters, + 'fields': fields, + 'channelIds': channelIds, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _clientLogDocumentPost( + {required Object? body}) { + final Uri $url = Uri.parse('/ClientLog/Document'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _collectionsPost({ + String? name, + List? ids, + String? parentId, + bool? isLocked, + }) { + final Uri $url = Uri.parse('/Collections'); + final Map $params = { + 'name': name, + 'ids': ids, + 'parentId': parentId, + 'isLocked': isLocked, + }; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _collectionsCollectionIdItemsPost({ + required String? collectionId, + required List? ids, + }) { + final Uri $url = Uri.parse('/Collections/${collectionId}/Items'); + final Map $params = {'ids': ids}; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _collectionsCollectionIdItemsDelete({ + required String? collectionId, + required List? ids, + }) { + final Uri $url = Uri.parse('/Collections/${collectionId}/Items'); + final Map $params = {'ids': ids}; + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _systemConfigurationGet() { + final Uri $url = Uri.parse('/System/Configuration'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _systemConfigurationPost( + {required ServerConfiguration? body}) { + final Uri $url = Uri.parse('/System/Configuration'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _systemConfigurationKeyGet({required String? key}) { + final Uri $url = Uri.parse('/System/Configuration/${key}'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _systemConfigurationKeyPost({ + required String? key, + required Object? body, + }) { + final Uri $url = Uri.parse('/System/Configuration/${key}'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> + _systemConfigurationMetadataOptionsDefaultGet() { + final Uri $url = Uri.parse('/System/Configuration/MetadataOptions/Default'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _webConfigurationPageGet({String? name}) { + final Uri $url = Uri.parse('/web/ConfigurationPage'); + final Map $params = {'name': name}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future>> _webConfigurationPagesGet( + {bool? enableInMainMenu}) { + final Uri $url = Uri.parse('/web/ConfigurationPages'); + final Map $params = { + 'enableInMainMenu': enableInMainMenu + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send, ConfigurationPageInfo>($request); + } + + @override + Future> _devicesGet({String? userId}) { + final Uri $url = Uri.parse('/Devices'); + final Map $params = {'userId': userId}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _devicesDelete({required String? id}) { + final Uri $url = Uri.parse('/Devices'); + final Map $params = {'id': id}; + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _devicesInfoGet({required String? id}) { + final Uri $url = Uri.parse('/Devices/Info'); + final Map $params = {'id': id}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _devicesOptionsGet({required String? id}) { + final Uri $url = Uri.parse('/Devices/Options'); + final Map $params = {'id': id}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _devicesOptionsPost({ + required String? id, + required DeviceOptionsDto? body, + }) { + final Uri $url = Uri.parse('/Devices/Options'); + final Map $params = {'id': id}; + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> + _displayPreferencesDisplayPreferencesIdGet({ + required String? displayPreferencesId, + String? userId, + required String? $client, + }) { + final Uri $url = Uri.parse('/DisplayPreferences/${displayPreferencesId}'); + final Map $params = { + 'userId': userId, + 'client': $client, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _displayPreferencesDisplayPreferencesIdPost({ + required String? displayPreferencesId, + String? userId, + required String? $client, + required DisplayPreferencesDto? body, + }) { + final Uri $url = Uri.parse('/DisplayPreferences/${displayPreferencesId}'); + final Map $params = { + 'userId': userId, + 'client': $client, + }; + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _audioItemIdHls1PlaylistIdSegmentIdContainerGet({ + required String? itemId, + required String? playlistId, + required int? segmentId, + required String? container, + required int? runtimeTicks, + required int? actualSegmentLengthTicks, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? maxStreamingBitrate, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? videoBitRate, + int? subtitleStreamIndex, + String? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + String? context, + Object? streamOptions, + }) { + final Uri $url = Uri.parse( + '/Audio/${itemId}/hls1/${playlistId}/${segmentId}.${container}'); + final Map $params = { + 'runtimeTicks': runtimeTicks, + 'actualSegmentLengthTicks': actualSegmentLengthTicks, + 'static': $static, + 'params': params, + 'tag': tag, + 'deviceProfileId': deviceProfileId, + 'playSessionId': playSessionId, + 'segmentContainer': segmentContainer, + 'segmentLength': segmentLength, + 'minSegments': minSegments, + 'mediaSourceId': mediaSourceId, + 'deviceId': deviceId, + 'audioCodec': audioCodec, + 'enableAutoStreamCopy': enableAutoStreamCopy, + 'allowVideoStreamCopy': allowVideoStreamCopy, + 'allowAudioStreamCopy': allowAudioStreamCopy, + 'breakOnNonKeyFrames': breakOnNonKeyFrames, + 'audioSampleRate': audioSampleRate, + 'maxAudioBitDepth': maxAudioBitDepth, + 'maxStreamingBitrate': maxStreamingBitrate, + 'audioBitRate': audioBitRate, + 'audioChannels': audioChannels, + 'maxAudioChannels': maxAudioChannels, + 'profile': profile, + 'level': level, + 'framerate': framerate, + 'maxFramerate': maxFramerate, + 'copyTimestamps': copyTimestamps, + 'startTimeTicks': startTimeTicks, + 'width': width, + 'height': height, + 'videoBitRate': videoBitRate, + 'subtitleStreamIndex': subtitleStreamIndex, + 'subtitleMethod': subtitleMethod, + 'maxRefFrames': maxRefFrames, + 'maxVideoBitDepth': maxVideoBitDepth, + 'requireAvc': requireAvc, + 'deInterlace': deInterlace, + 'requireNonAnamorphic': requireNonAnamorphic, + 'transcodingMaxAudioChannels': transcodingMaxAudioChannels, + 'cpuCoreLimit': cpuCoreLimit, + 'liveStreamId': liveStreamId, + 'enableMpegtsM2TsMode': enableMpegtsM2TsMode, + 'videoCodec': videoCodec, + 'subtitleCodec': subtitleCodec, + 'transcodeReasons': transcodeReasons, + 'audioStreamIndex': audioStreamIndex, + 'videoStreamIndex': videoStreamIndex, + 'context': context, + 'streamOptions': streamOptions, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _audioItemIdMainM3u8Get({ + required String? itemId, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? maxStreamingBitrate, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? videoBitRate, + int? subtitleStreamIndex, + String? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + String? context, + Object? streamOptions, + }) { + final Uri $url = Uri.parse('/Audio/${itemId}/main.m3u8'); + final Map $params = { + 'static': $static, + 'params': params, + 'tag': tag, + 'deviceProfileId': deviceProfileId, + 'playSessionId': playSessionId, + 'segmentContainer': segmentContainer, + 'segmentLength': segmentLength, + 'minSegments': minSegments, + 'mediaSourceId': mediaSourceId, + 'deviceId': deviceId, + 'audioCodec': audioCodec, + 'enableAutoStreamCopy': enableAutoStreamCopy, + 'allowVideoStreamCopy': allowVideoStreamCopy, + 'allowAudioStreamCopy': allowAudioStreamCopy, + 'breakOnNonKeyFrames': breakOnNonKeyFrames, + 'audioSampleRate': audioSampleRate, + 'maxAudioBitDepth': maxAudioBitDepth, + 'maxStreamingBitrate': maxStreamingBitrate, + 'audioBitRate': audioBitRate, + 'audioChannels': audioChannels, + 'maxAudioChannels': maxAudioChannels, + 'profile': profile, + 'level': level, + 'framerate': framerate, + 'maxFramerate': maxFramerate, + 'copyTimestamps': copyTimestamps, + 'startTimeTicks': startTimeTicks, + 'width': width, + 'height': height, + 'videoBitRate': videoBitRate, + 'subtitleStreamIndex': subtitleStreamIndex, + 'subtitleMethod': subtitleMethod, + 'maxRefFrames': maxRefFrames, + 'maxVideoBitDepth': maxVideoBitDepth, + 'requireAvc': requireAvc, + 'deInterlace': deInterlace, + 'requireNonAnamorphic': requireNonAnamorphic, + 'transcodingMaxAudioChannels': transcodingMaxAudioChannels, + 'cpuCoreLimit': cpuCoreLimit, + 'liveStreamId': liveStreamId, + 'enableMpegtsM2TsMode': enableMpegtsM2TsMode, + 'videoCodec': videoCodec, + 'subtitleCodec': subtitleCodec, + 'transcodeReasons': transcodeReasons, + 'audioStreamIndex': audioStreamIndex, + 'videoStreamIndex': videoStreamIndex, + 'context': context, + 'streamOptions': streamOptions, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _audioItemIdMasterM3u8Get({ + required String? itemId, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + required String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? maxStreamingBitrate, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? videoBitRate, + int? subtitleStreamIndex, + String? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + String? context, + Object? streamOptions, + bool? enableAdaptiveBitrateStreaming, + }) { + final Uri $url = Uri.parse('/Audio/${itemId}/master.m3u8'); + final Map $params = { + 'static': $static, + 'params': params, + 'tag': tag, + 'deviceProfileId': deviceProfileId, + 'playSessionId': playSessionId, + 'segmentContainer': segmentContainer, + 'segmentLength': segmentLength, + 'minSegments': minSegments, + 'mediaSourceId': mediaSourceId, + 'deviceId': deviceId, + 'audioCodec': audioCodec, + 'enableAutoStreamCopy': enableAutoStreamCopy, + 'allowVideoStreamCopy': allowVideoStreamCopy, + 'allowAudioStreamCopy': allowAudioStreamCopy, + 'breakOnNonKeyFrames': breakOnNonKeyFrames, + 'audioSampleRate': audioSampleRate, + 'maxAudioBitDepth': maxAudioBitDepth, + 'maxStreamingBitrate': maxStreamingBitrate, + 'audioBitRate': audioBitRate, + 'audioChannels': audioChannels, + 'maxAudioChannels': maxAudioChannels, + 'profile': profile, + 'level': level, + 'framerate': framerate, + 'maxFramerate': maxFramerate, + 'copyTimestamps': copyTimestamps, + 'startTimeTicks': startTimeTicks, + 'width': width, + 'height': height, + 'videoBitRate': videoBitRate, + 'subtitleStreamIndex': subtitleStreamIndex, + 'subtitleMethod': subtitleMethod, + 'maxRefFrames': maxRefFrames, + 'maxVideoBitDepth': maxVideoBitDepth, + 'requireAvc': requireAvc, + 'deInterlace': deInterlace, + 'requireNonAnamorphic': requireNonAnamorphic, + 'transcodingMaxAudioChannels': transcodingMaxAudioChannels, + 'cpuCoreLimit': cpuCoreLimit, + 'liveStreamId': liveStreamId, + 'enableMpegtsM2TsMode': enableMpegtsM2TsMode, + 'videoCodec': videoCodec, + 'subtitleCodec': subtitleCodec, + 'transcodeReasons': transcodeReasons, + 'audioStreamIndex': audioStreamIndex, + 'videoStreamIndex': videoStreamIndex, + 'context': context, + 'streamOptions': streamOptions, + 'enableAdaptiveBitrateStreaming': enableAdaptiveBitrateStreaming, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _audioItemIdMasterM3u8Head({ + required String? itemId, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + required String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? maxStreamingBitrate, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? videoBitRate, + int? subtitleStreamIndex, + String? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + String? context, + Object? streamOptions, + bool? enableAdaptiveBitrateStreaming, + }) { + final Uri $url = Uri.parse('/Audio/${itemId}/master.m3u8'); + final Map $params = { + 'static': $static, + 'params': params, + 'tag': tag, + 'deviceProfileId': deviceProfileId, + 'playSessionId': playSessionId, + 'segmentContainer': segmentContainer, + 'segmentLength': segmentLength, + 'minSegments': minSegments, + 'mediaSourceId': mediaSourceId, + 'deviceId': deviceId, + 'audioCodec': audioCodec, + 'enableAutoStreamCopy': enableAutoStreamCopy, + 'allowVideoStreamCopy': allowVideoStreamCopy, + 'allowAudioStreamCopy': allowAudioStreamCopy, + 'breakOnNonKeyFrames': breakOnNonKeyFrames, + 'audioSampleRate': audioSampleRate, + 'maxAudioBitDepth': maxAudioBitDepth, + 'maxStreamingBitrate': maxStreamingBitrate, + 'audioBitRate': audioBitRate, + 'audioChannels': audioChannels, + 'maxAudioChannels': maxAudioChannels, + 'profile': profile, + 'level': level, + 'framerate': framerate, + 'maxFramerate': maxFramerate, + 'copyTimestamps': copyTimestamps, + 'startTimeTicks': startTimeTicks, + 'width': width, + 'height': height, + 'videoBitRate': videoBitRate, + 'subtitleStreamIndex': subtitleStreamIndex, + 'subtitleMethod': subtitleMethod, + 'maxRefFrames': maxRefFrames, + 'maxVideoBitDepth': maxVideoBitDepth, + 'requireAvc': requireAvc, + 'deInterlace': deInterlace, + 'requireNonAnamorphic': requireNonAnamorphic, + 'transcodingMaxAudioChannels': transcodingMaxAudioChannels, + 'cpuCoreLimit': cpuCoreLimit, + 'liveStreamId': liveStreamId, + 'enableMpegtsM2TsMode': enableMpegtsM2TsMode, + 'videoCodec': videoCodec, + 'subtitleCodec': subtitleCodec, + 'transcodeReasons': transcodeReasons, + 'audioStreamIndex': audioStreamIndex, + 'videoStreamIndex': videoStreamIndex, + 'context': context, + 'streamOptions': streamOptions, + 'enableAdaptiveBitrateStreaming': enableAdaptiveBitrateStreaming, + }; + final Request $request = Request( + 'HEAD', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _videosItemIdHls1PlaylistIdSegmentIdContainerGet({ + required String? itemId, + required String? playlistId, + required int? segmentId, + required String? container, + required int? runtimeTicks, + required int? actualSegmentLengthTicks, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? maxWidth, + int? maxHeight, + int? videoBitRate, + int? subtitleStreamIndex, + String? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + String? context, + Object? streamOptions, + }) { + final Uri $url = Uri.parse( + '/Videos/${itemId}/hls1/${playlistId}/${segmentId}.${container}'); + final Map $params = { + 'runtimeTicks': runtimeTicks, + 'actualSegmentLengthTicks': actualSegmentLengthTicks, + 'static': $static, + 'params': params, + 'tag': tag, + 'deviceProfileId': deviceProfileId, + 'playSessionId': playSessionId, + 'segmentContainer': segmentContainer, + 'segmentLength': segmentLength, + 'minSegments': minSegments, + 'mediaSourceId': mediaSourceId, + 'deviceId': deviceId, + 'audioCodec': audioCodec, + 'enableAutoStreamCopy': enableAutoStreamCopy, + 'allowVideoStreamCopy': allowVideoStreamCopy, + 'allowAudioStreamCopy': allowAudioStreamCopy, + 'breakOnNonKeyFrames': breakOnNonKeyFrames, + 'audioSampleRate': audioSampleRate, + 'maxAudioBitDepth': maxAudioBitDepth, + 'audioBitRate': audioBitRate, + 'audioChannels': audioChannels, + 'maxAudioChannels': maxAudioChannels, + 'profile': profile, + 'level': level, + 'framerate': framerate, + 'maxFramerate': maxFramerate, + 'copyTimestamps': copyTimestamps, + 'startTimeTicks': startTimeTicks, + 'width': width, + 'height': height, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'videoBitRate': videoBitRate, + 'subtitleStreamIndex': subtitleStreamIndex, + 'subtitleMethod': subtitleMethod, + 'maxRefFrames': maxRefFrames, + 'maxVideoBitDepth': maxVideoBitDepth, + 'requireAvc': requireAvc, + 'deInterlace': deInterlace, + 'requireNonAnamorphic': requireNonAnamorphic, + 'transcodingMaxAudioChannels': transcodingMaxAudioChannels, + 'cpuCoreLimit': cpuCoreLimit, + 'liveStreamId': liveStreamId, + 'enableMpegtsM2TsMode': enableMpegtsM2TsMode, + 'videoCodec': videoCodec, + 'subtitleCodec': subtitleCodec, + 'transcodeReasons': transcodeReasons, + 'audioStreamIndex': audioStreamIndex, + 'videoStreamIndex': videoStreamIndex, + 'context': context, + 'streamOptions': streamOptions, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _videosItemIdLiveM3u8Get({ + required String? itemId, + String? container, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? videoBitRate, + int? subtitleStreamIndex, + String? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + String? context, + Object? streamOptions, + int? maxWidth, + int? maxHeight, + bool? enableSubtitlesInManifest, + }) { + final Uri $url = Uri.parse('/Videos/${itemId}/live.m3u8'); + final Map $params = { + 'container': container, + 'static': $static, + 'params': params, + 'tag': tag, + 'deviceProfileId': deviceProfileId, + 'playSessionId': playSessionId, + 'segmentContainer': segmentContainer, + 'segmentLength': segmentLength, + 'minSegments': minSegments, + 'mediaSourceId': mediaSourceId, + 'deviceId': deviceId, + 'audioCodec': audioCodec, + 'enableAutoStreamCopy': enableAutoStreamCopy, + 'allowVideoStreamCopy': allowVideoStreamCopy, + 'allowAudioStreamCopy': allowAudioStreamCopy, + 'breakOnNonKeyFrames': breakOnNonKeyFrames, + 'audioSampleRate': audioSampleRate, + 'maxAudioBitDepth': maxAudioBitDepth, + 'audioBitRate': audioBitRate, + 'audioChannels': audioChannels, + 'maxAudioChannels': maxAudioChannels, + 'profile': profile, + 'level': level, + 'framerate': framerate, + 'maxFramerate': maxFramerate, + 'copyTimestamps': copyTimestamps, + 'startTimeTicks': startTimeTicks, + 'width': width, + 'height': height, + 'videoBitRate': videoBitRate, + 'subtitleStreamIndex': subtitleStreamIndex, + 'subtitleMethod': subtitleMethod, + 'maxRefFrames': maxRefFrames, + 'maxVideoBitDepth': maxVideoBitDepth, + 'requireAvc': requireAvc, + 'deInterlace': deInterlace, + 'requireNonAnamorphic': requireNonAnamorphic, + 'transcodingMaxAudioChannels': transcodingMaxAudioChannels, + 'cpuCoreLimit': cpuCoreLimit, + 'liveStreamId': liveStreamId, + 'enableMpegtsM2TsMode': enableMpegtsM2TsMode, + 'videoCodec': videoCodec, + 'subtitleCodec': subtitleCodec, + 'transcodeReasons': transcodeReasons, + 'audioStreamIndex': audioStreamIndex, + 'videoStreamIndex': videoStreamIndex, + 'context': context, + 'streamOptions': streamOptions, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'enableSubtitlesInManifest': enableSubtitlesInManifest, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _videosItemIdMainM3u8Get({ + required String? itemId, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? maxWidth, + int? maxHeight, + int? videoBitRate, + int? subtitleStreamIndex, + String? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + String? context, + Object? streamOptions, + }) { + final Uri $url = Uri.parse('/Videos/${itemId}/main.m3u8'); + final Map $params = { + 'static': $static, + 'params': params, + 'tag': tag, + 'deviceProfileId': deviceProfileId, + 'playSessionId': playSessionId, + 'segmentContainer': segmentContainer, + 'segmentLength': segmentLength, + 'minSegments': minSegments, + 'mediaSourceId': mediaSourceId, + 'deviceId': deviceId, + 'audioCodec': audioCodec, + 'enableAutoStreamCopy': enableAutoStreamCopy, + 'allowVideoStreamCopy': allowVideoStreamCopy, + 'allowAudioStreamCopy': allowAudioStreamCopy, + 'breakOnNonKeyFrames': breakOnNonKeyFrames, + 'audioSampleRate': audioSampleRate, + 'maxAudioBitDepth': maxAudioBitDepth, + 'audioBitRate': audioBitRate, + 'audioChannels': audioChannels, + 'maxAudioChannels': maxAudioChannels, + 'profile': profile, + 'level': level, + 'framerate': framerate, + 'maxFramerate': maxFramerate, + 'copyTimestamps': copyTimestamps, + 'startTimeTicks': startTimeTicks, + 'width': width, + 'height': height, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'videoBitRate': videoBitRate, + 'subtitleStreamIndex': subtitleStreamIndex, + 'subtitleMethod': subtitleMethod, + 'maxRefFrames': maxRefFrames, + 'maxVideoBitDepth': maxVideoBitDepth, + 'requireAvc': requireAvc, + 'deInterlace': deInterlace, + 'requireNonAnamorphic': requireNonAnamorphic, + 'transcodingMaxAudioChannels': transcodingMaxAudioChannels, + 'cpuCoreLimit': cpuCoreLimit, + 'liveStreamId': liveStreamId, + 'enableMpegtsM2TsMode': enableMpegtsM2TsMode, + 'videoCodec': videoCodec, + 'subtitleCodec': subtitleCodec, + 'transcodeReasons': transcodeReasons, + 'audioStreamIndex': audioStreamIndex, + 'videoStreamIndex': videoStreamIndex, + 'context': context, + 'streamOptions': streamOptions, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _videosItemIdMasterM3u8Get({ + required String? itemId, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + required String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? maxWidth, + int? maxHeight, + int? videoBitRate, + int? subtitleStreamIndex, + String? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + String? context, + Object? streamOptions, + bool? enableAdaptiveBitrateStreaming, + bool? enableTrickplay, + }) { + final Uri $url = Uri.parse('/Videos/${itemId}/master.m3u8'); + final Map $params = { + 'static': $static, + 'params': params, + 'tag': tag, + 'deviceProfileId': deviceProfileId, + 'playSessionId': playSessionId, + 'segmentContainer': segmentContainer, + 'segmentLength': segmentLength, + 'minSegments': minSegments, + 'mediaSourceId': mediaSourceId, + 'deviceId': deviceId, + 'audioCodec': audioCodec, + 'enableAutoStreamCopy': enableAutoStreamCopy, + 'allowVideoStreamCopy': allowVideoStreamCopy, + 'allowAudioStreamCopy': allowAudioStreamCopy, + 'breakOnNonKeyFrames': breakOnNonKeyFrames, + 'audioSampleRate': audioSampleRate, + 'maxAudioBitDepth': maxAudioBitDepth, + 'audioBitRate': audioBitRate, + 'audioChannels': audioChannels, + 'maxAudioChannels': maxAudioChannels, + 'profile': profile, + 'level': level, + 'framerate': framerate, + 'maxFramerate': maxFramerate, + 'copyTimestamps': copyTimestamps, + 'startTimeTicks': startTimeTicks, + 'width': width, + 'height': height, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'videoBitRate': videoBitRate, + 'subtitleStreamIndex': subtitleStreamIndex, + 'subtitleMethod': subtitleMethod, + 'maxRefFrames': maxRefFrames, + 'maxVideoBitDepth': maxVideoBitDepth, + 'requireAvc': requireAvc, + 'deInterlace': deInterlace, + 'requireNonAnamorphic': requireNonAnamorphic, + 'transcodingMaxAudioChannels': transcodingMaxAudioChannels, + 'cpuCoreLimit': cpuCoreLimit, + 'liveStreamId': liveStreamId, + 'enableMpegtsM2TsMode': enableMpegtsM2TsMode, + 'videoCodec': videoCodec, + 'subtitleCodec': subtitleCodec, + 'transcodeReasons': transcodeReasons, + 'audioStreamIndex': audioStreamIndex, + 'videoStreamIndex': videoStreamIndex, + 'context': context, + 'streamOptions': streamOptions, + 'enableAdaptiveBitrateStreaming': enableAdaptiveBitrateStreaming, + 'enableTrickplay': enableTrickplay, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _videosItemIdMasterM3u8Head({ + required String? itemId, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + required String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? maxWidth, + int? maxHeight, + int? videoBitRate, + int? subtitleStreamIndex, + String? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + String? context, + Object? streamOptions, + bool? enableAdaptiveBitrateStreaming, + bool? enableTrickplay, + }) { + final Uri $url = Uri.parse('/Videos/${itemId}/master.m3u8'); + final Map $params = { + 'static': $static, + 'params': params, + 'tag': tag, + 'deviceProfileId': deviceProfileId, + 'playSessionId': playSessionId, + 'segmentContainer': segmentContainer, + 'segmentLength': segmentLength, + 'minSegments': minSegments, + 'mediaSourceId': mediaSourceId, + 'deviceId': deviceId, + 'audioCodec': audioCodec, + 'enableAutoStreamCopy': enableAutoStreamCopy, + 'allowVideoStreamCopy': allowVideoStreamCopy, + 'allowAudioStreamCopy': allowAudioStreamCopy, + 'breakOnNonKeyFrames': breakOnNonKeyFrames, + 'audioSampleRate': audioSampleRate, + 'maxAudioBitDepth': maxAudioBitDepth, + 'audioBitRate': audioBitRate, + 'audioChannels': audioChannels, + 'maxAudioChannels': maxAudioChannels, + 'profile': profile, + 'level': level, + 'framerate': framerate, + 'maxFramerate': maxFramerate, + 'copyTimestamps': copyTimestamps, + 'startTimeTicks': startTimeTicks, + 'width': width, + 'height': height, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'videoBitRate': videoBitRate, + 'subtitleStreamIndex': subtitleStreamIndex, + 'subtitleMethod': subtitleMethod, + 'maxRefFrames': maxRefFrames, + 'maxVideoBitDepth': maxVideoBitDepth, + 'requireAvc': requireAvc, + 'deInterlace': deInterlace, + 'requireNonAnamorphic': requireNonAnamorphic, + 'transcodingMaxAudioChannels': transcodingMaxAudioChannels, + 'cpuCoreLimit': cpuCoreLimit, + 'liveStreamId': liveStreamId, + 'enableMpegtsM2TsMode': enableMpegtsM2TsMode, + 'videoCodec': videoCodec, + 'subtitleCodec': subtitleCodec, + 'transcodeReasons': transcodeReasons, + 'audioStreamIndex': audioStreamIndex, + 'videoStreamIndex': videoStreamIndex, + 'context': context, + 'streamOptions': streamOptions, + 'enableAdaptiveBitrateStreaming': enableAdaptiveBitrateStreaming, + 'enableTrickplay': enableTrickplay, + }; + final Request $request = Request( + 'HEAD', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> + _environmentDefaultDirectoryBrowserGet() { + final Uri $url = Uri.parse('/Environment/DefaultDirectoryBrowser'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future>> _environmentDirectoryContentsGet({ + required String? path, + bool? includeFiles, + bool? includeDirectories, + }) { + final Uri $url = Uri.parse('/Environment/DirectoryContents'); + final Map $params = { + 'path': path, + 'includeFiles': includeFiles, + 'includeDirectories': includeDirectories, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send, FileSystemEntryInfo>($request); + } + + @override + Future>> _environmentDrivesGet() { + final Uri $url = Uri.parse('/Environment/Drives'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client + .send, FileSystemEntryInfo>($request); + } + + @override + Future>> _environmentNetworkSharesGet() { + final Uri $url = Uri.parse('/Environment/NetworkShares'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client + .send, FileSystemEntryInfo>($request); + } + + @override + Future> _environmentParentPathGet({required String? path}) { + final Uri $url = Uri.parse('/Environment/ParentPath'); + final Map $params = {'path': path}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _environmentValidatePathPost( + {required ValidatePathDto? body}) { + final Uri $url = Uri.parse('/Environment/ValidatePath'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _itemsFiltersGet({ + String? userId, + String? parentId, + List? includeItemTypes, + List? mediaTypes, + }) { + final Uri $url = Uri.parse('/Items/Filters'); + final Map $params = { + 'userId': userId, + 'parentId': parentId, + 'includeItemTypes': includeItemTypes, + 'mediaTypes': mediaTypes, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _itemsFilters2Get({ + String? userId, + String? parentId, + List? includeItemTypes, + bool? isAiring, + bool? isMovie, + bool? isSports, + bool? isKids, + bool? isNews, + bool? isSeries, + bool? recursive, + }) { + final Uri $url = Uri.parse('/Items/Filters2'); + final Map $params = { + 'userId': userId, + 'parentId': parentId, + 'includeItemTypes': includeItemTypes, + 'isAiring': isAiring, + 'isMovie': isMovie, + 'isSports': isSports, + 'isKids': isKids, + 'isNews': isNews, + 'isSeries': isSeries, + 'recursive': recursive, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _genresGet({ + int? startIndex, + int? limit, + String? searchTerm, + String? parentId, + List? fields, + List? excludeItemTypes, + List? includeItemTypes, + bool? isFavorite, + int? imageTypeLimit, + List? enableImageTypes, + String? userId, + String? nameStartsWithOrGreater, + String? nameStartsWith, + String? nameLessThan, + List? sortBy, + List? sortOrder, + bool? enableImages, + bool? enableTotalRecordCount, + }) { + final Uri $url = Uri.parse('/Genres'); + final Map $params = { + 'startIndex': startIndex, + 'limit': limit, + 'searchTerm': searchTerm, + 'parentId': parentId, + 'fields': fields, + 'excludeItemTypes': excludeItemTypes, + 'includeItemTypes': includeItemTypes, + 'isFavorite': isFavorite, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + 'userId': userId, + 'nameStartsWithOrGreater': nameStartsWithOrGreater, + 'nameStartsWith': nameStartsWith, + 'nameLessThan': nameLessThan, + 'sortBy': sortBy, + 'sortOrder': sortOrder, + 'enableImages': enableImages, + 'enableTotalRecordCount': enableTotalRecordCount, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _genresGenreNameGet({ + required String? genreName, + String? userId, + }) { + final Uri $url = Uri.parse('/Genres/${genreName}'); + final Map $params = {'userId': userId}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _audioItemIdHlsSegmentIdStreamAacGet({ + required String? itemId, + required String? segmentId, + }) { + final Uri $url = Uri.parse('/Audio/${itemId}/hls/${segmentId}/stream.aac'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _audioItemIdHlsSegmentIdStreamMp3Get({ + required String? itemId, + required String? segmentId, + }) { + final Uri $url = Uri.parse('/Audio/${itemId}/hls/${segmentId}/stream.mp3'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> + _videosItemIdHlsPlaylistIdSegmentIdSegmentContainerGet({ + required String? itemId, + required String? playlistId, + required String? segmentId, + required String? segmentContainer, + }) { + final Uri $url = Uri.parse( + '/Videos/${itemId}/hls/${playlistId}/${segmentId}.${segmentContainer}'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _videosItemIdHlsPlaylistIdStreamM3u8Get({ + required String? itemId, + required String? playlistId, + }) { + final Uri $url = + Uri.parse('/Videos/${itemId}/hls/${playlistId}/stream.m3u8'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _videosActiveEncodingsDelete({ + required String? deviceId, + required String? playSessionId, + }) { + final Uri $url = Uri.parse('/Videos/ActiveEncodings'); + final Map $params = { + 'deviceId': deviceId, + 'playSessionId': playSessionId, + }; + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _artistsNameImagesImageTypeImageIndexGet({ + required String? name, + required String? imageType, + String? tag, + String? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + required int? imageIndex, + }) { + final Uri $url = + Uri.parse('/Artists/${name}/Images/${imageType}/${imageIndex}'); + final Map $params = { + 'tag': tag, + 'format': format, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'percentPlayed': percentPlayed, + 'unplayedCount': unplayedCount, + 'width': width, + 'height': height, + 'quality': quality, + 'fillWidth': fillWidth, + 'fillHeight': fillHeight, + 'blur': blur, + 'backgroundColor': backgroundColor, + 'foregroundLayer': foregroundLayer, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _artistsNameImagesImageTypeImageIndexHead({ + required String? name, + required String? imageType, + String? tag, + String? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + required int? imageIndex, + }) { + final Uri $url = + Uri.parse('/Artists/${name}/Images/${imageType}/${imageIndex}'); + final Map $params = { + 'tag': tag, + 'format': format, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'percentPlayed': percentPlayed, + 'unplayedCount': unplayedCount, + 'width': width, + 'height': height, + 'quality': quality, + 'fillWidth': fillWidth, + 'fillHeight': fillHeight, + 'blur': blur, + 'backgroundColor': backgroundColor, + 'foregroundLayer': foregroundLayer, + }; + final Request $request = Request( + 'HEAD', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _brandingSplashscreenGet({ + String? tag, + String? format, + int? maxWidth, + int? maxHeight, + int? width, + int? height, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + int? quality, + }) { + final Uri $url = Uri.parse('/Branding/Splashscreen'); + final Map $params = { + 'tag': tag, + 'format': format, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'width': width, + 'height': height, + 'fillWidth': fillWidth, + 'fillHeight': fillHeight, + 'blur': blur, + 'backgroundColor': backgroundColor, + 'foregroundLayer': foregroundLayer, + 'quality': quality, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _brandingSplashscreenPost({required Object? body}) { + final Uri $url = Uri.parse('/Branding/Splashscreen'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _brandingSplashscreenDelete() { + final Uri $url = Uri.parse('/Branding/Splashscreen'); + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _genresNameImagesImageTypeGet({ + required String? name, + required String? imageType, + String? tag, + String? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + int? imageIndex, + }) { + final Uri $url = Uri.parse('/Genres/${name}/Images/${imageType}'); + final Map $params = { + 'tag': tag, + 'format': format, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'percentPlayed': percentPlayed, + 'unplayedCount': unplayedCount, + 'width': width, + 'height': height, + 'quality': quality, + 'fillWidth': fillWidth, + 'fillHeight': fillHeight, + 'blur': blur, + 'backgroundColor': backgroundColor, + 'foregroundLayer': foregroundLayer, + 'imageIndex': imageIndex, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _genresNameImagesImageTypeHead({ + required String? name, + required String? imageType, + String? tag, + String? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + int? imageIndex, + }) { + final Uri $url = Uri.parse('/Genres/${name}/Images/${imageType}'); + final Map $params = { + 'tag': tag, + 'format': format, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'percentPlayed': percentPlayed, + 'unplayedCount': unplayedCount, + 'width': width, + 'height': height, + 'quality': quality, + 'fillWidth': fillWidth, + 'fillHeight': fillHeight, + 'blur': blur, + 'backgroundColor': backgroundColor, + 'foregroundLayer': foregroundLayer, + 'imageIndex': imageIndex, + }; + final Request $request = Request( + 'HEAD', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _genresNameImagesImageTypeImageIndexGet({ + required String? name, + required String? imageType, + required int? imageIndex, + String? tag, + String? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + }) { + final Uri $url = + Uri.parse('/Genres/${name}/Images/${imageType}/${imageIndex}'); + final Map $params = { + 'tag': tag, + 'format': format, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'percentPlayed': percentPlayed, + 'unplayedCount': unplayedCount, + 'width': width, + 'height': height, + 'quality': quality, + 'fillWidth': fillWidth, + 'fillHeight': fillHeight, + 'blur': blur, + 'backgroundColor': backgroundColor, + 'foregroundLayer': foregroundLayer, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _genresNameImagesImageTypeImageIndexHead({ + required String? name, + required String? imageType, + required int? imageIndex, + String? tag, + String? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + }) { + final Uri $url = + Uri.parse('/Genres/${name}/Images/${imageType}/${imageIndex}'); + final Map $params = { + 'tag': tag, + 'format': format, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'percentPlayed': percentPlayed, + 'unplayedCount': unplayedCount, + 'width': width, + 'height': height, + 'quality': quality, + 'fillWidth': fillWidth, + 'fillHeight': fillHeight, + 'blur': blur, + 'backgroundColor': backgroundColor, + 'foregroundLayer': foregroundLayer, + }; + final Request $request = Request( + 'HEAD', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future>> _itemsItemIdImagesGet( + {required String? itemId}) { + final Uri $url = Uri.parse('/Items/${itemId}/Images'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send, ImageInfo>($request); + } + + @override + Future> _itemsItemIdImagesImageTypeDelete({ + required String? itemId, + required String? imageType, + int? imageIndex, + }) { + final Uri $url = Uri.parse('/Items/${itemId}/Images/${imageType}'); + final Map $params = { + 'imageIndex': imageIndex + }; + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _itemsItemIdImagesImageTypePost({ + required String? itemId, + required String? imageType, + required Object? body, + }) { + final Uri $url = Uri.parse('/Items/${itemId}/Images/${imageType}'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _itemsItemIdImagesImageTypeGet({ + required String? itemId, + required String? imageType, + int? maxWidth, + int? maxHeight, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + String? tag, + String? format, + num? percentPlayed, + int? unplayedCount, + int? blur, + String? backgroundColor, + String? foregroundLayer, + int? imageIndex, + }) { + final Uri $url = Uri.parse('/Items/${itemId}/Images/${imageType}'); + final Map $params = { + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'width': width, + 'height': height, + 'quality': quality, + 'fillWidth': fillWidth, + 'fillHeight': fillHeight, + 'tag': tag, + 'format': format, + 'percentPlayed': percentPlayed, + 'unplayedCount': unplayedCount, + 'blur': blur, + 'backgroundColor': backgroundColor, + 'foregroundLayer': foregroundLayer, + 'imageIndex': imageIndex, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _itemsItemIdImagesImageTypeHead({ + required String? itemId, + required String? imageType, + int? maxWidth, + int? maxHeight, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + String? tag, + String? format, + num? percentPlayed, + int? unplayedCount, + int? blur, + String? backgroundColor, + String? foregroundLayer, + int? imageIndex, + }) { + final Uri $url = Uri.parse('/Items/${itemId}/Images/${imageType}'); + final Map $params = { + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'width': width, + 'height': height, + 'quality': quality, + 'fillWidth': fillWidth, + 'fillHeight': fillHeight, + 'tag': tag, + 'format': format, + 'percentPlayed': percentPlayed, + 'unplayedCount': unplayedCount, + 'blur': blur, + 'backgroundColor': backgroundColor, + 'foregroundLayer': foregroundLayer, + 'imageIndex': imageIndex, + }; + final Request $request = Request( + 'HEAD', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _itemsItemIdImagesImageTypeImageIndexDelete({ + required String? itemId, + required String? imageType, + required int? imageIndex, + }) { + final Uri $url = + Uri.parse('/Items/${itemId}/Images/${imageType}/${imageIndex}'); + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _itemsItemIdImagesImageTypeImageIndexPost({ + required String? itemId, + required String? imageType, + required int? imageIndex, + required Object? body, + }) { + final Uri $url = + Uri.parse('/Items/${itemId}/Images/${imageType}/${imageIndex}'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _itemsItemIdImagesImageTypeImageIndexGet({ + required String? itemId, + required String? imageType, + required int? imageIndex, + int? maxWidth, + int? maxHeight, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + String? tag, + String? format, + num? percentPlayed, + int? unplayedCount, + int? blur, + String? backgroundColor, + String? foregroundLayer, + }) { + final Uri $url = + Uri.parse('/Items/${itemId}/Images/${imageType}/${imageIndex}'); + final Map $params = { + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'width': width, + 'height': height, + 'quality': quality, + 'fillWidth': fillWidth, + 'fillHeight': fillHeight, + 'tag': tag, + 'format': format, + 'percentPlayed': percentPlayed, + 'unplayedCount': unplayedCount, + 'blur': blur, + 'backgroundColor': backgroundColor, + 'foregroundLayer': foregroundLayer, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _itemsItemIdImagesImageTypeImageIndexHead({ + required String? itemId, + required String? imageType, + required int? imageIndex, + int? maxWidth, + int? maxHeight, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + String? tag, + String? format, + num? percentPlayed, + int? unplayedCount, + int? blur, + String? backgroundColor, + String? foregroundLayer, + }) { + final Uri $url = + Uri.parse('/Items/${itemId}/Images/${imageType}/${imageIndex}'); + final Map $params = { + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'width': width, + 'height': height, + 'quality': quality, + 'fillWidth': fillWidth, + 'fillHeight': fillHeight, + 'tag': tag, + 'format': format, + 'percentPlayed': percentPlayed, + 'unplayedCount': unplayedCount, + 'blur': blur, + 'backgroundColor': backgroundColor, + 'foregroundLayer': foregroundLayer, + }; + final Request $request = Request( + 'HEAD', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> + _itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGet({ + required String? itemId, + required String? imageType, + required int? maxWidth, + required int? maxHeight, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + required String? tag, + required String? format, + required num? percentPlayed, + required int? unplayedCount, + int? blur, + String? backgroundColor, + String? foregroundLayer, + required int? imageIndex, + }) { + final Uri $url = Uri.parse( + '/Items/${itemId}/Images/${imageType}/${imageIndex}/${tag}/${format}/${maxWidth}/${maxHeight}/${percentPlayed}/${unplayedCount}'); + final Map $params = { + 'width': width, + 'height': height, + 'quality': quality, + 'fillWidth': fillWidth, + 'fillHeight': fillHeight, + 'blur': blur, + 'backgroundColor': backgroundColor, + 'foregroundLayer': foregroundLayer, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> + _itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHead({ + required String? itemId, + required String? imageType, + required int? maxWidth, + required int? maxHeight, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + required String? tag, + required String? format, + required num? percentPlayed, + required int? unplayedCount, + int? blur, + String? backgroundColor, + String? foregroundLayer, + required int? imageIndex, + }) { + final Uri $url = Uri.parse( + '/Items/${itemId}/Images/${imageType}/${imageIndex}/${tag}/${format}/${maxWidth}/${maxHeight}/${percentPlayed}/${unplayedCount}'); + final Map $params = { + 'width': width, + 'height': height, + 'quality': quality, + 'fillWidth': fillWidth, + 'fillHeight': fillHeight, + 'blur': blur, + 'backgroundColor': backgroundColor, + 'foregroundLayer': foregroundLayer, + }; + final Request $request = Request( + 'HEAD', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _itemsItemIdImagesImageTypeImageIndexIndexPost({ + required String? itemId, + required String? imageType, + required int? imageIndex, + required int? newIndex, + }) { + final Uri $url = + Uri.parse('/Items/${itemId}/Images/${imageType}/${imageIndex}/Index'); + final Map $params = { + 'newIndex': newIndex + }; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _musicGenresNameImagesImageTypeGet({ + required String? name, + required String? imageType, + String? tag, + String? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + int? imageIndex, + }) { + final Uri $url = Uri.parse('/MusicGenres/${name}/Images/${imageType}'); + final Map $params = { + 'tag': tag, + 'format': format, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'percentPlayed': percentPlayed, + 'unplayedCount': unplayedCount, + 'width': width, + 'height': height, + 'quality': quality, + 'fillWidth': fillWidth, + 'fillHeight': fillHeight, + 'blur': blur, + 'backgroundColor': backgroundColor, + 'foregroundLayer': foregroundLayer, + 'imageIndex': imageIndex, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _musicGenresNameImagesImageTypeHead({ + required String? name, + required String? imageType, + String? tag, + String? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + int? imageIndex, + }) { + final Uri $url = Uri.parse('/MusicGenres/${name}/Images/${imageType}'); + final Map $params = { + 'tag': tag, + 'format': format, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'percentPlayed': percentPlayed, + 'unplayedCount': unplayedCount, + 'width': width, + 'height': height, + 'quality': quality, + 'fillWidth': fillWidth, + 'fillHeight': fillHeight, + 'blur': blur, + 'backgroundColor': backgroundColor, + 'foregroundLayer': foregroundLayer, + 'imageIndex': imageIndex, + }; + final Request $request = Request( + 'HEAD', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _musicGenresNameImagesImageTypeImageIndexGet({ + required String? name, + required String? imageType, + required int? imageIndex, + String? tag, + String? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + }) { + final Uri $url = + Uri.parse('/MusicGenres/${name}/Images/${imageType}/${imageIndex}'); + final Map $params = { + 'tag': tag, + 'format': format, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'percentPlayed': percentPlayed, + 'unplayedCount': unplayedCount, + 'width': width, + 'height': height, + 'quality': quality, + 'fillWidth': fillWidth, + 'fillHeight': fillHeight, + 'blur': blur, + 'backgroundColor': backgroundColor, + 'foregroundLayer': foregroundLayer, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _musicGenresNameImagesImageTypeImageIndexHead({ + required String? name, + required String? imageType, + required int? imageIndex, + String? tag, + String? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + }) { + final Uri $url = + Uri.parse('/MusicGenres/${name}/Images/${imageType}/${imageIndex}'); + final Map $params = { + 'tag': tag, + 'format': format, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'percentPlayed': percentPlayed, + 'unplayedCount': unplayedCount, + 'width': width, + 'height': height, + 'quality': quality, + 'fillWidth': fillWidth, + 'fillHeight': fillHeight, + 'blur': blur, + 'backgroundColor': backgroundColor, + 'foregroundLayer': foregroundLayer, + }; + final Request $request = Request( + 'HEAD', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _personsNameImagesImageTypeGet({ + required String? name, + required String? imageType, + String? tag, + String? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + int? imageIndex, + }) { + final Uri $url = Uri.parse('/Persons/${name}/Images/${imageType}'); + final Map $params = { + 'tag': tag, + 'format': format, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'percentPlayed': percentPlayed, + 'unplayedCount': unplayedCount, + 'width': width, + 'height': height, + 'quality': quality, + 'fillWidth': fillWidth, + 'fillHeight': fillHeight, + 'blur': blur, + 'backgroundColor': backgroundColor, + 'foregroundLayer': foregroundLayer, + 'imageIndex': imageIndex, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _personsNameImagesImageTypeHead({ + required String? name, + required String? imageType, + String? tag, + String? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + int? imageIndex, + }) { + final Uri $url = Uri.parse('/Persons/${name}/Images/${imageType}'); + final Map $params = { + 'tag': tag, + 'format': format, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'percentPlayed': percentPlayed, + 'unplayedCount': unplayedCount, + 'width': width, + 'height': height, + 'quality': quality, + 'fillWidth': fillWidth, + 'fillHeight': fillHeight, + 'blur': blur, + 'backgroundColor': backgroundColor, + 'foregroundLayer': foregroundLayer, + 'imageIndex': imageIndex, + }; + final Request $request = Request( + 'HEAD', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _personsNameImagesImageTypeImageIndexGet({ + required String? name, + required String? imageType, + required int? imageIndex, + String? tag, + String? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + }) { + final Uri $url = + Uri.parse('/Persons/${name}/Images/${imageType}/${imageIndex}'); + final Map $params = { + 'tag': tag, + 'format': format, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'percentPlayed': percentPlayed, + 'unplayedCount': unplayedCount, + 'width': width, + 'height': height, + 'quality': quality, + 'fillWidth': fillWidth, + 'fillHeight': fillHeight, + 'blur': blur, + 'backgroundColor': backgroundColor, + 'foregroundLayer': foregroundLayer, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _personsNameImagesImageTypeImageIndexHead({ + required String? name, + required String? imageType, + required int? imageIndex, + String? tag, + String? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + }) { + final Uri $url = + Uri.parse('/Persons/${name}/Images/${imageType}/${imageIndex}'); + final Map $params = { + 'tag': tag, + 'format': format, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'percentPlayed': percentPlayed, + 'unplayedCount': unplayedCount, + 'width': width, + 'height': height, + 'quality': quality, + 'fillWidth': fillWidth, + 'fillHeight': fillHeight, + 'blur': blur, + 'backgroundColor': backgroundColor, + 'foregroundLayer': foregroundLayer, + }; + final Request $request = Request( + 'HEAD', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _studiosNameImagesImageTypeGet({ + required String? name, + required String? imageType, + String? tag, + String? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + int? imageIndex, + }) { + final Uri $url = Uri.parse('/Studios/${name}/Images/${imageType}'); + final Map $params = { + 'tag': tag, + 'format': format, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'percentPlayed': percentPlayed, + 'unplayedCount': unplayedCount, + 'width': width, + 'height': height, + 'quality': quality, + 'fillWidth': fillWidth, + 'fillHeight': fillHeight, + 'blur': blur, + 'backgroundColor': backgroundColor, + 'foregroundLayer': foregroundLayer, + 'imageIndex': imageIndex, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _studiosNameImagesImageTypeHead({ + required String? name, + required String? imageType, + String? tag, + String? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + int? imageIndex, + }) { + final Uri $url = Uri.parse('/Studios/${name}/Images/${imageType}'); + final Map $params = { + 'tag': tag, + 'format': format, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'percentPlayed': percentPlayed, + 'unplayedCount': unplayedCount, + 'width': width, + 'height': height, + 'quality': quality, + 'fillWidth': fillWidth, + 'fillHeight': fillHeight, + 'blur': blur, + 'backgroundColor': backgroundColor, + 'foregroundLayer': foregroundLayer, + 'imageIndex': imageIndex, + }; + final Request $request = Request( + 'HEAD', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _studiosNameImagesImageTypeImageIndexGet({ + required String? name, + required String? imageType, + required int? imageIndex, + String? tag, + String? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + }) { + final Uri $url = + Uri.parse('/Studios/${name}/Images/${imageType}/${imageIndex}'); + final Map $params = { + 'tag': tag, + 'format': format, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'percentPlayed': percentPlayed, + 'unplayedCount': unplayedCount, + 'width': width, + 'height': height, + 'quality': quality, + 'fillWidth': fillWidth, + 'fillHeight': fillHeight, + 'blur': blur, + 'backgroundColor': backgroundColor, + 'foregroundLayer': foregroundLayer, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _studiosNameImagesImageTypeImageIndexHead({ + required String? name, + required String? imageType, + required int? imageIndex, + String? tag, + String? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + }) { + final Uri $url = + Uri.parse('/Studios/${name}/Images/${imageType}/${imageIndex}'); + final Map $params = { + 'tag': tag, + 'format': format, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'percentPlayed': percentPlayed, + 'unplayedCount': unplayedCount, + 'width': width, + 'height': height, + 'quality': quality, + 'fillWidth': fillWidth, + 'fillHeight': fillHeight, + 'blur': blur, + 'backgroundColor': backgroundColor, + 'foregroundLayer': foregroundLayer, + }; + final Request $request = Request( + 'HEAD', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _userImagePost({ + String? userId, + required Object? body, + }) { + final Uri $url = Uri.parse('/UserImage'); + final Map $params = {'userId': userId}; + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _userImageDelete({String? userId}) { + final Uri $url = Uri.parse('/UserImage'); + final Map $params = {'userId': userId}; + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _userImageGet({ + String? userId, + String? tag, + String? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + int? imageIndex, + }) { + final Uri $url = Uri.parse('/UserImage'); + final Map $params = { + 'userId': userId, + 'tag': tag, + 'format': format, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'percentPlayed': percentPlayed, + 'unplayedCount': unplayedCount, + 'width': width, + 'height': height, + 'quality': quality, + 'fillWidth': fillWidth, + 'fillHeight': fillHeight, + 'blur': blur, + 'backgroundColor': backgroundColor, + 'foregroundLayer': foregroundLayer, + 'imageIndex': imageIndex, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _userImageHead({ + String? userId, + String? tag, + String? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + int? imageIndex, + }) { + final Uri $url = Uri.parse('/UserImage'); + final Map $params = { + 'userId': userId, + 'tag': tag, + 'format': format, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'percentPlayed': percentPlayed, + 'unplayedCount': unplayedCount, + 'width': width, + 'height': height, + 'quality': quality, + 'fillWidth': fillWidth, + 'fillHeight': fillHeight, + 'blur': blur, + 'backgroundColor': backgroundColor, + 'foregroundLayer': foregroundLayer, + 'imageIndex': imageIndex, + }; + final Request $request = Request( + 'HEAD', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _albumsItemIdInstantMixGet({ + required String? itemId, + String? userId, + int? limit, + List? fields, + bool? enableImages, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + }) { + final Uri $url = Uri.parse('/Albums/${itemId}/InstantMix'); + final Map $params = { + 'userId': userId, + 'limit': limit, + 'fields': fields, + 'enableImages': enableImages, + 'enableUserData': enableUserData, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _artistsItemIdInstantMixGet({ + required String? itemId, + String? userId, + int? limit, + List? fields, + bool? enableImages, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + }) { + final Uri $url = Uri.parse('/Artists/${itemId}/InstantMix'); + final Map $params = { + 'userId': userId, + 'limit': limit, + 'fields': fields, + 'enableImages': enableImages, + 'enableUserData': enableUserData, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _artistsInstantMixGet({ + required String? id, + String? userId, + int? limit, + List? fields, + bool? enableImages, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + }) { + final Uri $url = Uri.parse('/Artists/InstantMix'); + final Map $params = { + 'id': id, + 'userId': userId, + 'limit': limit, + 'fields': fields, + 'enableImages': enableImages, + 'enableUserData': enableUserData, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _itemsItemIdInstantMixGet({ + required String? itemId, + String? userId, + int? limit, + List? fields, + bool? enableImages, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + }) { + final Uri $url = Uri.parse('/Items/${itemId}/InstantMix'); + final Map $params = { + 'userId': userId, + 'limit': limit, + 'fields': fields, + 'enableImages': enableImages, + 'enableUserData': enableUserData, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _musicGenresNameInstantMixGet({ + required String? name, + String? userId, + int? limit, + List? fields, + bool? enableImages, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + }) { + final Uri $url = Uri.parse('/MusicGenres/${name}/InstantMix'); + final Map $params = { + 'userId': userId, + 'limit': limit, + 'fields': fields, + 'enableImages': enableImages, + 'enableUserData': enableUserData, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _musicGenresInstantMixGet({ + required String? id, + String? userId, + int? limit, + List? fields, + bool? enableImages, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + }) { + final Uri $url = Uri.parse('/MusicGenres/InstantMix'); + final Map $params = { + 'id': id, + 'userId': userId, + 'limit': limit, + 'fields': fields, + 'enableImages': enableImages, + 'enableUserData': enableUserData, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _playlistsItemIdInstantMixGet({ + required String? itemId, + String? userId, + int? limit, + List? fields, + bool? enableImages, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + }) { + final Uri $url = Uri.parse('/Playlists/${itemId}/InstantMix'); + final Map $params = { + 'userId': userId, + 'limit': limit, + 'fields': fields, + 'enableImages': enableImages, + 'enableUserData': enableUserData, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _songsItemIdInstantMixGet({ + required String? itemId, + String? userId, + int? limit, + List? fields, + bool? enableImages, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + }) { + final Uri $url = Uri.parse('/Songs/${itemId}/InstantMix'); + final Map $params = { + 'userId': userId, + 'limit': limit, + 'fields': fields, + 'enableImages': enableImages, + 'enableUserData': enableUserData, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future>> _itemsItemIdExternalIdInfosGet( + {required String? itemId}) { + final Uri $url = Uri.parse('/Items/${itemId}/ExternalIdInfos'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send, ExternalIdInfo>($request); + } + + @override + Future> _itemsRemoteSearchApplyItemIdPost({ + required String? itemId, + bool? replaceAllImages, + required RemoteSearchResult? body, + }) { + final Uri $url = Uri.parse('/Items/RemoteSearch/Apply/${itemId}'); + final Map $params = { + 'replaceAllImages': replaceAllImages + }; + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + parameters: $params, + ); + return client.send($request); + } + + @override + Future>> _itemsRemoteSearchBookPost( + {required BookInfoRemoteSearchQuery? body}) { + final Uri $url = Uri.parse('/Items/RemoteSearch/Book'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send, RemoteSearchResult>($request); + } + + @override + Future>> _itemsRemoteSearchBoxSetPost( + {required BoxSetInfoRemoteSearchQuery? body}) { + final Uri $url = Uri.parse('/Items/RemoteSearch/BoxSet'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send, RemoteSearchResult>($request); + } + + @override + Future>> _itemsRemoteSearchMoviePost( + {required MovieInfoRemoteSearchQuery? body}) { + final Uri $url = Uri.parse('/Items/RemoteSearch/Movie'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send, RemoteSearchResult>($request); + } + + @override + Future>> _itemsRemoteSearchMusicAlbumPost( + {required AlbumInfoRemoteSearchQuery? body}) { + final Uri $url = Uri.parse('/Items/RemoteSearch/MusicAlbum'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send, RemoteSearchResult>($request); + } + + @override + Future>> _itemsRemoteSearchMusicArtistPost( + {required ArtistInfoRemoteSearchQuery? body}) { + final Uri $url = Uri.parse('/Items/RemoteSearch/MusicArtist'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send, RemoteSearchResult>($request); + } + + @override + Future>> _itemsRemoteSearchMusicVideoPost( + {required MusicVideoInfoRemoteSearchQuery? body}) { + final Uri $url = Uri.parse('/Items/RemoteSearch/MusicVideo'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send, RemoteSearchResult>($request); + } + + @override + Future>> _itemsRemoteSearchPersonPost( + {required PersonLookupInfoRemoteSearchQuery? body}) { + final Uri $url = Uri.parse('/Items/RemoteSearch/Person'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send, RemoteSearchResult>($request); + } + + @override + Future>> _itemsRemoteSearchSeriesPost( + {required SeriesInfoRemoteSearchQuery? body}) { + final Uri $url = Uri.parse('/Items/RemoteSearch/Series'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send, RemoteSearchResult>($request); + } + + @override + Future>> _itemsRemoteSearchTrailerPost( + {required TrailerInfoRemoteSearchQuery? body}) { + final Uri $url = Uri.parse('/Items/RemoteSearch/Trailer'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send, RemoteSearchResult>($request); + } + + @override + Future> _itemsItemIdRefreshPost({ + required String? itemId, + String? metadataRefreshMode, + String? imageRefreshMode, + bool? replaceAllMetadata, + bool? replaceAllImages, + }) { + final Uri $url = Uri.parse('/Items/${itemId}/Refresh'); + final Map $params = { + 'metadataRefreshMode': metadataRefreshMode, + 'imageRefreshMode': imageRefreshMode, + 'replaceAllMetadata': replaceAllMetadata, + 'replaceAllImages': replaceAllImages, + }; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _itemsGet({ + String? userId, + String? maxOfficialRating, + bool? hasThemeSong, + bool? hasThemeVideo, + bool? hasSubtitles, + bool? hasSpecialFeature, + bool? hasTrailer, + String? adjacentTo, + int? parentIndexNumber, + bool? hasParentalRating, + bool? isHd, + bool? is4K, + List? locationTypes, + List? excludeLocationTypes, + bool? isMissing, + bool? isUnaired, + num? minCommunityRating, + num? minCriticRating, + DateTime? minPremiereDate, + DateTime? minDateLastSaved, + DateTime? minDateLastSavedForUser, + DateTime? maxPremiereDate, + bool? hasOverview, + bool? hasImdbId, + bool? hasTmdbId, + bool? hasTvdbId, + bool? isMovie, + bool? isSeries, + bool? isNews, + bool? isKids, + bool? isSports, + List? excludeItemIds, + int? startIndex, + int? limit, + bool? recursive, + String? searchTerm, + List? sortOrder, + String? parentId, + List? fields, + List? excludeItemTypes, + List? includeItemTypes, + List? filters, + bool? isFavorite, + List? mediaTypes, + List? imageTypes, + List? sortBy, + bool? isPlayed, + List? genres, + List? officialRatings, + List? tags, + List? years, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + String? person, + List? personIds, + List? personTypes, + List? studios, + List? artists, + List? excludeArtistIds, + List? artistIds, + List? albumArtistIds, + List? contributingArtistIds, + List? albums, + List? albumIds, + List? ids, + List? videoTypes, + String? minOfficialRating, + bool? isLocked, + bool? isPlaceHolder, + bool? hasOfficialRating, + bool? collapseBoxSetItems, + int? minWidth, + int? minHeight, + int? maxWidth, + int? maxHeight, + bool? is3D, + List? seriesStatus, + String? nameStartsWithOrGreater, + String? nameStartsWith, + String? nameLessThan, + List? studioIds, + List? genreIds, + bool? enableTotalRecordCount, + bool? enableImages, + }) { + final Uri $url = Uri.parse('/Items'); + final Map $params = { + 'userId': userId, + 'maxOfficialRating': maxOfficialRating, + 'hasThemeSong': hasThemeSong, + 'hasThemeVideo': hasThemeVideo, + 'hasSubtitles': hasSubtitles, + 'hasSpecialFeature': hasSpecialFeature, + 'hasTrailer': hasTrailer, + 'adjacentTo': adjacentTo, + 'parentIndexNumber': parentIndexNumber, + 'hasParentalRating': hasParentalRating, + 'isHd': isHd, + 'is4K': is4K, + 'locationTypes': locationTypes, + 'excludeLocationTypes': excludeLocationTypes, + 'isMissing': isMissing, + 'isUnaired': isUnaired, + 'minCommunityRating': minCommunityRating, + 'minCriticRating': minCriticRating, + 'minPremiereDate': minPremiereDate, + 'minDateLastSaved': minDateLastSaved, + 'minDateLastSavedForUser': minDateLastSavedForUser, + 'maxPremiereDate': maxPremiereDate, + 'hasOverview': hasOverview, + 'hasImdbId': hasImdbId, + 'hasTmdbId': hasTmdbId, + 'hasTvdbId': hasTvdbId, + 'isMovie': isMovie, + 'isSeries': isSeries, + 'isNews': isNews, + 'isKids': isKids, + 'isSports': isSports, + 'excludeItemIds': excludeItemIds, + 'startIndex': startIndex, + 'limit': limit, + 'recursive': recursive, + 'searchTerm': searchTerm, + 'sortOrder': sortOrder, + 'parentId': parentId, + 'fields': fields, + 'excludeItemTypes': excludeItemTypes, + 'includeItemTypes': includeItemTypes, + 'filters': filters, + 'isFavorite': isFavorite, + 'mediaTypes': mediaTypes, + 'imageTypes': imageTypes, + 'sortBy': sortBy, + 'isPlayed': isPlayed, + 'genres': genres, + 'officialRatings': officialRatings, + 'tags': tags, + 'years': years, + 'enableUserData': enableUserData, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + 'person': person, + 'personIds': personIds, + 'personTypes': personTypes, + 'studios': studios, + 'artists': artists, + 'excludeArtistIds': excludeArtistIds, + 'artistIds': artistIds, + 'albumArtistIds': albumArtistIds, + 'contributingArtistIds': contributingArtistIds, + 'albums': albums, + 'albumIds': albumIds, + 'ids': ids, + 'videoTypes': videoTypes, + 'minOfficialRating': minOfficialRating, + 'isLocked': isLocked, + 'isPlaceHolder': isPlaceHolder, + 'hasOfficialRating': hasOfficialRating, + 'collapseBoxSetItems': collapseBoxSetItems, + 'minWidth': minWidth, + 'minHeight': minHeight, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'is3D': is3D, + 'seriesStatus': seriesStatus, + 'nameStartsWithOrGreater': nameStartsWithOrGreater, + 'nameStartsWith': nameStartsWith, + 'nameLessThan': nameLessThan, + 'studioIds': studioIds, + 'genreIds': genreIds, + 'enableTotalRecordCount': enableTotalRecordCount, + 'enableImages': enableImages, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _itemsDelete({List? ids}) { + final Uri $url = Uri.parse('/Items'); + final Map $params = {'ids': ids}; + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _userItemsItemIdUserDataGet({ + String? userId, + required String? itemId, + }) { + final Uri $url = Uri.parse('/UserItems/${itemId}/UserData'); + final Map $params = {'userId': userId}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _userItemsItemIdUserDataPost({ + String? userId, + required String? itemId, + required UpdateUserItemDataDto? body, + }) { + final Uri $url = Uri.parse('/UserItems/${itemId}/UserData'); + final Map $params = {'userId': userId}; + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _userItemsResumeGet({ + String? userId, + int? startIndex, + int? limit, + String? searchTerm, + String? parentId, + List? fields, + List? mediaTypes, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + List? excludeItemTypes, + List? includeItemTypes, + bool? enableTotalRecordCount, + bool? enableImages, + bool? excludeActiveSessions, + }) { + final Uri $url = Uri.parse('/UserItems/Resume'); + final Map $params = { + 'userId': userId, + 'startIndex': startIndex, + 'limit': limit, + 'searchTerm': searchTerm, + 'parentId': parentId, + 'fields': fields, + 'mediaTypes': mediaTypes, + 'enableUserData': enableUserData, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + 'excludeItemTypes': excludeItemTypes, + 'includeItemTypes': includeItemTypes, + 'enableTotalRecordCount': enableTotalRecordCount, + 'enableImages': enableImages, + 'excludeActiveSessions': excludeActiveSessions, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _itemsItemIdPost({ + required String? itemId, + required BaseItemDto? body, + }) { + final Uri $url = Uri.parse('/Items/${itemId}'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _itemsItemIdDelete({required String? itemId}) { + final Uri $url = Uri.parse('/Items/${itemId}'); + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _itemsItemIdGet({ + String? userId, + required String? itemId, + }) { + final Uri $url = Uri.parse('/Items/${itemId}'); + final Map $params = {'userId': userId}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _itemsItemIdContentTypePost({ + required String? itemId, + String? contentType, + }) { + final Uri $url = Uri.parse('/Items/${itemId}/ContentType'); + final Map $params = { + 'contentType': contentType + }; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _itemsItemIdMetadataEditorGet( + {required String? itemId}) { + final Uri $url = Uri.parse('/Items/${itemId}/MetadataEditor'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _albumsItemIdSimilarGet({ + required String? itemId, + List? excludeArtistIds, + String? userId, + int? limit, + List? fields, + }) { + final Uri $url = Uri.parse('/Albums/${itemId}/Similar'); + final Map $params = { + 'excludeArtistIds': excludeArtistIds, + 'userId': userId, + 'limit': limit, + 'fields': fields, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _artistsItemIdSimilarGet({ + required String? itemId, + List? excludeArtistIds, + String? userId, + int? limit, + List? fields, + }) { + final Uri $url = Uri.parse('/Artists/${itemId}/Similar'); + final Map $params = { + 'excludeArtistIds': excludeArtistIds, + 'userId': userId, + 'limit': limit, + 'fields': fields, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future>> _itemsItemIdAncestorsGet({ + required String? itemId, + String? userId, + }) { + final Uri $url = Uri.parse('/Items/${itemId}/Ancestors'); + final Map $params = {'userId': userId}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send, BaseItemDto>($request); + } + + @override + Future> _itemsItemIdCriticReviewsGet( + {required String? itemId}) { + final Uri $url = Uri.parse('/Items/${itemId}/CriticReviews'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client + .send($request); + } + + @override + Future> _itemsItemIdDownloadGet({required String? itemId}) { + final Uri $url = Uri.parse('/Items/${itemId}/Download'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _itemsItemIdFileGet({required String? itemId}) { + final Uri $url = Uri.parse('/Items/${itemId}/File'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _itemsItemIdSimilarGet({ + required String? itemId, + List? excludeArtistIds, + String? userId, + int? limit, + List? fields, + }) { + final Uri $url = Uri.parse('/Items/${itemId}/Similar'); + final Map $params = { + 'excludeArtistIds': excludeArtistIds, + 'userId': userId, + 'limit': limit, + 'fields': fields, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _itemsItemIdThemeMediaGet({ + required String? itemId, + String? userId, + bool? inheritFromParent, + }) { + final Uri $url = Uri.parse('/Items/${itemId}/ThemeMedia'); + final Map $params = { + 'userId': userId, + 'inheritFromParent': inheritFromParent, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _itemsItemIdThemeSongsGet({ + required String? itemId, + String? userId, + bool? inheritFromParent, + }) { + final Uri $url = Uri.parse('/Items/${itemId}/ThemeSongs'); + final Map $params = { + 'userId': userId, + 'inheritFromParent': inheritFromParent, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _itemsItemIdThemeVideosGet({ + required String? itemId, + String? userId, + bool? inheritFromParent, + }) { + final Uri $url = Uri.parse('/Items/${itemId}/ThemeVideos'); + final Map $params = { + 'userId': userId, + 'inheritFromParent': inheritFromParent, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _itemsCountsGet({ + String? userId, + bool? isFavorite, + }) { + final Uri $url = Uri.parse('/Items/Counts'); + final Map $params = { + 'userId': userId, + 'isFavorite': isFavorite, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _librariesAvailableOptionsGet({ + String? libraryContentType, + bool? isNewLibrary, + }) { + final Uri $url = Uri.parse('/Libraries/AvailableOptions'); + final Map $params = { + 'libraryContentType': libraryContentType, + 'isNewLibrary': isNewLibrary, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _libraryMediaUpdatedPost( + {required MediaUpdateInfoDto? body}) { + final Uri $url = Uri.parse('/Library/Media/Updated'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _libraryMediaFoldersGet( + {bool? isHidden}) { + final Uri $url = Uri.parse('/Library/MediaFolders'); + final Map $params = { + 'isHidden': isHidden + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _libraryMoviesAddedPost({ + String? tmdbId, + String? imdbId, + }) { + final Uri $url = Uri.parse('/Library/Movies/Added'); + final Map $params = { + 'tmdbId': tmdbId, + 'imdbId': imdbId, + }; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _libraryMoviesUpdatedPost({ + String? tmdbId, + String? imdbId, + }) { + final Uri $url = Uri.parse('/Library/Movies/Updated'); + final Map $params = { + 'tmdbId': tmdbId, + 'imdbId': imdbId, + }; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future>> _libraryPhysicalPathsGet() { + final Uri $url = Uri.parse('/Library/PhysicalPaths'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send, String>($request); + } + + @override + Future> _libraryRefreshPost() { + final Uri $url = Uri.parse('/Library/Refresh'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _librarySeriesAddedPost({String? tvdbId}) { + final Uri $url = Uri.parse('/Library/Series/Added'); + final Map $params = {'tvdbId': tvdbId}; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _librarySeriesUpdatedPost({String? tvdbId}) { + final Uri $url = Uri.parse('/Library/Series/Updated'); + final Map $params = {'tvdbId': tvdbId}; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _moviesItemIdSimilarGet({ + required String? itemId, + List? excludeArtistIds, + String? userId, + int? limit, + List? fields, + }) { + final Uri $url = Uri.parse('/Movies/${itemId}/Similar'); + final Map $params = { + 'excludeArtistIds': excludeArtistIds, + 'userId': userId, + 'limit': limit, + 'fields': fields, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _showsItemIdSimilarGet({ + required String? itemId, + List? excludeArtistIds, + String? userId, + int? limit, + List? fields, + }) { + final Uri $url = Uri.parse('/Shows/${itemId}/Similar'); + final Map $params = { + 'excludeArtistIds': excludeArtistIds, + 'userId': userId, + 'limit': limit, + 'fields': fields, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _trailersItemIdSimilarGet({ + required String? itemId, + List? excludeArtistIds, + String? userId, + int? limit, + List? fields, + }) { + final Uri $url = Uri.parse('/Trailers/${itemId}/Similar'); + final Map $params = { + 'excludeArtistIds': excludeArtistIds, + 'userId': userId, + 'limit': limit, + 'fields': fields, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future>> _libraryVirtualFoldersGet() { + final Uri $url = Uri.parse('/Library/VirtualFolders'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send, VirtualFolderInfo>($request); + } + + @override + Future> _libraryVirtualFoldersPost({ + String? name, + String? collectionType, + List? paths, + bool? refreshLibrary, + required AddVirtualFolderDto? body, + }) { + final Uri $url = Uri.parse('/Library/VirtualFolders'); + final Map $params = { + 'name': name, + 'collectionType': collectionType, + 'paths': paths, + 'refreshLibrary': refreshLibrary, + }; + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _libraryVirtualFoldersDelete({ + String? name, + bool? refreshLibrary, + }) { + final Uri $url = Uri.parse('/Library/VirtualFolders'); + final Map $params = { + 'name': name, + 'refreshLibrary': refreshLibrary, + }; + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _libraryVirtualFoldersLibraryOptionsPost( + {required UpdateLibraryOptionsDto? body}) { + final Uri $url = Uri.parse('/Library/VirtualFolders/LibraryOptions'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _libraryVirtualFoldersNamePost({ + String? name, + String? newName, + bool? refreshLibrary, + }) { + final Uri $url = Uri.parse('/Library/VirtualFolders/Name'); + final Map $params = { + 'name': name, + 'newName': newName, + 'refreshLibrary': refreshLibrary, + }; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _libraryVirtualFoldersPathsPost({ + bool? refreshLibrary, + required MediaPathDto? body, + }) { + final Uri $url = Uri.parse('/Library/VirtualFolders/Paths'); + final Map $params = { + 'refreshLibrary': refreshLibrary + }; + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _libraryVirtualFoldersPathsDelete({ + String? name, + String? path, + bool? refreshLibrary, + }) { + final Uri $url = Uri.parse('/Library/VirtualFolders/Paths'); + final Map $params = { + 'name': name, + 'path': path, + 'refreshLibrary': refreshLibrary, + }; + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _libraryVirtualFoldersPathsUpdatePost( + {required UpdateMediaPathRequestDto? body}) { + final Uri $url = Uri.parse('/Library/VirtualFolders/Paths/Update'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _liveTvChannelMappingOptionsGet( + {String? providerId}) { + final Uri $url = Uri.parse('/LiveTv/ChannelMappingOptions'); + final Map $params = { + 'providerId': providerId + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _liveTvChannelMappingsPost( + {required SetChannelMappingDto? body}) { + final Uri $url = Uri.parse('/LiveTv/ChannelMappings'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _liveTvChannelsGet({ + String? type, + String? userId, + int? startIndex, + bool? isMovie, + bool? isSeries, + bool? isNews, + bool? isKids, + bool? isSports, + int? limit, + bool? isFavorite, + bool? isLiked, + bool? isDisliked, + bool? enableImages, + int? imageTypeLimit, + List? enableImageTypes, + List? fields, + bool? enableUserData, + List? sortBy, + String? sortOrder, + bool? enableFavoriteSorting, + bool? addCurrentProgram, + }) { + final Uri $url = Uri.parse('/LiveTv/Channels'); + final Map $params = { + 'type': type, + 'userId': userId, + 'startIndex': startIndex, + 'isMovie': isMovie, + 'isSeries': isSeries, + 'isNews': isNews, + 'isKids': isKids, + 'isSports': isSports, + 'limit': limit, + 'isFavorite': isFavorite, + 'isLiked': isLiked, + 'isDisliked': isDisliked, + 'enableImages': enableImages, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + 'fields': fields, + 'enableUserData': enableUserData, + 'sortBy': sortBy, + 'sortOrder': sortOrder, + 'enableFavoriteSorting': enableFavoriteSorting, + 'addCurrentProgram': addCurrentProgram, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _liveTvChannelsChannelIdGet({ + required String? channelId, + String? userId, + }) { + final Uri $url = Uri.parse('/LiveTv/Channels/${channelId}'); + final Map $params = {'userId': userId}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _liveTvGuideInfoGet() { + final Uri $url = Uri.parse('/LiveTv/GuideInfo'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _liveTvInfoGet() { + final Uri $url = Uri.parse('/LiveTv/Info'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _liveTvListingProvidersPost({ + String? pw, + bool? validateListings, + bool? validateLogin, + required ListingsProviderInfo? body, + }) { + final Uri $url = Uri.parse('/LiveTv/ListingProviders'); + final Map $params = { + 'pw': pw, + 'validateListings': validateListings, + 'validateLogin': validateLogin, + }; + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _liveTvListingProvidersDelete({String? id}) { + final Uri $url = Uri.parse('/LiveTv/ListingProviders'); + final Map $params = {'id': id}; + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _liveTvListingProvidersDefaultGet() { + final Uri $url = Uri.parse('/LiveTv/ListingProviders/Default'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future>> _liveTvListingProvidersLineupsGet({ + String? id, + String? type, + String? location, + String? country, + }) { + final Uri $url = Uri.parse('/LiveTv/ListingProviders/Lineups'); + final Map $params = { + 'id': id, + 'type': type, + 'location': location, + 'country': country, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send, NameIdPair>($request); + } + + @override + Future> + _liveTvListingProvidersSchedulesDirectCountriesGet() { + final Uri $url = + Uri.parse('/LiveTv/ListingProviders/SchedulesDirect/Countries'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _liveTvLiveRecordingsRecordingIdStreamGet( + {required String? recordingId}) { + final Uri $url = Uri.parse('/LiveTv/LiveRecordings/${recordingId}/stream'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _liveTvLiveStreamFilesStreamIdStreamContainerGet({ + required String? streamId, + required String? container, + }) { + final Uri $url = + Uri.parse('/LiveTv/LiveStreamFiles/${streamId}/stream.${container}'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _liveTvProgramsGet({ + List? channelIds, + String? userId, + DateTime? minStartDate, + bool? hasAired, + bool? isAiring, + DateTime? maxStartDate, + DateTime? minEndDate, + DateTime? maxEndDate, + bool? isMovie, + bool? isSeries, + bool? isNews, + bool? isKids, + bool? isSports, + int? startIndex, + int? limit, + List? sortBy, + List? sortOrder, + List? genres, + List? genreIds, + bool? enableImages, + int? imageTypeLimit, + List? enableImageTypes, + bool? enableUserData, + String? seriesTimerId, + String? librarySeriesId, + List? fields, + bool? enableTotalRecordCount, + }) { + final Uri $url = Uri.parse('/LiveTv/Programs'); + final Map $params = { + 'channelIds': channelIds, + 'userId': userId, + 'minStartDate': minStartDate, + 'hasAired': hasAired, + 'isAiring': isAiring, + 'maxStartDate': maxStartDate, + 'minEndDate': minEndDate, + 'maxEndDate': maxEndDate, + 'isMovie': isMovie, + 'isSeries': isSeries, + 'isNews': isNews, + 'isKids': isKids, + 'isSports': isSports, + 'startIndex': startIndex, + 'limit': limit, + 'sortBy': sortBy, + 'sortOrder': sortOrder, + 'genres': genres, + 'genreIds': genreIds, + 'enableImages': enableImages, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + 'enableUserData': enableUserData, + 'seriesTimerId': seriesTimerId, + 'librarySeriesId': librarySeriesId, + 'fields': fields, + 'enableTotalRecordCount': enableTotalRecordCount, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _liveTvProgramsPost( + {required GetProgramsDto? body}) { + final Uri $url = Uri.parse('/LiveTv/Programs'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client + .send($request); + } + + @override + Future> _liveTvProgramsProgramIdGet({ + required String? programId, + String? userId, + }) { + final Uri $url = Uri.parse('/LiveTv/Programs/${programId}'); + final Map $params = {'userId': userId}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _liveTvProgramsRecommendedGet({ + String? userId, + int? limit, + bool? isAiring, + bool? hasAired, + bool? isSeries, + bool? isMovie, + bool? isNews, + bool? isKids, + bool? isSports, + bool? enableImages, + int? imageTypeLimit, + List? enableImageTypes, + List? genreIds, + List? fields, + bool? enableUserData, + bool? enableTotalRecordCount, + }) { + final Uri $url = Uri.parse('/LiveTv/Programs/Recommended'); + final Map $params = { + 'userId': userId, + 'limit': limit, + 'isAiring': isAiring, + 'hasAired': hasAired, + 'isSeries': isSeries, + 'isMovie': isMovie, + 'isNews': isNews, + 'isKids': isKids, + 'isSports': isSports, + 'enableImages': enableImages, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + 'genreIds': genreIds, + 'fields': fields, + 'enableUserData': enableUserData, + 'enableTotalRecordCount': enableTotalRecordCount, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _liveTvRecordingsGet({ + String? channelId, + String? userId, + int? startIndex, + int? limit, + String? status, + bool? isInProgress, + String? seriesTimerId, + bool? enableImages, + int? imageTypeLimit, + List? enableImageTypes, + List? fields, + bool? enableUserData, + bool? isMovie, + bool? isSeries, + bool? isKids, + bool? isSports, + bool? isNews, + bool? isLibraryItem, + bool? enableTotalRecordCount, + }) { + final Uri $url = Uri.parse('/LiveTv/Recordings'); + final Map $params = { + 'channelId': channelId, + 'userId': userId, + 'startIndex': startIndex, + 'limit': limit, + 'status': status, + 'isInProgress': isInProgress, + 'seriesTimerId': seriesTimerId, + 'enableImages': enableImages, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + 'fields': fields, + 'enableUserData': enableUserData, + 'isMovie': isMovie, + 'isSeries': isSeries, + 'isKids': isKids, + 'isSports': isSports, + 'isNews': isNews, + 'isLibraryItem': isLibraryItem, + 'enableTotalRecordCount': enableTotalRecordCount, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _liveTvRecordingsRecordingIdGet({ + required String? recordingId, + String? userId, + }) { + final Uri $url = Uri.parse('/LiveTv/Recordings/${recordingId}'); + final Map $params = {'userId': userId}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _liveTvRecordingsRecordingIdDelete( + {required String? recordingId}) { + final Uri $url = Uri.parse('/LiveTv/Recordings/${recordingId}'); + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _liveTvRecordingsFoldersGet( + {String? userId}) { + final Uri $url = Uri.parse('/LiveTv/Recordings/Folders'); + final Map $params = {'userId': userId}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _liveTvRecordingsGroupsGet( + {String? userId}) { + final Uri $url = Uri.parse('/LiveTv/Recordings/Groups'); + final Map $params = {'userId': userId}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _liveTvRecordingsGroupsGroupIdGet( + {required String? groupId}) { + final Uri $url = Uri.parse('/LiveTv/Recordings/Groups/${groupId}'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _liveTvRecordingsSeriesGet({ + String? channelId, + String? userId, + String? groupId, + int? startIndex, + int? limit, + String? status, + bool? isInProgress, + String? seriesTimerId, + bool? enableImages, + int? imageTypeLimit, + List? enableImageTypes, + List? fields, + bool? enableUserData, + bool? enableTotalRecordCount, + }) { + final Uri $url = Uri.parse('/LiveTv/Recordings/Series'); + final Map $params = { + 'channelId': channelId, + 'userId': userId, + 'groupId': groupId, + 'startIndex': startIndex, + 'limit': limit, + 'status': status, + 'isInProgress': isInProgress, + 'seriesTimerId': seriesTimerId, + 'enableImages': enableImages, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + 'fields': fields, + 'enableUserData': enableUserData, + 'enableTotalRecordCount': enableTotalRecordCount, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _liveTvSeriesTimersGet({ + String? sortBy, + String? sortOrder, + }) { + final Uri $url = Uri.parse('/LiveTv/SeriesTimers'); + final Map $params = { + 'sortBy': sortBy, + 'sortOrder': sortOrder, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _liveTvSeriesTimersPost( + {required SeriesTimerInfoDto? body}) { + final Uri $url = Uri.parse('/LiveTv/SeriesTimers'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _liveTvSeriesTimersTimerIdGet( + {required String? timerId}) { + final Uri $url = Uri.parse('/LiveTv/SeriesTimers/${timerId}'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _liveTvSeriesTimersTimerIdDelete( + {required String? timerId}) { + final Uri $url = Uri.parse('/LiveTv/SeriesTimers/${timerId}'); + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _liveTvSeriesTimersTimerIdPost({ + required String? timerId, + required SeriesTimerInfoDto? body, + }) { + final Uri $url = Uri.parse('/LiveTv/SeriesTimers/${timerId}'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _liveTvTimersGet({ + String? channelId, + String? seriesTimerId, + bool? isActive, + bool? isScheduled, + }) { + final Uri $url = Uri.parse('/LiveTv/Timers'); + final Map $params = { + 'channelId': channelId, + 'seriesTimerId': seriesTimerId, + 'isActive': isActive, + 'isScheduled': isScheduled, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _liveTvTimersPost({required TimerInfoDto? body}) { + final Uri $url = Uri.parse('/LiveTv/Timers'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _liveTvTimersTimerIdGet( + {required String? timerId}) { + final Uri $url = Uri.parse('/LiveTv/Timers/${timerId}'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _liveTvTimersTimerIdDelete( + {required String? timerId}) { + final Uri $url = Uri.parse('/LiveTv/Timers/${timerId}'); + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _liveTvTimersTimerIdPost({ + required String? timerId, + required TimerInfoDto? body, + }) { + final Uri $url = Uri.parse('/LiveTv/Timers/${timerId}'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _liveTvTimersDefaultsGet( + {String? programId}) { + final Uri $url = Uri.parse('/LiveTv/Timers/Defaults'); + final Map $params = { + 'programId': programId + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _liveTvTunerHostsPost( + {required TunerHostInfo? body}) { + final Uri $url = Uri.parse('/LiveTv/TunerHosts'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _liveTvTunerHostsDelete({String? id}) { + final Uri $url = Uri.parse('/LiveTv/TunerHosts'); + final Map $params = {'id': id}; + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future>> _liveTvTunerHostsTypesGet() { + final Uri $url = Uri.parse('/LiveTv/TunerHosts/Types'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send, NameIdPair>($request); + } + + @override + Future> _liveTvTunersTunerIdResetPost( + {required String? tunerId}) { + final Uri $url = Uri.parse('/LiveTv/Tuners/${tunerId}/Reset'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future>> _liveTvTunersDiscoverGet( + {bool? newDevicesOnly}) { + final Uri $url = Uri.parse('/LiveTv/Tuners/Discover'); + final Map $params = { + 'newDevicesOnly': newDevicesOnly + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send, TunerHostInfo>($request); + } + + @override + Future>> _liveTvTunersDiscvoverGet( + {bool? newDevicesOnly}) { + final Uri $url = Uri.parse('/LiveTv/Tuners/Discvover'); + final Map $params = { + 'newDevicesOnly': newDevicesOnly + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send, TunerHostInfo>($request); + } + + @override + Future>> _localizationCountriesGet() { + final Uri $url = Uri.parse('/Localization/Countries'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send, CountryInfo>($request); + } + + @override + Future>> _localizationCulturesGet() { + final Uri $url = Uri.parse('/Localization/Cultures'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send, CultureDto>($request); + } + + @override + Future>> _localizationOptionsGet() { + final Uri $url = Uri.parse('/Localization/Options'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send, LocalizationOption>($request); + } + + @override + Future>> _localizationParentalRatingsGet() { + final Uri $url = Uri.parse('/Localization/ParentalRatings'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send, ParentalRating>($request); + } + + @override + Future> _audioItemIdLyricsGet({required String? itemId}) { + final Uri $url = Uri.parse('/Audio/${itemId}/Lyrics'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _audioItemIdLyricsPost({ + required String? itemId, + required String? fileName, + required Object? body, + }) { + final Uri $url = Uri.parse('/Audio/${itemId}/Lyrics'); + final Map $params = { + 'fileName': fileName + }; + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _audioItemIdLyricsDelete( + {required String? itemId}) { + final Uri $url = Uri.parse('/Audio/${itemId}/Lyrics'); + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future>> _audioItemIdRemoteSearchLyricsGet( + {required String? itemId}) { + final Uri $url = Uri.parse('/Audio/${itemId}/RemoteSearch/Lyrics'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send, RemoteLyricInfoDto>($request); + } + + @override + Future> _audioItemIdRemoteSearchLyricsLyricIdPost({ + required String? itemId, + required String? lyricId, + }) { + final Uri $url = + Uri.parse('/Audio/${itemId}/RemoteSearch/Lyrics/${lyricId}'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _providersLyricsLyricIdGet( + {required String? lyricId}) { + final Uri $url = Uri.parse('/Providers/Lyrics/${lyricId}'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _itemsItemIdPlaybackInfoGet({ + required String? itemId, + String? userId, + }) { + final Uri $url = Uri.parse('/Items/${itemId}/PlaybackInfo'); + final Map $params = {'userId': userId}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _itemsItemIdPlaybackInfoPost({ + required String? itemId, + String? userId, + int? maxStreamingBitrate, + int? startTimeTicks, + int? audioStreamIndex, + int? subtitleStreamIndex, + int? maxAudioChannels, + String? mediaSourceId, + String? liveStreamId, + bool? autoOpenLiveStream, + bool? enableDirectPlay, + bool? enableDirectStream, + bool? enableTranscoding, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + required PlaybackInfoDto? body, + }) { + final Uri $url = Uri.parse('/Items/${itemId}/PlaybackInfo'); + final Map $params = { + 'userId': userId, + 'maxStreamingBitrate': maxStreamingBitrate, + 'startTimeTicks': startTimeTicks, + 'audioStreamIndex': audioStreamIndex, + 'subtitleStreamIndex': subtitleStreamIndex, + 'maxAudioChannels': maxAudioChannels, + 'mediaSourceId': mediaSourceId, + 'liveStreamId': liveStreamId, + 'autoOpenLiveStream': autoOpenLiveStream, + 'enableDirectPlay': enableDirectPlay, + 'enableDirectStream': enableDirectStream, + 'enableTranscoding': enableTranscoding, + 'allowVideoStreamCopy': allowVideoStreamCopy, + 'allowAudioStreamCopy': allowAudioStreamCopy, + }; + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _liveStreamsClosePost( + {required String? liveStreamId}) { + final Uri $url = Uri.parse('/LiveStreams/Close'); + final Map $params = { + 'liveStreamId': liveStreamId + }; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _liveStreamsOpenPost({ + String? openToken, + String? userId, + String? playSessionId, + int? maxStreamingBitrate, + int? startTimeTicks, + int? audioStreamIndex, + int? subtitleStreamIndex, + int? maxAudioChannels, + String? itemId, + bool? enableDirectPlay, + bool? enableDirectStream, + required OpenLiveStreamDto? body, + }) { + final Uri $url = Uri.parse('/LiveStreams/Open'); + final Map $params = { + 'openToken': openToken, + 'userId': userId, + 'playSessionId': playSessionId, + 'maxStreamingBitrate': maxStreamingBitrate, + 'startTimeTicks': startTimeTicks, + 'audioStreamIndex': audioStreamIndex, + 'subtitleStreamIndex': subtitleStreamIndex, + 'maxAudioChannels': maxAudioChannels, + 'itemId': itemId, + 'enableDirectPlay': enableDirectPlay, + 'enableDirectStream': enableDirectStream, + }; + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _playbackBitrateTestGet({int? size}) { + final Uri $url = Uri.parse('/Playback/BitrateTest'); + final Map $params = {'size': size}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future>> _moviesRecommendationsGet({ + String? userId, + String? parentId, + List? fields, + int? categoryLimit, + int? itemLimit, + }) { + final Uri $url = Uri.parse('/Movies/Recommendations'); + final Map $params = { + 'userId': userId, + 'parentId': parentId, + 'fields': fields, + 'categoryLimit': categoryLimit, + 'itemLimit': itemLimit, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send, RecommendationDto>($request); + } + + @override + Future> _musicGenresGet({ + int? startIndex, + int? limit, + String? searchTerm, + String? parentId, + List? fields, + List? excludeItemTypes, + List? includeItemTypes, + bool? isFavorite, + int? imageTypeLimit, + List? enableImageTypes, + String? userId, + String? nameStartsWithOrGreater, + String? nameStartsWith, + String? nameLessThan, + List? sortBy, + List? sortOrder, + bool? enableImages, + bool? enableTotalRecordCount, + }) { + final Uri $url = Uri.parse('/MusicGenres'); + final Map $params = { + 'startIndex': startIndex, + 'limit': limit, + 'searchTerm': searchTerm, + 'parentId': parentId, + 'fields': fields, + 'excludeItemTypes': excludeItemTypes, + 'includeItemTypes': includeItemTypes, + 'isFavorite': isFavorite, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + 'userId': userId, + 'nameStartsWithOrGreater': nameStartsWithOrGreater, + 'nameStartsWith': nameStartsWith, + 'nameLessThan': nameLessThan, + 'sortBy': sortBy, + 'sortOrder': sortOrder, + 'enableImages': enableImages, + 'enableTotalRecordCount': enableTotalRecordCount, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _musicGenresGenreNameGet({ + required String? genreName, + String? userId, + }) { + final Uri $url = Uri.parse('/MusicGenres/${genreName}'); + final Map $params = {'userId': userId}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future>> _packagesGet() { + final Uri $url = Uri.parse('/Packages'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send, PackageInfo>($request); + } + + @override + Future> _packagesNameGet({ + required String? name, + String? assemblyGuid, + }) { + final Uri $url = Uri.parse('/Packages/${name}'); + final Map $params = { + 'assemblyGuid': assemblyGuid + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _packagesInstalledNamePost({ + required String? name, + String? assemblyGuid, + String? version, + String? repositoryUrl, + }) { + final Uri $url = Uri.parse('/Packages/Installed/${name}'); + final Map $params = { + 'assemblyGuid': assemblyGuid, + 'version': version, + 'repositoryUrl': repositoryUrl, + }; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _packagesInstallingPackageIdDelete( + {required String? packageId}) { + final Uri $url = Uri.parse('/Packages/Installing/${packageId}'); + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future>> _repositoriesGet() { + final Uri $url = Uri.parse('/Repositories'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send, RepositoryInfo>($request); + } + + @override + Future> _repositoriesPost( + {required List? body}) { + final Uri $url = Uri.parse('/Repositories'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _personsGet({ + int? limit, + String? searchTerm, + List? fields, + List? filters, + bool? isFavorite, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + List? excludePersonTypes, + List? personTypes, + String? appearsInItemId, + String? userId, + bool? enableImages, + }) { + final Uri $url = Uri.parse('/Persons'); + final Map $params = { + 'limit': limit, + 'searchTerm': searchTerm, + 'fields': fields, + 'filters': filters, + 'isFavorite': isFavorite, + 'enableUserData': enableUserData, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + 'excludePersonTypes': excludePersonTypes, + 'personTypes': personTypes, + 'appearsInItemId': appearsInItemId, + 'userId': userId, + 'enableImages': enableImages, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _personsNameGet({ + required String? name, + String? userId, + }) { + final Uri $url = Uri.parse('/Persons/${name}'); + final Map $params = {'userId': userId}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _userUsageStatsBreakdownTypeBreakdownReportGet({ + required String? breakdownType, + int? days, + DateTime? endDate, + num? timezoneOffset, + }) { + final Uri $url = + Uri.parse('/user_usage_stats/${breakdownType}/BreakdownReport'); + final Map $params = { + 'days': days, + 'endDate': endDate, + 'timezoneOffset': timezoneOffset, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _userUsageStatsUserIdDateGetItemsGet({ + required String? userId, + required String? date, + String? filter, + num? timezoneOffset, + }) { + final Uri $url = Uri.parse('/user_usage_stats/${userId}/${date}/GetItems'); + final Map $params = { + 'filter': filter, + 'timezoneOffset': timezoneOffset, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _userUsageStatsDurationHistogramReportGet({ + int? days, + DateTime? endDate, + String? filter, + }) { + final Uri $url = Uri.parse('/user_usage_stats/DurationHistogramReport'); + final Map $params = { + 'days': days, + 'endDate': endDate, + 'filter': filter, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _userUsageStatsGetTvShowsReportGet({ + int? days, + DateTime? endDate, + num? timezoneOffset, + }) { + final Uri $url = Uri.parse('/user_usage_stats/GetTvShowsReport'); + final Map $params = { + 'days': days, + 'endDate': endDate, + 'timezoneOffset': timezoneOffset, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _userUsageStatsHourlyReportGet({ + int? days, + DateTime? endDate, + String? filter, + num? timezoneOffset, + }) { + final Uri $url = Uri.parse('/user_usage_stats/HourlyReport'); + final Map $params = { + 'days': days, + 'endDate': endDate, + 'filter': filter, + 'timezoneOffset': timezoneOffset, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future>> _userUsageStatsLoadBackupGet( + {String? backupFilePath}) { + final Uri $url = Uri.parse('/user_usage_stats/load_backup'); + final Map $params = { + 'backupFilePath': backupFilePath + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send, String>($request); + } + + @override + Future> _userUsageStatsMoviesReportGet({ + int? days, + DateTime? endDate, + num? timezoneOffset, + }) { + final Uri $url = Uri.parse('/user_usage_stats/MoviesReport'); + final Map $params = { + 'days': days, + 'endDate': endDate, + 'timezoneOffset': timezoneOffset, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _userUsageStatsPlayActivityGet({ + int? days, + DateTime? endDate, + String? filter, + String? dataType, + num? timezoneOffset, + }) { + final Uri $url = Uri.parse('/user_usage_stats/PlayActivity'); + final Map $params = { + 'days': days, + 'endDate': endDate, + 'filter': filter, + 'dataType': dataType, + 'timezoneOffset': timezoneOffset, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future>> _userUsageStatsSaveBackupGet() { + final Uri $url = Uri.parse('/user_usage_stats/save_backup'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send, String>($request); + } + + @override + Future> _userUsageStatsSubmitCustomQueryPost( + {required CustomQueryData? body}) { + final Uri $url = Uri.parse('/user_usage_stats/submit_custom_query'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _userUsageStatsTypeFilterListGet() { + final Uri $url = Uri.parse('/user_usage_stats/type_filter_list'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _userUsageStatsUserActivityGet({ + int? days, + DateTime? endDate, + num? timezoneOffset, + }) { + final Uri $url = Uri.parse('/user_usage_stats/user_activity'); + final Map $params = { + 'days': days, + 'endDate': endDate, + 'timezoneOffset': timezoneOffset, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _userUsageStatsUserListGet() { + final Uri $url = Uri.parse('/user_usage_stats/user_list'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _userUsageStatsUserManageAddGet({String? id}) { + final Uri $url = Uri.parse('/user_usage_stats/user_manage/add'); + final Map $params = {'id': id}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _userUsageStatsUserManagePruneGet() { + final Uri $url = Uri.parse('/user_usage_stats/user_manage/prune'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _userUsageStatsUserManageRemoveGet({String? id}) { + final Uri $url = Uri.parse('/user_usage_stats/user_manage/remove'); + final Map $params = {'id': id}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _playlistsPost({ + String? name, + List? ids, + String? userId, + String? mediaType, + required CreatePlaylistDto? body, + }) { + final Uri $url = Uri.parse('/Playlists'); + final Map $params = { + 'name': name, + 'ids': ids, + 'userId': userId, + 'mediaType': mediaType, + }; + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _playlistsPlaylistIdPost({ + required String? playlistId, + required UpdatePlaylistDto? body, + }) { + final Uri $url = Uri.parse('/Playlists/${playlistId}'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _playlistsPlaylistIdItemsPost({ + required String? playlistId, + List? ids, + String? userId, + }) { + final Uri $url = Uri.parse('/Playlists/${playlistId}/Items'); + final Map $params = { + 'ids': ids, + 'userId': userId, + }; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _playlistsPlaylistIdItemsDelete({ + required String? playlistId, + List? entryIds, + }) { + final Uri $url = Uri.parse('/Playlists/${playlistId}/Items'); + final Map $params = { + 'entryIds': entryIds + }; + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _playlistsPlaylistIdItemsGet({ + required String? playlistId, + String? userId, + int? startIndex, + int? limit, + List? fields, + bool? enableImages, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + }) { + final Uri $url = Uri.parse('/Playlists/${playlistId}/Items'); + final Map $params = { + 'userId': userId, + 'startIndex': startIndex, + 'limit': limit, + 'fields': fields, + 'enableImages': enableImages, + 'enableUserData': enableUserData, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _playlistsPlaylistIdItemsItemIdMoveNewIndexPost({ + required String? playlistId, + required String? itemId, + required int? newIndex, + }) { + final Uri $url = + Uri.parse('/Playlists/${playlistId}/Items/${itemId}/Move/${newIndex}'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future>> _playlistsPlaylistIdUsersGet( + {required String? playlistId}) { + final Uri $url = Uri.parse('/Playlists/${playlistId}/Users'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client + .send, PlaylistUserPermissions>($request); + } + + @override + Future> _playlistsPlaylistIdUsersUserIdGet({ + required String? playlistId, + required String? userId, + }) { + final Uri $url = Uri.parse('/Playlists/${playlistId}/Users/${userId}'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client + .send($request); + } + + @override + Future> _playlistsPlaylistIdUsersUserIdPost({ + required String? playlistId, + required String? userId, + required UpdatePlaylistUserDto? body, + }) { + final Uri $url = Uri.parse('/Playlists/${playlistId}/Users/${userId}'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _playlistsPlaylistIdUsersUserIdDelete({ + required String? playlistId, + required String? userId, + }) { + final Uri $url = Uri.parse('/Playlists/${playlistId}/Users/${userId}'); + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _playingItemsItemIdPost({ + required String? itemId, + String? mediaSourceId, + int? audioStreamIndex, + int? subtitleStreamIndex, + String? playMethod, + String? liveStreamId, + String? playSessionId, + bool? canSeek, + }) { + final Uri $url = Uri.parse('/PlayingItems/${itemId}'); + final Map $params = { + 'mediaSourceId': mediaSourceId, + 'audioStreamIndex': audioStreamIndex, + 'subtitleStreamIndex': subtitleStreamIndex, + 'playMethod': playMethod, + 'liveStreamId': liveStreamId, + 'playSessionId': playSessionId, + 'canSeek': canSeek, + }; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _playingItemsItemIdDelete({ + required String? itemId, + String? mediaSourceId, + String? nextMediaType, + int? positionTicks, + String? liveStreamId, + String? playSessionId, + }) { + final Uri $url = Uri.parse('/PlayingItems/${itemId}'); + final Map $params = { + 'mediaSourceId': mediaSourceId, + 'nextMediaType': nextMediaType, + 'positionTicks': positionTicks, + 'liveStreamId': liveStreamId, + 'playSessionId': playSessionId, + }; + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _playingItemsItemIdProgressPost({ + required String? itemId, + String? mediaSourceId, + int? positionTicks, + int? audioStreamIndex, + int? subtitleStreamIndex, + int? volumeLevel, + String? playMethod, + String? liveStreamId, + String? playSessionId, + String? repeatMode, + bool? isPaused, + bool? isMuted, + }) { + final Uri $url = Uri.parse('/PlayingItems/${itemId}/Progress'); + final Map $params = { + 'mediaSourceId': mediaSourceId, + 'positionTicks': positionTicks, + 'audioStreamIndex': audioStreamIndex, + 'subtitleStreamIndex': subtitleStreamIndex, + 'volumeLevel': volumeLevel, + 'playMethod': playMethod, + 'liveStreamId': liveStreamId, + 'playSessionId': playSessionId, + 'repeatMode': repeatMode, + 'isPaused': isPaused, + 'isMuted': isMuted, + }; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _sessionsPlayingPost( + {required PlaybackStartInfo? body}) { + final Uri $url = Uri.parse('/Sessions/Playing'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _sessionsPlayingPingPost( + {required String? playSessionId}) { + final Uri $url = Uri.parse('/Sessions/Playing/Ping'); + final Map $params = { + 'playSessionId': playSessionId + }; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _sessionsPlayingProgressPost( + {required PlaybackProgressInfo? body}) { + final Uri $url = Uri.parse('/Sessions/Playing/Progress'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _sessionsPlayingStoppedPost( + {required PlaybackStopInfo? body}) { + final Uri $url = Uri.parse('/Sessions/Playing/Stopped'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _userPlayedItemsItemIdPost({ + String? userId, + required String? itemId, + DateTime? datePlayed, + }) { + final Uri $url = Uri.parse('/UserPlayedItems/${itemId}'); + final Map $params = { + 'userId': userId, + 'datePlayed': datePlayed, + }; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _userPlayedItemsItemIdDelete({ + String? userId, + required String? itemId, + }) { + final Uri $url = Uri.parse('/UserPlayedItems/${itemId}'); + final Map $params = {'userId': userId}; + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future>> _pluginsGet() { + final Uri $url = Uri.parse('/Plugins'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send, PluginInfo>($request); + } + + @override + Future> _pluginsPluginIdDelete( + {required String? pluginId}) { + final Uri $url = Uri.parse('/Plugins/${pluginId}'); + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _pluginsPluginIdVersionDelete({ + required String? pluginId, + required String? version, + }) { + final Uri $url = Uri.parse('/Plugins/${pluginId}/${version}'); + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _pluginsPluginIdVersionDisablePost({ + required String? pluginId, + required String? version, + }) { + final Uri $url = Uri.parse('/Plugins/${pluginId}/${version}/Disable'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _pluginsPluginIdVersionEnablePost({ + required String? pluginId, + required String? version, + }) { + final Uri $url = Uri.parse('/Plugins/${pluginId}/${version}/Enable'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _pluginsPluginIdVersionImageGet({ + required String? pluginId, + required String? version, + }) { + final Uri $url = Uri.parse('/Plugins/${pluginId}/${version}/Image'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _pluginsPluginIdConfigurationGet( + {required String? pluginId}) { + final Uri $url = Uri.parse('/Plugins/${pluginId}/Configuration'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client + .send($request); + } + + @override + Future> _pluginsPluginIdConfigurationPost( + {required String? pluginId}) { + final Uri $url = Uri.parse('/Plugins/${pluginId}/Configuration'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _pluginsPluginIdManifestPost( + {required String? pluginId}) { + final Uri $url = Uri.parse('/Plugins/${pluginId}/Manifest'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _quickConnectAuthorizePost({ + required String? code, + String? userId, + }) { + final Uri $url = Uri.parse('/QuickConnect/Authorize'); + final Map $params = { + 'code': code, + 'userId': userId, + }; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _quickConnectConnectGet( + {required String? secret}) { + final Uri $url = Uri.parse('/QuickConnect/Connect'); + final Map $params = {'secret': secret}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _quickConnectEnabledGet() { + final Uri $url = Uri.parse('/QuickConnect/Enabled'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _quickConnectInitiatePost() { + final Uri $url = Uri.parse('/QuickConnect/Initiate'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _itemsItemIdRemoteImagesGet({ + required String? itemId, + String? type, + int? startIndex, + int? limit, + String? providerName, + bool? includeAllLanguages, + }) { + final Uri $url = Uri.parse('/Items/${itemId}/RemoteImages'); + final Map $params = { + 'type': type, + 'startIndex': startIndex, + 'limit': limit, + 'providerName': providerName, + 'includeAllLanguages': includeAllLanguages, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _itemsItemIdRemoteImagesDownloadPost({ + required String? itemId, + required String? type, + String? imageUrl, + }) { + final Uri $url = Uri.parse('/Items/${itemId}/RemoteImages/Download'); + final Map $params = { + 'type': type, + 'imageUrl': imageUrl, + }; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future>> + _itemsItemIdRemoteImagesProvidersGet({required String? itemId}) { + final Uri $url = Uri.parse('/Items/${itemId}/RemoteImages/Providers'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send, ImageProviderInfo>($request); + } + + @override + Future>> _scheduledTasksGet({ + bool? isHidden, + bool? isEnabled, + }) { + final Uri $url = Uri.parse('/ScheduledTasks'); + final Map $params = { + 'isHidden': isHidden, + 'isEnabled': isEnabled, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send, TaskInfo>($request); + } + + @override + Future> _scheduledTasksTaskIdGet( + {required String? taskId}) { + final Uri $url = Uri.parse('/ScheduledTasks/${taskId}'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _scheduledTasksTaskIdTriggersPost({ + required String? taskId, + required List? body, + }) { + final Uri $url = Uri.parse('/ScheduledTasks/${taskId}/Triggers'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _scheduledTasksRunningTaskIdPost( + {required String? taskId}) { + final Uri $url = Uri.parse('/ScheduledTasks/Running/${taskId}'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _scheduledTasksRunningTaskIdDelete( + {required String? taskId}) { + final Uri $url = Uri.parse('/ScheduledTasks/Running/${taskId}'); + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _searchHintsGet({ + int? startIndex, + int? limit, + String? userId, + required String? searchTerm, + List? includeItemTypes, + List? excludeItemTypes, + List? mediaTypes, + String? parentId, + bool? isMovie, + bool? isSeries, + bool? isNews, + bool? isKids, + bool? isSports, + bool? includePeople, + bool? includeMedia, + bool? includeGenres, + bool? includeStudios, + bool? includeArtists, + }) { + final Uri $url = Uri.parse('/Search/Hints'); + final Map $params = { + 'startIndex': startIndex, + 'limit': limit, + 'userId': userId, + 'searchTerm': searchTerm, + 'includeItemTypes': includeItemTypes, + 'excludeItemTypes': excludeItemTypes, + 'mediaTypes': mediaTypes, + 'parentId': parentId, + 'isMovie': isMovie, + 'isSeries': isSeries, + 'isNews': isNews, + 'isKids': isKids, + 'isSports': isSports, + 'includePeople': includePeople, + 'includeMedia': includeMedia, + 'includeGenres': includeGenres, + 'includeStudios': includeStudios, + 'includeArtists': includeArtists, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future>> _authPasswordResetProvidersGet() { + final Uri $url = Uri.parse('/Auth/PasswordResetProviders'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send, NameIdPair>($request); + } + + @override + Future>> _authProvidersGet() { + final Uri $url = Uri.parse('/Auth/Providers'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send, NameIdPair>($request); + } + + @override + Future>> _sessionsGet({ + String? controllableByUserId, + String? deviceId, + int? activeWithinSeconds, + }) { + final Uri $url = Uri.parse('/Sessions'); + final Map $params = { + 'controllableByUserId': controllableByUserId, + 'deviceId': deviceId, + 'activeWithinSeconds': activeWithinSeconds, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send, SessionInfo>($request); + } + + @override + Future> _sessionsSessionIdCommandPost({ + required String? sessionId, + required GeneralCommand? body, + }) { + final Uri $url = Uri.parse('/Sessions/${sessionId}/Command'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _sessionsSessionIdCommandCommandPost({ + required String? sessionId, + required String? command, + }) { + final Uri $url = Uri.parse('/Sessions/${sessionId}/Command/${command}'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _sessionsSessionIdMessagePost({ + required String? sessionId, + required MessageCommand? body, + }) { + final Uri $url = Uri.parse('/Sessions/${sessionId}/Message'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _sessionsSessionIdPlayingPost({ + required String? sessionId, + required String? playCommand, + required List? itemIds, + int? startPositionTicks, + String? mediaSourceId, + int? audioStreamIndex, + int? subtitleStreamIndex, + int? startIndex, + }) { + final Uri $url = Uri.parse('/Sessions/${sessionId}/Playing'); + final Map $params = { + 'playCommand': playCommand, + 'itemIds': itemIds, + 'startPositionTicks': startPositionTicks, + 'mediaSourceId': mediaSourceId, + 'audioStreamIndex': audioStreamIndex, + 'subtitleStreamIndex': subtitleStreamIndex, + 'startIndex': startIndex, + }; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _sessionsSessionIdPlayingCommandPost({ + required String? sessionId, + required String? command, + int? seekPositionTicks, + String? controllingUserId, + }) { + final Uri $url = Uri.parse('/Sessions/${sessionId}/Playing/${command}'); + final Map $params = { + 'seekPositionTicks': seekPositionTicks, + 'controllingUserId': controllingUserId, + }; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _sessionsSessionIdSystemCommandPost({ + required String? sessionId, + required String? command, + }) { + final Uri $url = Uri.parse('/Sessions/${sessionId}/System/${command}'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _sessionsSessionIdUserUserIdPost({ + required String? sessionId, + required String? userId, + }) { + final Uri $url = Uri.parse('/Sessions/${sessionId}/User/${userId}'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _sessionsSessionIdUserUserIdDelete({ + required String? sessionId, + required String? userId, + }) { + final Uri $url = Uri.parse('/Sessions/${sessionId}/User/${userId}'); + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _sessionsSessionIdViewingPost({ + required String? sessionId, + required String? itemType, + required String? itemId, + required String? itemName, + }) { + final Uri $url = Uri.parse('/Sessions/${sessionId}/Viewing'); + final Map $params = { + 'itemType': itemType, + 'itemId': itemId, + 'itemName': itemName, + }; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _sessionsCapabilitiesPost({ + String? id, + List? playableMediaTypes, + List? supportedCommands, + bool? supportsMediaControl, + bool? supportsPersistentIdentifier, + }) { + final Uri $url = Uri.parse('/Sessions/Capabilities'); + final Map $params = { + 'id': id, + 'playableMediaTypes': playableMediaTypes, + 'supportedCommands': supportedCommands, + 'supportsMediaControl': supportsMediaControl, + 'supportsPersistentIdentifier': supportsPersistentIdentifier, + }; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _sessionsCapabilitiesFullPost({ + String? id, + required ClientCapabilitiesDto? body, + }) { + final Uri $url = Uri.parse('/Sessions/Capabilities/Full'); + final Map $params = {'id': id}; + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _sessionsLogoutPost() { + final Uri $url = Uri.parse('/Sessions/Logout'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _sessionsViewingPost({ + String? sessionId, + required String? itemId, + }) { + final Uri $url = Uri.parse('/Sessions/Viewing'); + final Map $params = { + 'sessionId': sessionId, + 'itemId': itemId, + }; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _episodeIdIntroSkipperSegmentsGet( + {required String? id}) { + final Uri $url = Uri.parse('/Episode/${id}/IntroSkipperSegments'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _episodeIdIntroTimestampsGet({ + required String? id, + String? mode, + }) { + final Uri $url = Uri.parse('/Episode/${id}/IntroTimestamps'); + final Map $params = {'mode': mode}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _episodeIdIntroTimestampsV1Get({ + required String? id, + String? mode, + }) { + final Uri $url = Uri.parse('/Episode/${id}/IntroTimestamps/v1'); + final Map $params = {'mode': mode}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future>> _introsAllGet({String? mode}) { + final Uri $url = Uri.parse('/Intros/All'); + final Map $params = {'mode': mode}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send, IntroWithMetadata>($request); + } + + @override + Future> _introsEraseTimestampsPost({ + String? mode, + bool? eraseCache, + }) { + final Uri $url = Uri.parse('/Intros/EraseTimestamps'); + final Map $params = { + 'mode': mode, + 'eraseCache': eraseCache, + }; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> + _introsUserInterfaceConfigurationGet() { + final Uri $url = Uri.parse('/Intros/UserInterfaceConfiguration'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client + .send($request); + } + + @override + Future> _startupCompletePost() { + final Uri $url = Uri.parse('/Startup/Complete'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _startupConfigurationGet() { + final Uri $url = Uri.parse('/Startup/Configuration'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client + .send($request); + } + + @override + Future> _startupConfigurationPost( + {required StartupConfigurationDto? body}) { + final Uri $url = Uri.parse('/Startup/Configuration'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _startupFirstUserGet() { + final Uri $url = Uri.parse('/Startup/FirstUser'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _startupRemoteAccessPost( + {required StartupRemoteAccessDto? body}) { + final Uri $url = Uri.parse('/Startup/RemoteAccess'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _startupUserGet() { + final Uri $url = Uri.parse('/Startup/User'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _startupUserPost({required StartupUserDto? body}) { + final Uri $url = Uri.parse('/Startup/User'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _studiosGet({ + int? startIndex, + int? limit, + String? searchTerm, + String? parentId, + List? fields, + List? excludeItemTypes, + List? includeItemTypes, + bool? isFavorite, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + String? userId, + String? nameStartsWithOrGreater, + String? nameStartsWith, + String? nameLessThan, + bool? enableImages, + bool? enableTotalRecordCount, + }) { + final Uri $url = Uri.parse('/Studios'); + final Map $params = { + 'startIndex': startIndex, + 'limit': limit, + 'searchTerm': searchTerm, + 'parentId': parentId, + 'fields': fields, + 'excludeItemTypes': excludeItemTypes, + 'includeItemTypes': includeItemTypes, + 'isFavorite': isFavorite, + 'enableUserData': enableUserData, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + 'userId': userId, + 'nameStartsWithOrGreater': nameStartsWithOrGreater, + 'nameStartsWith': nameStartsWith, + 'nameLessThan': nameLessThan, + 'enableImages': enableImages, + 'enableTotalRecordCount': enableTotalRecordCount, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _studiosNameGet({ + required String? name, + String? userId, + }) { + final Uri $url = Uri.parse('/Studios/${name}'); + final Map $params = {'userId': userId}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future>> _fallbackFontFontsGet() { + final Uri $url = Uri.parse('/FallbackFont/Fonts'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send, FontFile>($request); + } + + @override + Future> _fallbackFontFontsNameGet({required String? name}) { + final Uri $url = Uri.parse('/FallbackFont/Fonts/${name}'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future>> + _itemsItemIdRemoteSearchSubtitlesLanguageGet({ + required String? itemId, + required String? language, + bool? isPerfectMatch, + }) { + final Uri $url = + Uri.parse('/Items/${itemId}/RemoteSearch/Subtitles/${language}'); + final Map $params = { + 'isPerfectMatch': isPerfectMatch + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send, RemoteSubtitleInfo>($request); + } + + @override + Future> _itemsItemIdRemoteSearchSubtitlesSubtitleIdPost({ + required String? itemId, + required String? subtitleId, + }) { + final Uri $url = + Uri.parse('/Items/${itemId}/RemoteSearch/Subtitles/${subtitleId}'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _providersSubtitlesSubtitlesSubtitleIdGet( + {required String? subtitleId}) { + final Uri $url = Uri.parse('/Providers/Subtitles/Subtitles/${subtitleId}'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> + _videosItemIdMediaSourceIdSubtitlesIndexSubtitlesM3u8Get({ + required String? itemId, + required int? index, + required String? mediaSourceId, + required int? segmentLength, + }) { + final Uri $url = Uri.parse( + '/Videos/${itemId}/${mediaSourceId}/Subtitles/${index}/subtitles.m3u8'); + final Map $params = { + 'segmentLength': segmentLength + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _videosItemIdSubtitlesPost({ + required String? itemId, + required UploadSubtitleDto? body, + }) { + final Uri $url = Uri.parse('/Videos/${itemId}/Subtitles'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _videosItemIdSubtitlesIndexDelete({ + required String? itemId, + required int? index, + }) { + final Uri $url = Uri.parse('/Videos/${itemId}/Subtitles/${index}'); + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> + _videosRouteItemIdRouteMediaSourceIdSubtitlesRouteIndexRouteStartPositionTicksStreamRouteFormatGet({ + required String? routeItemId, + required String? routeMediaSourceId, + required int? routeIndex, + required int? routeStartPositionTicks, + required String? routeFormat, + String? itemId, + String? mediaSourceId, + int? index, + int? startPositionTicks, + String? format, + int? endPositionTicks, + bool? copyTimestamps, + bool? addVttTimeMap, + }) { + final Uri $url = Uri.parse( + '/Videos/${routeItemId}/${routeMediaSourceId}/Subtitles/${routeIndex}/${routeStartPositionTicks}/Stream.${routeFormat}'); + final Map $params = { + 'itemId': itemId, + 'mediaSourceId': mediaSourceId, + 'index': index, + 'startPositionTicks': startPositionTicks, + 'format': format, + 'endPositionTicks': endPositionTicks, + 'copyTimestamps': copyTimestamps, + 'addVttTimeMap': addVttTimeMap, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> + _videosRouteItemIdRouteMediaSourceIdSubtitlesRouteIndexStreamRouteFormatGet({ + required String? routeItemId, + required String? routeMediaSourceId, + required int? routeIndex, + required String? routeFormat, + String? itemId, + String? mediaSourceId, + int? index, + String? format, + int? endPositionTicks, + bool? copyTimestamps, + bool? addVttTimeMap, + int? startPositionTicks, + }) { + final Uri $url = Uri.parse( + '/Videos/${routeItemId}/${routeMediaSourceId}/Subtitles/${routeIndex}/Stream.${routeFormat}'); + final Map $params = { + 'itemId': itemId, + 'mediaSourceId': mediaSourceId, + 'index': index, + 'format': format, + 'endPositionTicks': endPositionTicks, + 'copyTimestamps': copyTimestamps, + 'addVttTimeMap': addVttTimeMap, + 'startPositionTicks': startPositionTicks, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _itemsSuggestionsGet({ + String? userId, + List? mediaType, + List? type, + int? startIndex, + int? limit, + bool? enableTotalRecordCount, + }) { + final Uri $url = Uri.parse('/Items/Suggestions'); + final Map $params = { + 'userId': userId, + 'mediaType': mediaType, + 'type': type, + 'startIndex': startIndex, + 'limit': limit, + 'enableTotalRecordCount': enableTotalRecordCount, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _syncPlayBufferingPost( + {required BufferRequestDto? body}) { + final Uri $url = Uri.parse('/SyncPlay/Buffering'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _syncPlayJoinPost( + {required JoinGroupRequestDto? body}) { + final Uri $url = Uri.parse('/SyncPlay/Join'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _syncPlayLeavePost() { + final Uri $url = Uri.parse('/SyncPlay/Leave'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future>> _syncPlayListGet() { + final Uri $url = Uri.parse('/SyncPlay/List'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send, GroupInfoDto>($request); + } + + @override + Future> _syncPlayMovePlaylistItemPost( + {required MovePlaylistItemRequestDto? body}) { + final Uri $url = Uri.parse('/SyncPlay/MovePlaylistItem'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _syncPlayNewPost( + {required NewGroupRequestDto? body}) { + final Uri $url = Uri.parse('/SyncPlay/New'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _syncPlayNextItemPost( + {required NextItemRequestDto? body}) { + final Uri $url = Uri.parse('/SyncPlay/NextItem'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _syncPlayPausePost() { + final Uri $url = Uri.parse('/SyncPlay/Pause'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _syncPlayPingPost({required PingRequestDto? body}) { + final Uri $url = Uri.parse('/SyncPlay/Ping'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _syncPlayPreviousItemPost( + {required PreviousItemRequestDto? body}) { + final Uri $url = Uri.parse('/SyncPlay/PreviousItem'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _syncPlayQueuePost( + {required QueueRequestDto? body}) { + final Uri $url = Uri.parse('/SyncPlay/Queue'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _syncPlayReadyPost( + {required ReadyRequestDto? body}) { + final Uri $url = Uri.parse('/SyncPlay/Ready'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _syncPlayRemoveFromPlaylistPost( + {required RemoveFromPlaylistRequestDto? body}) { + final Uri $url = Uri.parse('/SyncPlay/RemoveFromPlaylist'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _syncPlaySeekPost({required SeekRequestDto? body}) { + final Uri $url = Uri.parse('/SyncPlay/Seek'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _syncPlaySetIgnoreWaitPost( + {required IgnoreWaitRequestDto? body}) { + final Uri $url = Uri.parse('/SyncPlay/SetIgnoreWait'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _syncPlaySetNewQueuePost( + {required PlayRequestDto? body}) { + final Uri $url = Uri.parse('/SyncPlay/SetNewQueue'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _syncPlaySetPlaylistItemPost( + {required SetPlaylistItemRequestDto? body}) { + final Uri $url = Uri.parse('/SyncPlay/SetPlaylistItem'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _syncPlaySetRepeatModePost( + {required SetRepeatModeRequestDto? body}) { + final Uri $url = Uri.parse('/SyncPlay/SetRepeatMode'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _syncPlaySetShuffleModePost( + {required SetShuffleModeRequestDto? body}) { + final Uri $url = Uri.parse('/SyncPlay/SetShuffleMode'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _syncPlayStopPost() { + final Uri $url = Uri.parse('/SyncPlay/Stop'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _syncPlayUnpausePost() { + final Uri $url = Uri.parse('/SyncPlay/Unpause'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _systemEndpointGet() { + final Uri $url = Uri.parse('/System/Endpoint'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _systemInfoGet() { + final Uri $url = Uri.parse('/System/Info'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _systemInfoPublicGet() { + final Uri $url = Uri.parse('/System/Info/Public'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future>> _systemLogsGet() { + final Uri $url = Uri.parse('/System/Logs'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send, LogFile>($request); + } + + @override + Future> _systemLogsLogGet({required String? name}) { + final Uri $url = Uri.parse('/System/Logs/Log'); + final Map $params = {'name': name}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _systemPingGet() { + final Uri $url = Uri.parse('/System/Ping'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _systemPingPost() { + final Uri $url = Uri.parse('/System/Ping'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _systemRestartPost() { + final Uri $url = Uri.parse('/System/Restart'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _systemShutdownPost() { + final Uri $url = Uri.parse('/System/Shutdown'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future>> _systemWakeOnLanInfoGet() { + final Uri $url = Uri.parse('/System/WakeOnLanInfo'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send, WakeOnLanInfo>($request); + } + + @override + Future> _getUtcTimeGet() { + final Uri $url = Uri.parse('/GetUtcTime'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _tmdbClientConfigurationGet() { + final Uri $url = Uri.parse('/Tmdb/ClientConfiguration'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _tMDbBoxSetsRefreshPost() { + final Uri $url = Uri.parse('/TMDbBoxSets/Refresh'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _trailersGet({ + String? userId, + String? maxOfficialRating, + bool? hasThemeSong, + bool? hasThemeVideo, + bool? hasSubtitles, + bool? hasSpecialFeature, + bool? hasTrailer, + String? adjacentTo, + int? parentIndexNumber, + bool? hasParentalRating, + bool? isHd, + bool? is4K, + List? locationTypes, + List? excludeLocationTypes, + bool? isMissing, + bool? isUnaired, + num? minCommunityRating, + num? minCriticRating, + DateTime? minPremiereDate, + DateTime? minDateLastSaved, + DateTime? minDateLastSavedForUser, + DateTime? maxPremiereDate, + bool? hasOverview, + bool? hasImdbId, + bool? hasTmdbId, + bool? hasTvdbId, + bool? isMovie, + bool? isSeries, + bool? isNews, + bool? isKids, + bool? isSports, + List? excludeItemIds, + int? startIndex, + int? limit, + bool? recursive, + String? searchTerm, + List? sortOrder, + String? parentId, + List? fields, + List? excludeItemTypes, + List? filters, + bool? isFavorite, + List? mediaTypes, + List? imageTypes, + List? sortBy, + bool? isPlayed, + List? genres, + List? officialRatings, + List? tags, + List? years, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + String? person, + List? personIds, + List? personTypes, + List? studios, + List? artists, + List? excludeArtistIds, + List? artistIds, + List? albumArtistIds, + List? contributingArtistIds, + List? albums, + List? albumIds, + List? ids, + List? videoTypes, + String? minOfficialRating, + bool? isLocked, + bool? isPlaceHolder, + bool? hasOfficialRating, + bool? collapseBoxSetItems, + int? minWidth, + int? minHeight, + int? maxWidth, + int? maxHeight, + bool? is3D, + List? seriesStatus, + String? nameStartsWithOrGreater, + String? nameStartsWith, + String? nameLessThan, + List? studioIds, + List? genreIds, + bool? enableTotalRecordCount, + bool? enableImages, + }) { + final Uri $url = Uri.parse('/Trailers'); + final Map $params = { + 'userId': userId, + 'maxOfficialRating': maxOfficialRating, + 'hasThemeSong': hasThemeSong, + 'hasThemeVideo': hasThemeVideo, + 'hasSubtitles': hasSubtitles, + 'hasSpecialFeature': hasSpecialFeature, + 'hasTrailer': hasTrailer, + 'adjacentTo': adjacentTo, + 'parentIndexNumber': parentIndexNumber, + 'hasParentalRating': hasParentalRating, + 'isHd': isHd, + 'is4K': is4K, + 'locationTypes': locationTypes, + 'excludeLocationTypes': excludeLocationTypes, + 'isMissing': isMissing, + 'isUnaired': isUnaired, + 'minCommunityRating': minCommunityRating, + 'minCriticRating': minCriticRating, + 'minPremiereDate': minPremiereDate, + 'minDateLastSaved': minDateLastSaved, + 'minDateLastSavedForUser': minDateLastSavedForUser, + 'maxPremiereDate': maxPremiereDate, + 'hasOverview': hasOverview, + 'hasImdbId': hasImdbId, + 'hasTmdbId': hasTmdbId, + 'hasTvdbId': hasTvdbId, + 'isMovie': isMovie, + 'isSeries': isSeries, + 'isNews': isNews, + 'isKids': isKids, + 'isSports': isSports, + 'excludeItemIds': excludeItemIds, + 'startIndex': startIndex, + 'limit': limit, + 'recursive': recursive, + 'searchTerm': searchTerm, + 'sortOrder': sortOrder, + 'parentId': parentId, + 'fields': fields, + 'excludeItemTypes': excludeItemTypes, + 'filters': filters, + 'isFavorite': isFavorite, + 'mediaTypes': mediaTypes, + 'imageTypes': imageTypes, + 'sortBy': sortBy, + 'isPlayed': isPlayed, + 'genres': genres, + 'officialRatings': officialRatings, + 'tags': tags, + 'years': years, + 'enableUserData': enableUserData, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + 'person': person, + 'personIds': personIds, + 'personTypes': personTypes, + 'studios': studios, + 'artists': artists, + 'excludeArtistIds': excludeArtistIds, + 'artistIds': artistIds, + 'albumArtistIds': albumArtistIds, + 'contributingArtistIds': contributingArtistIds, + 'albums': albums, + 'albumIds': albumIds, + 'ids': ids, + 'videoTypes': videoTypes, + 'minOfficialRating': minOfficialRating, + 'isLocked': isLocked, + 'isPlaceHolder': isPlaceHolder, + 'hasOfficialRating': hasOfficialRating, + 'collapseBoxSetItems': collapseBoxSetItems, + 'minWidth': minWidth, + 'minHeight': minHeight, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'is3D': is3D, + 'seriesStatus': seriesStatus, + 'nameStartsWithOrGreater': nameStartsWithOrGreater, + 'nameStartsWith': nameStartsWith, + 'nameLessThan': nameLessThan, + 'studioIds': studioIds, + 'genreIds': genreIds, + 'enableTotalRecordCount': enableTotalRecordCount, + 'enableImages': enableImages, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _traktUsersUserGuidAuthorizePost( + {required String? userGuid}) { + final Uri $url = Uri.parse('/Trakt/Users/${userGuid}/Authorize'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _traktUsersUserGuidDeauthorizePost( + {required String? userGuid}) { + final Uri $url = Uri.parse('/Trakt/Users/${userGuid}/Deauthorize'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _traktUsersUserGuidItemsItemIdRatePost({ + required String? userGuid, + required String? itemId, + int? rating, + }) { + final Uri $url = Uri.parse('/Trakt/Users/${userGuid}/Items/${itemId}/Rate'); + final Map $params = {'rating': rating}; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _traktUsersUserGuidPollAuthorizationStatusGet( + {required String? userGuid}) { + final Uri $url = + Uri.parse('/Trakt/Users/${userGuid}/PollAuthorizationStatus'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future>> _traktUsersUserGuidRecommendedMoviesPost( + {required String? userGuid}) { + final Uri $url = Uri.parse('/Trakt/Users/${userGuid}/RecommendedMovies'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send, TraktMovie>($request); + } + + @override + Future>> _traktUsersUserGuidRecommendedShowsPost( + {required String? userGuid}) { + final Uri $url = Uri.parse('/Trakt/Users/${userGuid}/RecommendedShows'); + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + ); + return client.send, TraktShow>($request); + } + + @override + Future> _videosItemIdTrickplayWidthIndexJpgGet({ + required String? itemId, + required int? width, + required int? index, + String? mediaSourceId, + }) { + final Uri $url = + Uri.parse('/Videos/${itemId}/Trickplay/${width}/${index}.jpg'); + final Map $params = { + 'mediaSourceId': mediaSourceId + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _videosItemIdTrickplayWidthTilesM3u8Get({ + required String? itemId, + required int? width, + String? mediaSourceId, + }) { + final Uri $url = + Uri.parse('/Videos/${itemId}/Trickplay/${width}/tiles.m3u8'); + final Map $params = { + 'mediaSourceId': mediaSourceId + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _introSkipperSupportBundleGet() { + final Uri $url = Uri.parse('/IntroSkipper/SupportBundle'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _showsSeriesIdEpisodesGet({ + required String? seriesId, + String? userId, + List? fields, + int? season, + String? seasonId, + bool? isMissing, + String? adjacentTo, + String? startItemId, + int? startIndex, + int? limit, + bool? enableImages, + int? imageTypeLimit, + List? enableImageTypes, + bool? enableUserData, + String? sortBy, + }) { + final Uri $url = Uri.parse('/Shows/${seriesId}/Episodes'); + final Map $params = { + 'userId': userId, + 'fields': fields, + 'season': season, + 'seasonId': seasonId, + 'isMissing': isMissing, + 'adjacentTo': adjacentTo, + 'startItemId': startItemId, + 'startIndex': startIndex, + 'limit': limit, + 'enableImages': enableImages, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + 'enableUserData': enableUserData, + 'sortBy': sortBy, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _showsSeriesIdSeasonsGet({ + required String? seriesId, + String? userId, + List? fields, + bool? isSpecialSeason, + bool? isMissing, + String? adjacentTo, + bool? enableImages, + int? imageTypeLimit, + List? enableImageTypes, + bool? enableUserData, + }) { + final Uri $url = Uri.parse('/Shows/${seriesId}/Seasons'); + final Map $params = { + 'userId': userId, + 'fields': fields, + 'isSpecialSeason': isSpecialSeason, + 'isMissing': isMissing, + 'adjacentTo': adjacentTo, + 'enableImages': enableImages, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + 'enableUserData': enableUserData, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _showsNextUpGet({ + String? userId, + int? startIndex, + int? limit, + List? fields, + String? seriesId, + String? parentId, + bool? enableImages, + int? imageTypeLimit, + List? enableImageTypes, + bool? enableUserData, + DateTime? nextUpDateCutoff, + bool? enableTotalRecordCount, + bool? disableFirstEpisode, + bool? enableResumable, + bool? enableRewatching, + }) { + final Uri $url = Uri.parse('/Shows/NextUp'); + final Map $params = { + 'userId': userId, + 'startIndex': startIndex, + 'limit': limit, + 'fields': fields, + 'seriesId': seriesId, + 'parentId': parentId, + 'enableImages': enableImages, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + 'enableUserData': enableUserData, + 'nextUpDateCutoff': nextUpDateCutoff, + 'enableTotalRecordCount': enableTotalRecordCount, + 'disableFirstEpisode': disableFirstEpisode, + 'enableResumable': enableResumable, + 'enableRewatching': enableRewatching, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _showsUpcomingGet({ + String? userId, + int? startIndex, + int? limit, + List? fields, + String? parentId, + bool? enableImages, + int? imageTypeLimit, + List? enableImageTypes, + bool? enableUserData, + }) { + final Uri $url = Uri.parse('/Shows/Upcoming'); + final Map $params = { + 'userId': userId, + 'startIndex': startIndex, + 'limit': limit, + 'fields': fields, + 'parentId': parentId, + 'enableImages': enableImages, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + 'enableUserData': enableUserData, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _audioItemIdUniversalGet({ + required String? itemId, + List? container, + String? mediaSourceId, + String? deviceId, + String? userId, + String? audioCodec, + int? maxAudioChannels, + int? transcodingAudioChannels, + int? maxStreamingBitrate, + int? audioBitRate, + int? startTimeTicks, + String? transcodingContainer, + String? transcodingProtocol, + int? maxAudioSampleRate, + int? maxAudioBitDepth, + bool? enableRemoteMedia, + bool? breakOnNonKeyFrames, + bool? enableRedirection, + }) { + final Uri $url = Uri.parse('/Audio/${itemId}/universal'); + final Map $params = { + 'container': container, + 'mediaSourceId': mediaSourceId, + 'deviceId': deviceId, + 'userId': userId, + 'audioCodec': audioCodec, + 'maxAudioChannels': maxAudioChannels, + 'transcodingAudioChannels': transcodingAudioChannels, + 'maxStreamingBitrate': maxStreamingBitrate, + 'audioBitRate': audioBitRate, + 'startTimeTicks': startTimeTicks, + 'transcodingContainer': transcodingContainer, + 'transcodingProtocol': transcodingProtocol, + 'maxAudioSampleRate': maxAudioSampleRate, + 'maxAudioBitDepth': maxAudioBitDepth, + 'enableRemoteMedia': enableRemoteMedia, + 'breakOnNonKeyFrames': breakOnNonKeyFrames, + 'enableRedirection': enableRedirection, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _audioItemIdUniversalHead({ + required String? itemId, + List? container, + String? mediaSourceId, + String? deviceId, + String? userId, + String? audioCodec, + int? maxAudioChannels, + int? transcodingAudioChannels, + int? maxStreamingBitrate, + int? audioBitRate, + int? startTimeTicks, + String? transcodingContainer, + String? transcodingProtocol, + int? maxAudioSampleRate, + int? maxAudioBitDepth, + bool? enableRemoteMedia, + bool? breakOnNonKeyFrames, + bool? enableRedirection, + }) { + final Uri $url = Uri.parse('/Audio/${itemId}/universal'); + final Map $params = { + 'container': container, + 'mediaSourceId': mediaSourceId, + 'deviceId': deviceId, + 'userId': userId, + 'audioCodec': audioCodec, + 'maxAudioChannels': maxAudioChannels, + 'transcodingAudioChannels': transcodingAudioChannels, + 'maxStreamingBitrate': maxStreamingBitrate, + 'audioBitRate': audioBitRate, + 'startTimeTicks': startTimeTicks, + 'transcodingContainer': transcodingContainer, + 'transcodingProtocol': transcodingProtocol, + 'maxAudioSampleRate': maxAudioSampleRate, + 'maxAudioBitDepth': maxAudioBitDepth, + 'enableRemoteMedia': enableRemoteMedia, + 'breakOnNonKeyFrames': breakOnNonKeyFrames, + 'enableRedirection': enableRedirection, + }; + final Request $request = Request( + 'HEAD', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future>> _usersGet({ + bool? isHidden, + bool? isDisabled, + }) { + final Uri $url = Uri.parse('/Users'); + final Map $params = { + 'isHidden': isHidden, + 'isDisabled': isDisabled, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send, UserDto>($request); + } + + @override + Future> _usersPost({ + String? userId, + required UserDto? body, + }) { + final Uri $url = Uri.parse('/Users'); + final Map $params = {'userId': userId}; + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _usersUserIdGet({required String? userId}) { + final Uri $url = Uri.parse('/Users/${userId}'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _usersUserIdDelete({required String? userId}) { + final Uri $url = Uri.parse('/Users/${userId}'); + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _usersUserIdPolicyPost({ + required String? userId, + required UserPolicy? body, + }) { + final Uri $url = Uri.parse('/Users/${userId}/Policy'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _usersAuthenticateByNamePost( + {required AuthenticateUserByName? body}) { + final Uri $url = Uri.parse('/Users/AuthenticateByName'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _usersAuthenticateWithQuickConnectPost( + {required QuickConnectDto? body}) { + final Uri $url = Uri.parse('/Users/AuthenticateWithQuickConnect'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _usersConfigurationPost({ + String? userId, + required UserConfiguration? body, + }) { + final Uri $url = Uri.parse('/Users/Configuration'); + final Map $params = {'userId': userId}; + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _usersForgotPasswordPost( + {required ForgotPasswordDto? body}) { + final Uri $url = Uri.parse('/Users/ForgotPassword'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _usersForgotPasswordPinPost( + {required ForgotPasswordPinDto? body}) { + final Uri $url = Uri.parse('/Users/ForgotPassword/Pin'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _usersMeGet() { + final Uri $url = Uri.parse('/Users/Me'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _usersNewPost({required CreateUserByName? body}) { + final Uri $url = Uri.parse('/Users/New'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future> _usersPasswordPost({ + String? userId, + required UpdateUserPassword? body, + }) { + final Uri $url = Uri.parse('/Users/Password'); + final Map $params = {'userId': userId}; + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + parameters: $params, + ); + return client.send($request); + } + + @override + Future>> _usersPublicGet() { + final Uri $url = Uri.parse('/Users/Public'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send, UserDto>($request); + } + + @override + Future> _itemsItemIdIntrosGet({ + String? userId, + required String? itemId, + }) { + final Uri $url = Uri.parse('/Items/${itemId}/Intros'); + final Map $params = {'userId': userId}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future>> _itemsItemIdLocalTrailersGet({ + String? userId, + required String? itemId, + }) { + final Uri $url = Uri.parse('/Items/${itemId}/LocalTrailers'); + final Map $params = {'userId': userId}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send, BaseItemDto>($request); + } + + @override + Future>> _itemsItemIdSpecialFeaturesGet({ + String? userId, + required String? itemId, + }) { + final Uri $url = Uri.parse('/Items/${itemId}/SpecialFeatures'); + final Map $params = {'userId': userId}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send, BaseItemDto>($request); + } + + @override + Future>> _itemsLatestGet({ + String? userId, + String? parentId, + List? fields, + List? includeItemTypes, + bool? isPlayed, + bool? enableImages, + int? imageTypeLimit, + List? enableImageTypes, + bool? enableUserData, + int? limit, + bool? groupItems, + }) { + final Uri $url = Uri.parse('/Items/Latest'); + final Map $params = { + 'userId': userId, + 'parentId': parentId, + 'fields': fields, + 'includeItemTypes': includeItemTypes, + 'isPlayed': isPlayed, + 'enableImages': enableImages, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + 'enableUserData': enableUserData, + 'limit': limit, + 'groupItems': groupItems, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send, BaseItemDto>($request); + } + + @override + Future> _itemsRootGet({String? userId}) { + final Uri $url = Uri.parse('/Items/Root'); + final Map $params = {'userId': userId}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _userFavoriteItemsItemIdPost({ + String? userId, + required String? itemId, + }) { + final Uri $url = Uri.parse('/UserFavoriteItems/${itemId}'); + final Map $params = {'userId': userId}; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _userFavoriteItemsItemIdDelete({ + String? userId, + required String? itemId, + }) { + final Uri $url = Uri.parse('/UserFavoriteItems/${itemId}'); + final Map $params = {'userId': userId}; + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _userItemsItemIdRatingDelete({ + String? userId, + required String? itemId, + }) { + final Uri $url = Uri.parse('/UserItems/${itemId}/Rating'); + final Map $params = {'userId': userId}; + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _userItemsItemIdRatingPost({ + String? userId, + required String? itemId, + bool? likes, + }) { + final Uri $url = Uri.parse('/UserItems/${itemId}/Rating'); + final Map $params = { + 'userId': userId, + 'likes': likes, + }; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _userViewsGet({ + String? userId, + bool? includeExternalContent, + List? presetViews, + bool? includeHidden, + }) { + final Uri $url = Uri.parse('/UserViews'); + final Map $params = { + 'userId': userId, + 'includeExternalContent': includeExternalContent, + 'presetViews': presetViews, + 'includeHidden': includeHidden, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future>> _userViewsGroupingOptionsGet( + {String? userId}) { + final Uri $url = Uri.parse('/UserViews/GroupingOptions'); + final Map $params = {'userId': userId}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send, SpecialViewOptionDto>($request); + } + + @override + Future> _videosVideoIdMediaSourceIdAttachmentsIndexGet({ + required String? videoId, + required String? mediaSourceId, + required int? index, + }) { + final Uri $url = + Uri.parse('/Videos/${videoId}/${mediaSourceId}/Attachments/${index}'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _videosItemIdAdditionalPartsGet({ + required String? itemId, + String? userId, + }) { + final Uri $url = Uri.parse('/Videos/${itemId}/AdditionalParts'); + final Map $params = {'userId': userId}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _videosItemIdAlternateSourcesDelete( + {required String? itemId}) { + final Uri $url = Uri.parse('/Videos/${itemId}/AlternateSources'); + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _videosItemIdStreamGet({ + required String? itemId, + String? container, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? maxWidth, + int? maxHeight, + int? videoBitRate, + int? subtitleStreamIndex, + String? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + String? context, + Object? streamOptions, + }) { + final Uri $url = Uri.parse('/Videos/${itemId}/stream'); + final Map $params = { + 'container': container, + 'static': $static, + 'params': params, + 'tag': tag, + 'deviceProfileId': deviceProfileId, + 'playSessionId': playSessionId, + 'segmentContainer': segmentContainer, + 'segmentLength': segmentLength, + 'minSegments': minSegments, + 'mediaSourceId': mediaSourceId, + 'deviceId': deviceId, + 'audioCodec': audioCodec, + 'enableAutoStreamCopy': enableAutoStreamCopy, + 'allowVideoStreamCopy': allowVideoStreamCopy, + 'allowAudioStreamCopy': allowAudioStreamCopy, + 'breakOnNonKeyFrames': breakOnNonKeyFrames, + 'audioSampleRate': audioSampleRate, + 'maxAudioBitDepth': maxAudioBitDepth, + 'audioBitRate': audioBitRate, + 'audioChannels': audioChannels, + 'maxAudioChannels': maxAudioChannels, + 'profile': profile, + 'level': level, + 'framerate': framerate, + 'maxFramerate': maxFramerate, + 'copyTimestamps': copyTimestamps, + 'startTimeTicks': startTimeTicks, + 'width': width, + 'height': height, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'videoBitRate': videoBitRate, + 'subtitleStreamIndex': subtitleStreamIndex, + 'subtitleMethod': subtitleMethod, + 'maxRefFrames': maxRefFrames, + 'maxVideoBitDepth': maxVideoBitDepth, + 'requireAvc': requireAvc, + 'deInterlace': deInterlace, + 'requireNonAnamorphic': requireNonAnamorphic, + 'transcodingMaxAudioChannels': transcodingMaxAudioChannels, + 'cpuCoreLimit': cpuCoreLimit, + 'liveStreamId': liveStreamId, + 'enableMpegtsM2TsMode': enableMpegtsM2TsMode, + 'videoCodec': videoCodec, + 'subtitleCodec': subtitleCodec, + 'transcodeReasons': transcodeReasons, + 'audioStreamIndex': audioStreamIndex, + 'videoStreamIndex': videoStreamIndex, + 'context': context, + 'streamOptions': streamOptions, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _videosItemIdStreamHead({ + required String? itemId, + String? container, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? maxWidth, + int? maxHeight, + int? videoBitRate, + int? subtitleStreamIndex, + String? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + String? context, + Object? streamOptions, + }) { + final Uri $url = Uri.parse('/Videos/${itemId}/stream'); + final Map $params = { + 'container': container, + 'static': $static, + 'params': params, + 'tag': tag, + 'deviceProfileId': deviceProfileId, + 'playSessionId': playSessionId, + 'segmentContainer': segmentContainer, + 'segmentLength': segmentLength, + 'minSegments': minSegments, + 'mediaSourceId': mediaSourceId, + 'deviceId': deviceId, + 'audioCodec': audioCodec, + 'enableAutoStreamCopy': enableAutoStreamCopy, + 'allowVideoStreamCopy': allowVideoStreamCopy, + 'allowAudioStreamCopy': allowAudioStreamCopy, + 'breakOnNonKeyFrames': breakOnNonKeyFrames, + 'audioSampleRate': audioSampleRate, + 'maxAudioBitDepth': maxAudioBitDepth, + 'audioBitRate': audioBitRate, + 'audioChannels': audioChannels, + 'maxAudioChannels': maxAudioChannels, + 'profile': profile, + 'level': level, + 'framerate': framerate, + 'maxFramerate': maxFramerate, + 'copyTimestamps': copyTimestamps, + 'startTimeTicks': startTimeTicks, + 'width': width, + 'height': height, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'videoBitRate': videoBitRate, + 'subtitleStreamIndex': subtitleStreamIndex, + 'subtitleMethod': subtitleMethod, + 'maxRefFrames': maxRefFrames, + 'maxVideoBitDepth': maxVideoBitDepth, + 'requireAvc': requireAvc, + 'deInterlace': deInterlace, + 'requireNonAnamorphic': requireNonAnamorphic, + 'transcodingMaxAudioChannels': transcodingMaxAudioChannels, + 'cpuCoreLimit': cpuCoreLimit, + 'liveStreamId': liveStreamId, + 'enableMpegtsM2TsMode': enableMpegtsM2TsMode, + 'videoCodec': videoCodec, + 'subtitleCodec': subtitleCodec, + 'transcodeReasons': transcodeReasons, + 'audioStreamIndex': audioStreamIndex, + 'videoStreamIndex': videoStreamIndex, + 'context': context, + 'streamOptions': streamOptions, + }; + final Request $request = Request( + 'HEAD', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _videosItemIdStreamContainerGet({ + required String? itemId, + required String? container, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? maxWidth, + int? maxHeight, + int? videoBitRate, + int? subtitleStreamIndex, + String? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + String? context, + Object? streamOptions, + }) { + final Uri $url = Uri.parse('/Videos/${itemId}/stream.${container}'); + final Map $params = { + 'static': $static, + 'params': params, + 'tag': tag, + 'deviceProfileId': deviceProfileId, + 'playSessionId': playSessionId, + 'segmentContainer': segmentContainer, + 'segmentLength': segmentLength, + 'minSegments': minSegments, + 'mediaSourceId': mediaSourceId, + 'deviceId': deviceId, + 'audioCodec': audioCodec, + 'enableAutoStreamCopy': enableAutoStreamCopy, + 'allowVideoStreamCopy': allowVideoStreamCopy, + 'allowAudioStreamCopy': allowAudioStreamCopy, + 'breakOnNonKeyFrames': breakOnNonKeyFrames, + 'audioSampleRate': audioSampleRate, + 'maxAudioBitDepth': maxAudioBitDepth, + 'audioBitRate': audioBitRate, + 'audioChannels': audioChannels, + 'maxAudioChannels': maxAudioChannels, + 'profile': profile, + 'level': level, + 'framerate': framerate, + 'maxFramerate': maxFramerate, + 'copyTimestamps': copyTimestamps, + 'startTimeTicks': startTimeTicks, + 'width': width, + 'height': height, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'videoBitRate': videoBitRate, + 'subtitleStreamIndex': subtitleStreamIndex, + 'subtitleMethod': subtitleMethod, + 'maxRefFrames': maxRefFrames, + 'maxVideoBitDepth': maxVideoBitDepth, + 'requireAvc': requireAvc, + 'deInterlace': deInterlace, + 'requireNonAnamorphic': requireNonAnamorphic, + 'transcodingMaxAudioChannels': transcodingMaxAudioChannels, + 'cpuCoreLimit': cpuCoreLimit, + 'liveStreamId': liveStreamId, + 'enableMpegtsM2TsMode': enableMpegtsM2TsMode, + 'videoCodec': videoCodec, + 'subtitleCodec': subtitleCodec, + 'transcodeReasons': transcodeReasons, + 'audioStreamIndex': audioStreamIndex, + 'videoStreamIndex': videoStreamIndex, + 'context': context, + 'streamOptions': streamOptions, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _videosItemIdStreamContainerHead({ + required String? itemId, + required String? container, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? maxWidth, + int? maxHeight, + int? videoBitRate, + int? subtitleStreamIndex, + String? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + String? context, + Object? streamOptions, + }) { + final Uri $url = Uri.parse('/Videos/${itemId}/stream.${container}'); + final Map $params = { + 'static': $static, + 'params': params, + 'tag': tag, + 'deviceProfileId': deviceProfileId, + 'playSessionId': playSessionId, + 'segmentContainer': segmentContainer, + 'segmentLength': segmentLength, + 'minSegments': minSegments, + 'mediaSourceId': mediaSourceId, + 'deviceId': deviceId, + 'audioCodec': audioCodec, + 'enableAutoStreamCopy': enableAutoStreamCopy, + 'allowVideoStreamCopy': allowVideoStreamCopy, + 'allowAudioStreamCopy': allowAudioStreamCopy, + 'breakOnNonKeyFrames': breakOnNonKeyFrames, + 'audioSampleRate': audioSampleRate, + 'maxAudioBitDepth': maxAudioBitDepth, + 'audioBitRate': audioBitRate, + 'audioChannels': audioChannels, + 'maxAudioChannels': maxAudioChannels, + 'profile': profile, + 'level': level, + 'framerate': framerate, + 'maxFramerate': maxFramerate, + 'copyTimestamps': copyTimestamps, + 'startTimeTicks': startTimeTicks, + 'width': width, + 'height': height, + 'maxWidth': maxWidth, + 'maxHeight': maxHeight, + 'videoBitRate': videoBitRate, + 'subtitleStreamIndex': subtitleStreamIndex, + 'subtitleMethod': subtitleMethod, + 'maxRefFrames': maxRefFrames, + 'maxVideoBitDepth': maxVideoBitDepth, + 'requireAvc': requireAvc, + 'deInterlace': deInterlace, + 'requireNonAnamorphic': requireNonAnamorphic, + 'transcodingMaxAudioChannels': transcodingMaxAudioChannels, + 'cpuCoreLimit': cpuCoreLimit, + 'liveStreamId': liveStreamId, + 'enableMpegtsM2TsMode': enableMpegtsM2TsMode, + 'videoCodec': videoCodec, + 'subtitleCodec': subtitleCodec, + 'transcodeReasons': transcodeReasons, + 'audioStreamIndex': audioStreamIndex, + 'videoStreamIndex': videoStreamIndex, + 'context': context, + 'streamOptions': streamOptions, + }; + final Request $request = Request( + 'HEAD', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _videosMergeVersionsPost( + {required List? ids}) { + final Uri $url = Uri.parse('/Videos/MergeVersions'); + final Map $params = {'ids': ids}; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future>> _introsEpisodeIdChromaprintGet( + {required String? id}) { + final Uri $url = Uri.parse('/Intros/Episode/{Id}/Chromaprint'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send, int>($request); + } + + @override + Future> _introsEpisodeIdUpdateIntroTimestampsPost({ + required String? id, + required Intro? body, + }) { + final Uri $url = Uri.parse('/Intros/Episode/{Id}/UpdateIntroTimestamps'); + final $body = body; + final Request $request = Request( + 'POST', + $url, + client.baseUrl, + body: $body, + ); + return client.send($request); + } + + @override + Future>> _introsShowSeriesSeasonGet({ + required String? series, + required String? season, + }) { + final Uri $url = Uri.parse('/Intros/Show/{Series}/{Season}'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client + .send, EpisodeVisualization>($request); + } + + @override + Future> _introsShowSeriesSeasonDelete({ + required String? series, + required String? season, + bool? eraseCache, + }) { + final Uri $url = Uri.parse('/Intros/Show/{Series}/{Season}'); + final Map $params = { + 'eraseCache': eraseCache + }; + final Request $request = Request( + 'DELETE', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } + + @override + Future> _introsShowsGet() { + final Uri $url = Uri.parse('/Intros/Shows'); + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + ); + return client.send($request); + } + + @override + Future> _yearsGet({ + int? startIndex, + int? limit, + List? sortOrder, + String? parentId, + List? fields, + List? excludeItemTypes, + List? includeItemTypes, + List? mediaTypes, + List? sortBy, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + String? userId, + bool? recursive, + bool? enableImages, + }) { + final Uri $url = Uri.parse('/Years'); + final Map $params = { + 'startIndex': startIndex, + 'limit': limit, + 'sortOrder': sortOrder, + 'parentId': parentId, + 'fields': fields, + 'excludeItemTypes': excludeItemTypes, + 'includeItemTypes': includeItemTypes, + 'mediaTypes': mediaTypes, + 'sortBy': sortBy, + 'enableUserData': enableUserData, + 'imageTypeLimit': imageTypeLimit, + 'enableImageTypes': enableImageTypes, + 'userId': userId, + 'recursive': recursive, + 'enableImages': enableImages, + }; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client + .send($request); + } + + @override + Future> _yearsYearGet({ + required int? year, + String? userId, + }) { + final Uri $url = Uri.parse('/Years/${year}'); + final Map $params = {'userId': userId}; + final Request $request = Request( + 'GET', + $url, + client.baseUrl, + parameters: $params, + ); + return client.send($request); + } +} diff --git a/lib/jellyfin/jellyfin_open_api.swagger.dart b/lib/jellyfin/jellyfin_open_api.swagger.dart new file mode 100644 index 0000000..c2396f5 --- /dev/null +++ b/lib/jellyfin/jellyfin_open_api.swagger.dart @@ -0,0 +1,65767 @@ +// ignore_for_file: type=lint + +import 'package:json_annotation/json_annotation.dart'; +import 'package:collection/collection.dart'; +import 'dart:convert'; + +import 'package:chopper/chopper.dart'; + +import 'client_mapping.dart'; +import 'dart:async'; +import 'package:http/http.dart' as http; +import 'package:http/http.dart' show MultipartFile; +import 'package:chopper/chopper.dart' as chopper; +import 'jellyfin_open_api.enums.swagger.dart' as enums; +export 'jellyfin_open_api.enums.swagger.dart'; + +part 'jellyfin_open_api.swagger.chopper.dart'; +part 'jellyfin_open_api.swagger.g.dart'; + +// ************************************************************************** +// SwaggerChopperGenerator +// ************************************************************************** + +@ChopperApi() +abstract class JellyfinOpenApi extends ChopperService { + static JellyfinOpenApi create({ + ChopperClient? client, + http.Client? httpClient, + Authenticator? authenticator, + ErrorConverter? errorConverter, + Converter? converter, + Uri? baseUrl, + Iterable? interceptors, + }) { + if (client != null) { + return _$JellyfinOpenApi(client); + } + + final newClient = ChopperClient( + services: [_$JellyfinOpenApi()], + converter: converter ?? $JsonSerializableConverter(), + interceptors: interceptors ?? [], + client: httpClient, + authenticator: authenticator, + errorConverter: errorConverter, + baseUrl: baseUrl); + return _$JellyfinOpenApi(newClient); + } + + ///Gets activity log entries. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param minDate Optional. The minimum date. Format = ISO. + ///@param hasUserId Optional. Filter log entries if it has user id, or not. + Future> + systemActivityLogEntriesGet({ + int? startIndex, + int? limit, + DateTime? minDate, + bool? hasUserId, + }) { + generatedMapping.putIfAbsent(ActivityLogEntryQueryResult, + () => ActivityLogEntryQueryResult.fromJsonFactory); + + return _systemActivityLogEntriesGet( + startIndex: startIndex, + limit: limit, + minDate: minDate, + hasUserId: hasUserId); + } + + ///Gets activity log entries. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param minDate Optional. The minimum date. Format = ISO. + ///@param hasUserId Optional. Filter log entries if it has user id, or not. + @Get(path: '/System/ActivityLog/Entries') + Future> + _systemActivityLogEntriesGet({ + @Query('startIndex') int? startIndex, + @Query('limit') int? limit, + @Query('minDate') DateTime? minDate, + @Query('hasUserId') bool? hasUserId, + }); + + ///Get all keys. + Future> authKeysGet() { + generatedMapping.putIfAbsent(AuthenticationInfoQueryResult, + () => AuthenticationInfoQueryResult.fromJsonFactory); + + return _authKeysGet(); + } + + ///Get all keys. + @Get(path: '/Auth/Keys') + Future> _authKeysGet(); + + ///Create a new api key. + ///@param app Name of the app using the authentication key. + Future authKeysPost({required String? app}) { + return _authKeysPost(app: app); + } + + ///Create a new api key. + ///@param app Name of the app using the authentication key. + @Post( + path: '/Auth/Keys', + optionalBody: true, + ) + Future _authKeysPost({@Query('app') required String? app}); + + ///Remove an api key. + ///@param key The access token to delete. + Future authKeysKeyDelete({required String? key}) { + return _authKeysKeyDelete(key: key); + } + + ///Remove an api key. + ///@param key The access token to delete. + @Delete(path: '/Auth/Keys/{key}') + Future _authKeysKeyDelete( + {@Path('key') required String? key}); + + ///Gets all artists from a given item, folder, or the entire library. + ///@param minCommunityRating Optional filter by minimum community rating. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param searchTerm Optional. Search term. + ///@param parentId Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param excludeItemTypes Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited. + ///@param includeItemTypes Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited. + ///@param filters Optional. Specify additional filters to apply. + ///@param isFavorite Optional filter by items that are marked as favorite, or not. + ///@param mediaTypes Optional filter by MediaType. Allows multiple, comma delimited. + ///@param genres Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimited. + ///@param genreIds Optional. If specified, results will be filtered based on genre id. This allows multiple, pipe delimited. + ///@param officialRatings Optional. If specified, results will be filtered based on OfficialRating. This allows multiple, pipe delimited. + ///@param tags Optional. If specified, results will be filtered based on tag. This allows multiple, pipe delimited. + ///@param years Optional. If specified, results will be filtered based on production year. This allows multiple, comma delimited. + ///@param enableUserData Optional, include user data. + ///@param imageTypeLimit Optional, the max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param person Optional. If specified, results will be filtered to include only those containing the specified person. + ///@param personIds Optional. If specified, results will be filtered to include only those containing the specified person ids. + ///@param personTypes Optional. If specified, along with Person, results will be filtered to include only those containing the specified person and PersonType. Allows multiple, comma-delimited. + ///@param studios Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimited. + ///@param studioIds Optional. If specified, results will be filtered based on studio id. This allows multiple, pipe delimited. + ///@param userId User id. + ///@param nameStartsWithOrGreater Optional filter by items whose name is sorted equally or greater than a given input string. + ///@param nameStartsWith Optional filter by items whose name is sorted equally than a given input string. + ///@param nameLessThan Optional filter by items whose name is equally or lesser than a given input string. + ///@param sortBy Optional. Specify one or more sort orders, comma delimited. + ///@param sortOrder Sort Order - Ascending,Descending. + ///@param enableImages Optional, include image information in output. + ///@param enableTotalRecordCount Total record count. + Future> artistsGet({ + num? minCommunityRating, + int? startIndex, + int? limit, + String? searchTerm, + String? parentId, + List? fields, + List? excludeItemTypes, + List? includeItemTypes, + List? filters, + bool? isFavorite, + List? mediaTypes, + List? genres, + List? genreIds, + List? officialRatings, + List? tags, + List? years, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + String? person, + List? personIds, + List? personTypes, + List? studios, + List? studioIds, + String? userId, + String? nameStartsWithOrGreater, + String? nameStartsWith, + String? nameLessThan, + List? sortBy, + List? sortOrder, + bool? enableImages, + bool? enableTotalRecordCount, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _artistsGet( + minCommunityRating: minCommunityRating, + startIndex: startIndex, + limit: limit, + searchTerm: searchTerm, + parentId: parentId, + fields: itemFieldsListToJson(fields), + excludeItemTypes: baseItemKindListToJson(excludeItemTypes), + includeItemTypes: baseItemKindListToJson(includeItemTypes), + filters: itemFilterListToJson(filters), + isFavorite: isFavorite, + mediaTypes: mediaTypeListToJson(mediaTypes), + genres: genres, + genreIds: genreIds, + officialRatings: officialRatings, + tags: tags, + years: years, + enableUserData: enableUserData, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes), + person: person, + personIds: personIds, + personTypes: personTypes, + studios: studios, + studioIds: studioIds, + userId: userId, + nameStartsWithOrGreater: nameStartsWithOrGreater, + nameStartsWith: nameStartsWith, + nameLessThan: nameLessThan, + sortBy: itemSortByListToJson(sortBy), + sortOrder: sortOrderListToJson(sortOrder), + enableImages: enableImages, + enableTotalRecordCount: enableTotalRecordCount); + } + + ///Gets all artists from a given item, folder, or the entire library. + ///@param minCommunityRating Optional filter by minimum community rating. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param searchTerm Optional. Search term. + ///@param parentId Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param excludeItemTypes Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited. + ///@param includeItemTypes Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited. + ///@param filters Optional. Specify additional filters to apply. + ///@param isFavorite Optional filter by items that are marked as favorite, or not. + ///@param mediaTypes Optional filter by MediaType. Allows multiple, comma delimited. + ///@param genres Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimited. + ///@param genreIds Optional. If specified, results will be filtered based on genre id. This allows multiple, pipe delimited. + ///@param officialRatings Optional. If specified, results will be filtered based on OfficialRating. This allows multiple, pipe delimited. + ///@param tags Optional. If specified, results will be filtered based on tag. This allows multiple, pipe delimited. + ///@param years Optional. If specified, results will be filtered based on production year. This allows multiple, comma delimited. + ///@param enableUserData Optional, include user data. + ///@param imageTypeLimit Optional, the max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param person Optional. If specified, results will be filtered to include only those containing the specified person. + ///@param personIds Optional. If specified, results will be filtered to include only those containing the specified person ids. + ///@param personTypes Optional. If specified, along with Person, results will be filtered to include only those containing the specified person and PersonType. Allows multiple, comma-delimited. + ///@param studios Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimited. + ///@param studioIds Optional. If specified, results will be filtered based on studio id. This allows multiple, pipe delimited. + ///@param userId User id. + ///@param nameStartsWithOrGreater Optional filter by items whose name is sorted equally or greater than a given input string. + ///@param nameStartsWith Optional filter by items whose name is sorted equally than a given input string. + ///@param nameLessThan Optional filter by items whose name is equally or lesser than a given input string. + ///@param sortBy Optional. Specify one or more sort orders, comma delimited. + ///@param sortOrder Sort Order - Ascending,Descending. + ///@param enableImages Optional, include image information in output. + ///@param enableTotalRecordCount Total record count. + @Get(path: '/Artists') + Future> _artistsGet({ + @Query('minCommunityRating') num? minCommunityRating, + @Query('startIndex') int? startIndex, + @Query('limit') int? limit, + @Query('searchTerm') String? searchTerm, + @Query('parentId') String? parentId, + @Query('fields') List? fields, + @Query('excludeItemTypes') List? excludeItemTypes, + @Query('includeItemTypes') List? includeItemTypes, + @Query('filters') List? filters, + @Query('isFavorite') bool? isFavorite, + @Query('mediaTypes') List? mediaTypes, + @Query('genres') List? genres, + @Query('genreIds') List? genreIds, + @Query('officialRatings') List? officialRatings, + @Query('tags') List? tags, + @Query('years') List? years, + @Query('enableUserData') bool? enableUserData, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + @Query('person') String? person, + @Query('personIds') List? personIds, + @Query('personTypes') List? personTypes, + @Query('studios') List? studios, + @Query('studioIds') List? studioIds, + @Query('userId') String? userId, + @Query('nameStartsWithOrGreater') String? nameStartsWithOrGreater, + @Query('nameStartsWith') String? nameStartsWith, + @Query('nameLessThan') String? nameLessThan, + @Query('sortBy') List? sortBy, + @Query('sortOrder') List? sortOrder, + @Query('enableImages') bool? enableImages, + @Query('enableTotalRecordCount') bool? enableTotalRecordCount, + }); + + ///Gets an artist by name. + ///@param name Studio name. + ///@param userId Optional. Filter by user id, and attach user data. + Future> artistsNameGet({ + required String? name, + String? userId, + }) { + generatedMapping.putIfAbsent( + BaseItemDto, () => BaseItemDto.fromJsonFactory); + + return _artistsNameGet(name: name, userId: userId); + } + + ///Gets an artist by name. + ///@param name Studio name. + ///@param userId Optional. Filter by user id, and attach user data. + @Get(path: '/Artists/{name}') + Future> _artistsNameGet({ + @Path('name') required String? name, + @Query('userId') String? userId, + }); + + ///Gets all album artists from a given item, folder, or the entire library. + ///@param minCommunityRating Optional filter by minimum community rating. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param searchTerm Optional. Search term. + ///@param parentId Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param excludeItemTypes Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited. + ///@param includeItemTypes Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited. + ///@param filters Optional. Specify additional filters to apply. + ///@param isFavorite Optional filter by items that are marked as favorite, or not. + ///@param mediaTypes Optional filter by MediaType. Allows multiple, comma delimited. + ///@param genres Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimited. + ///@param genreIds Optional. If specified, results will be filtered based on genre id. This allows multiple, pipe delimited. + ///@param officialRatings Optional. If specified, results will be filtered based on OfficialRating. This allows multiple, pipe delimited. + ///@param tags Optional. If specified, results will be filtered based on tag. This allows multiple, pipe delimited. + ///@param years Optional. If specified, results will be filtered based on production year. This allows multiple, comma delimited. + ///@param enableUserData Optional, include user data. + ///@param imageTypeLimit Optional, the max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param person Optional. If specified, results will be filtered to include only those containing the specified person. + ///@param personIds Optional. If specified, results will be filtered to include only those containing the specified person ids. + ///@param personTypes Optional. If specified, along with Person, results will be filtered to include only those containing the specified person and PersonType. Allows multiple, comma-delimited. + ///@param studios Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimited. + ///@param studioIds Optional. If specified, results will be filtered based on studio id. This allows multiple, pipe delimited. + ///@param userId User id. + ///@param nameStartsWithOrGreater Optional filter by items whose name is sorted equally or greater than a given input string. + ///@param nameStartsWith Optional filter by items whose name is sorted equally than a given input string. + ///@param nameLessThan Optional filter by items whose name is equally or lesser than a given input string. + ///@param sortBy Optional. Specify one or more sort orders, comma delimited. + ///@param sortOrder Sort Order - Ascending,Descending. + ///@param enableImages Optional, include image information in output. + ///@param enableTotalRecordCount Total record count. + Future> artistsAlbumArtistsGet({ + num? minCommunityRating, + int? startIndex, + int? limit, + String? searchTerm, + String? parentId, + List? fields, + List? excludeItemTypes, + List? includeItemTypes, + List? filters, + bool? isFavorite, + List? mediaTypes, + List? genres, + List? genreIds, + List? officialRatings, + List? tags, + List? years, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + String? person, + List? personIds, + List? personTypes, + List? studios, + List? studioIds, + String? userId, + String? nameStartsWithOrGreater, + String? nameStartsWith, + String? nameLessThan, + List? sortBy, + List? sortOrder, + bool? enableImages, + bool? enableTotalRecordCount, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _artistsAlbumArtistsGet( + minCommunityRating: minCommunityRating, + startIndex: startIndex, + limit: limit, + searchTerm: searchTerm, + parentId: parentId, + fields: itemFieldsListToJson(fields), + excludeItemTypes: baseItemKindListToJson(excludeItemTypes), + includeItemTypes: baseItemKindListToJson(includeItemTypes), + filters: itemFilterListToJson(filters), + isFavorite: isFavorite, + mediaTypes: mediaTypeListToJson(mediaTypes), + genres: genres, + genreIds: genreIds, + officialRatings: officialRatings, + tags: tags, + years: years, + enableUserData: enableUserData, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes), + person: person, + personIds: personIds, + personTypes: personTypes, + studios: studios, + studioIds: studioIds, + userId: userId, + nameStartsWithOrGreater: nameStartsWithOrGreater, + nameStartsWith: nameStartsWith, + nameLessThan: nameLessThan, + sortBy: itemSortByListToJson(sortBy), + sortOrder: sortOrderListToJson(sortOrder), + enableImages: enableImages, + enableTotalRecordCount: enableTotalRecordCount); + } + + ///Gets all album artists from a given item, folder, or the entire library. + ///@param minCommunityRating Optional filter by minimum community rating. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param searchTerm Optional. Search term. + ///@param parentId Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param excludeItemTypes Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited. + ///@param includeItemTypes Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited. + ///@param filters Optional. Specify additional filters to apply. + ///@param isFavorite Optional filter by items that are marked as favorite, or not. + ///@param mediaTypes Optional filter by MediaType. Allows multiple, comma delimited. + ///@param genres Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimited. + ///@param genreIds Optional. If specified, results will be filtered based on genre id. This allows multiple, pipe delimited. + ///@param officialRatings Optional. If specified, results will be filtered based on OfficialRating. This allows multiple, pipe delimited. + ///@param tags Optional. If specified, results will be filtered based on tag. This allows multiple, pipe delimited. + ///@param years Optional. If specified, results will be filtered based on production year. This allows multiple, comma delimited. + ///@param enableUserData Optional, include user data. + ///@param imageTypeLimit Optional, the max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param person Optional. If specified, results will be filtered to include only those containing the specified person. + ///@param personIds Optional. If specified, results will be filtered to include only those containing the specified person ids. + ///@param personTypes Optional. If specified, along with Person, results will be filtered to include only those containing the specified person and PersonType. Allows multiple, comma-delimited. + ///@param studios Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimited. + ///@param studioIds Optional. If specified, results will be filtered based on studio id. This allows multiple, pipe delimited. + ///@param userId User id. + ///@param nameStartsWithOrGreater Optional filter by items whose name is sorted equally or greater than a given input string. + ///@param nameStartsWith Optional filter by items whose name is sorted equally than a given input string. + ///@param nameLessThan Optional filter by items whose name is equally or lesser than a given input string. + ///@param sortBy Optional. Specify one or more sort orders, comma delimited. + ///@param sortOrder Sort Order - Ascending,Descending. + ///@param enableImages Optional, include image information in output. + ///@param enableTotalRecordCount Total record count. + @Get(path: '/Artists/AlbumArtists') + Future> _artistsAlbumArtistsGet({ + @Query('minCommunityRating') num? minCommunityRating, + @Query('startIndex') int? startIndex, + @Query('limit') int? limit, + @Query('searchTerm') String? searchTerm, + @Query('parentId') String? parentId, + @Query('fields') List? fields, + @Query('excludeItemTypes') List? excludeItemTypes, + @Query('includeItemTypes') List? includeItemTypes, + @Query('filters') List? filters, + @Query('isFavorite') bool? isFavorite, + @Query('mediaTypes') List? mediaTypes, + @Query('genres') List? genres, + @Query('genreIds') List? genreIds, + @Query('officialRatings') List? officialRatings, + @Query('tags') List? tags, + @Query('years') List? years, + @Query('enableUserData') bool? enableUserData, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + @Query('person') String? person, + @Query('personIds') List? personIds, + @Query('personTypes') List? personTypes, + @Query('studios') List? studios, + @Query('studioIds') List? studioIds, + @Query('userId') String? userId, + @Query('nameStartsWithOrGreater') String? nameStartsWithOrGreater, + @Query('nameStartsWith') String? nameStartsWith, + @Query('nameLessThan') String? nameLessThan, + @Query('sortBy') List? sortBy, + @Query('sortOrder') List? sortOrder, + @Query('enableImages') bool? enableImages, + @Query('enableTotalRecordCount') bool? enableTotalRecordCount, + }); + + ///Gets an audio stream. + ///@param itemId The item id. + ///@param container The audio container. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + Future> audioItemIdStreamGet({ + required String? itemId, + String? container, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? videoBitRate, + int? subtitleStreamIndex, + enums.AudioItemIdStreamGetSubtitleMethod? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + enums.AudioItemIdStreamGetContext? context, + Object? streamOptions, + }) { + return _audioItemIdStreamGet( + itemId: itemId, + container: container, + $static: $static, + params: params, + tag: tag, + deviceProfileId: deviceProfileId, + playSessionId: playSessionId, + segmentContainer: segmentContainer, + segmentLength: segmentLength, + minSegments: minSegments, + mediaSourceId: mediaSourceId, + deviceId: deviceId, + audioCodec: audioCodec, + enableAutoStreamCopy: enableAutoStreamCopy, + allowVideoStreamCopy: allowVideoStreamCopy, + allowAudioStreamCopy: allowAudioStreamCopy, + breakOnNonKeyFrames: breakOnNonKeyFrames, + audioSampleRate: audioSampleRate, + maxAudioBitDepth: maxAudioBitDepth, + audioBitRate: audioBitRate, + audioChannels: audioChannels, + maxAudioChannels: maxAudioChannels, + profile: profile, + level: level, + framerate: framerate, + maxFramerate: maxFramerate, + copyTimestamps: copyTimestamps, + startTimeTicks: startTimeTicks, + width: width, + height: height, + videoBitRate: videoBitRate, + subtitleStreamIndex: subtitleStreamIndex, + subtitleMethod: subtitleMethod?.value?.toString(), + maxRefFrames: maxRefFrames, + maxVideoBitDepth: maxVideoBitDepth, + requireAvc: requireAvc, + deInterlace: deInterlace, + requireNonAnamorphic: requireNonAnamorphic, + transcodingMaxAudioChannels: transcodingMaxAudioChannels, + cpuCoreLimit: cpuCoreLimit, + liveStreamId: liveStreamId, + enableMpegtsM2TsMode: enableMpegtsM2TsMode, + videoCodec: videoCodec, + subtitleCodec: subtitleCodec, + transcodeReasons: transcodeReasons, + audioStreamIndex: audioStreamIndex, + videoStreamIndex: videoStreamIndex, + context: context?.value?.toString(), + streamOptions: streamOptions); + } + + ///Gets an audio stream. + ///@param itemId The item id. + ///@param container The audio container. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + @Get(path: '/Audio/{itemId}/stream') + Future> _audioItemIdStreamGet({ + @Path('itemId') required String? itemId, + @Query('container') String? container, + @Query('static') bool? $static, + @Query('params') String? params, + @Query('tag') String? tag, + @Query('deviceProfileId') String? deviceProfileId, + @Query('playSessionId') String? playSessionId, + @Query('segmentContainer') String? segmentContainer, + @Query('segmentLength') int? segmentLength, + @Query('minSegments') int? minSegments, + @Query('mediaSourceId') String? mediaSourceId, + @Query('deviceId') String? deviceId, + @Query('audioCodec') String? audioCodec, + @Query('enableAutoStreamCopy') bool? enableAutoStreamCopy, + @Query('allowVideoStreamCopy') bool? allowVideoStreamCopy, + @Query('allowAudioStreamCopy') bool? allowAudioStreamCopy, + @Query('breakOnNonKeyFrames') bool? breakOnNonKeyFrames, + @Query('audioSampleRate') int? audioSampleRate, + @Query('maxAudioBitDepth') int? maxAudioBitDepth, + @Query('audioBitRate') int? audioBitRate, + @Query('audioChannels') int? audioChannels, + @Query('maxAudioChannels') int? maxAudioChannels, + @Query('profile') String? profile, + @Query('level') String? level, + @Query('framerate') num? framerate, + @Query('maxFramerate') num? maxFramerate, + @Query('copyTimestamps') bool? copyTimestamps, + @Query('startTimeTicks') int? startTimeTicks, + @Query('width') int? width, + @Query('height') int? height, + @Query('videoBitRate') int? videoBitRate, + @Query('subtitleStreamIndex') int? subtitleStreamIndex, + @Query('subtitleMethod') String? subtitleMethod, + @Query('maxRefFrames') int? maxRefFrames, + @Query('maxVideoBitDepth') int? maxVideoBitDepth, + @Query('requireAvc') bool? requireAvc, + @Query('deInterlace') bool? deInterlace, + @Query('requireNonAnamorphic') bool? requireNonAnamorphic, + @Query('transcodingMaxAudioChannels') int? transcodingMaxAudioChannels, + @Query('cpuCoreLimit') int? cpuCoreLimit, + @Query('liveStreamId') String? liveStreamId, + @Query('enableMpegtsM2TsMode') bool? enableMpegtsM2TsMode, + @Query('videoCodec') String? videoCodec, + @Query('subtitleCodec') String? subtitleCodec, + @Query('transcodeReasons') String? transcodeReasons, + @Query('audioStreamIndex') int? audioStreamIndex, + @Query('videoStreamIndex') int? videoStreamIndex, + @Query('context') String? context, + @Query('streamOptions') Object? streamOptions, + }); + + ///Gets an audio stream. + ///@param itemId The item id. + ///@param container The audio container. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + Future> audioItemIdStreamHead({ + required String? itemId, + String? container, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? videoBitRate, + int? subtitleStreamIndex, + enums.AudioItemIdStreamHeadSubtitleMethod? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + enums.AudioItemIdStreamHeadContext? context, + Object? streamOptions, + }) { + return _audioItemIdStreamHead( + itemId: itemId, + container: container, + $static: $static, + params: params, + tag: tag, + deviceProfileId: deviceProfileId, + playSessionId: playSessionId, + segmentContainer: segmentContainer, + segmentLength: segmentLength, + minSegments: minSegments, + mediaSourceId: mediaSourceId, + deviceId: deviceId, + audioCodec: audioCodec, + enableAutoStreamCopy: enableAutoStreamCopy, + allowVideoStreamCopy: allowVideoStreamCopy, + allowAudioStreamCopy: allowAudioStreamCopy, + breakOnNonKeyFrames: breakOnNonKeyFrames, + audioSampleRate: audioSampleRate, + maxAudioBitDepth: maxAudioBitDepth, + audioBitRate: audioBitRate, + audioChannels: audioChannels, + maxAudioChannels: maxAudioChannels, + profile: profile, + level: level, + framerate: framerate, + maxFramerate: maxFramerate, + copyTimestamps: copyTimestamps, + startTimeTicks: startTimeTicks, + width: width, + height: height, + videoBitRate: videoBitRate, + subtitleStreamIndex: subtitleStreamIndex, + subtitleMethod: subtitleMethod?.value?.toString(), + maxRefFrames: maxRefFrames, + maxVideoBitDepth: maxVideoBitDepth, + requireAvc: requireAvc, + deInterlace: deInterlace, + requireNonAnamorphic: requireNonAnamorphic, + transcodingMaxAudioChannels: transcodingMaxAudioChannels, + cpuCoreLimit: cpuCoreLimit, + liveStreamId: liveStreamId, + enableMpegtsM2TsMode: enableMpegtsM2TsMode, + videoCodec: videoCodec, + subtitleCodec: subtitleCodec, + transcodeReasons: transcodeReasons, + audioStreamIndex: audioStreamIndex, + videoStreamIndex: videoStreamIndex, + context: context?.value?.toString(), + streamOptions: streamOptions); + } + + ///Gets an audio stream. + ///@param itemId The item id. + ///@param container The audio container. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + @Head(path: '/Audio/{itemId}/stream') + Future> _audioItemIdStreamHead({ + @Path('itemId') required String? itemId, + @Query('container') String? container, + @Query('static') bool? $static, + @Query('params') String? params, + @Query('tag') String? tag, + @Query('deviceProfileId') String? deviceProfileId, + @Query('playSessionId') String? playSessionId, + @Query('segmentContainer') String? segmentContainer, + @Query('segmentLength') int? segmentLength, + @Query('minSegments') int? minSegments, + @Query('mediaSourceId') String? mediaSourceId, + @Query('deviceId') String? deviceId, + @Query('audioCodec') String? audioCodec, + @Query('enableAutoStreamCopy') bool? enableAutoStreamCopy, + @Query('allowVideoStreamCopy') bool? allowVideoStreamCopy, + @Query('allowAudioStreamCopy') bool? allowAudioStreamCopy, + @Query('breakOnNonKeyFrames') bool? breakOnNonKeyFrames, + @Query('audioSampleRate') int? audioSampleRate, + @Query('maxAudioBitDepth') int? maxAudioBitDepth, + @Query('audioBitRate') int? audioBitRate, + @Query('audioChannels') int? audioChannels, + @Query('maxAudioChannels') int? maxAudioChannels, + @Query('profile') String? profile, + @Query('level') String? level, + @Query('framerate') num? framerate, + @Query('maxFramerate') num? maxFramerate, + @Query('copyTimestamps') bool? copyTimestamps, + @Query('startTimeTicks') int? startTimeTicks, + @Query('width') int? width, + @Query('height') int? height, + @Query('videoBitRate') int? videoBitRate, + @Query('subtitleStreamIndex') int? subtitleStreamIndex, + @Query('subtitleMethod') String? subtitleMethod, + @Query('maxRefFrames') int? maxRefFrames, + @Query('maxVideoBitDepth') int? maxVideoBitDepth, + @Query('requireAvc') bool? requireAvc, + @Query('deInterlace') bool? deInterlace, + @Query('requireNonAnamorphic') bool? requireNonAnamorphic, + @Query('transcodingMaxAudioChannels') int? transcodingMaxAudioChannels, + @Query('cpuCoreLimit') int? cpuCoreLimit, + @Query('liveStreamId') String? liveStreamId, + @Query('enableMpegtsM2TsMode') bool? enableMpegtsM2TsMode, + @Query('videoCodec') String? videoCodec, + @Query('subtitleCodec') String? subtitleCodec, + @Query('transcodeReasons') String? transcodeReasons, + @Query('audioStreamIndex') int? audioStreamIndex, + @Query('videoStreamIndex') int? videoStreamIndex, + @Query('context') String? context, + @Query('streamOptions') Object? streamOptions, + }); + + ///Gets an audio stream. + ///@param itemId The item id. + ///@param container The audio container. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamporphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + Future> audioItemIdStreamContainerGet({ + required String? itemId, + required String? container, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? videoBitRate, + int? subtitleStreamIndex, + enums.AudioItemIdStreamContainerGetSubtitleMethod? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + enums.AudioItemIdStreamContainerGetContext? context, + Object? streamOptions, + }) { + return _audioItemIdStreamContainerGet( + itemId: itemId, + container: container, + $static: $static, + params: params, + tag: tag, + deviceProfileId: deviceProfileId, + playSessionId: playSessionId, + segmentContainer: segmentContainer, + segmentLength: segmentLength, + minSegments: minSegments, + mediaSourceId: mediaSourceId, + deviceId: deviceId, + audioCodec: audioCodec, + enableAutoStreamCopy: enableAutoStreamCopy, + allowVideoStreamCopy: allowVideoStreamCopy, + allowAudioStreamCopy: allowAudioStreamCopy, + breakOnNonKeyFrames: breakOnNonKeyFrames, + audioSampleRate: audioSampleRate, + maxAudioBitDepth: maxAudioBitDepth, + audioBitRate: audioBitRate, + audioChannels: audioChannels, + maxAudioChannels: maxAudioChannels, + profile: profile, + level: level, + framerate: framerate, + maxFramerate: maxFramerate, + copyTimestamps: copyTimestamps, + startTimeTicks: startTimeTicks, + width: width, + height: height, + videoBitRate: videoBitRate, + subtitleStreamIndex: subtitleStreamIndex, + subtitleMethod: subtitleMethod?.value?.toString(), + maxRefFrames: maxRefFrames, + maxVideoBitDepth: maxVideoBitDepth, + requireAvc: requireAvc, + deInterlace: deInterlace, + requireNonAnamorphic: requireNonAnamorphic, + transcodingMaxAudioChannels: transcodingMaxAudioChannels, + cpuCoreLimit: cpuCoreLimit, + liveStreamId: liveStreamId, + enableMpegtsM2TsMode: enableMpegtsM2TsMode, + videoCodec: videoCodec, + subtitleCodec: subtitleCodec, + transcodeReasons: transcodeReasons, + audioStreamIndex: audioStreamIndex, + videoStreamIndex: videoStreamIndex, + context: context?.value?.toString(), + streamOptions: streamOptions); + } + + ///Gets an audio stream. + ///@param itemId The item id. + ///@param container The audio container. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamporphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + @Get(path: '/Audio/{itemId}/stream.{container}') + Future> _audioItemIdStreamContainerGet({ + @Path('itemId') required String? itemId, + @Path('container') required String? container, + @Query('static') bool? $static, + @Query('params') String? params, + @Query('tag') String? tag, + @Query('deviceProfileId') String? deviceProfileId, + @Query('playSessionId') String? playSessionId, + @Query('segmentContainer') String? segmentContainer, + @Query('segmentLength') int? segmentLength, + @Query('minSegments') int? minSegments, + @Query('mediaSourceId') String? mediaSourceId, + @Query('deviceId') String? deviceId, + @Query('audioCodec') String? audioCodec, + @Query('enableAutoStreamCopy') bool? enableAutoStreamCopy, + @Query('allowVideoStreamCopy') bool? allowVideoStreamCopy, + @Query('allowAudioStreamCopy') bool? allowAudioStreamCopy, + @Query('breakOnNonKeyFrames') bool? breakOnNonKeyFrames, + @Query('audioSampleRate') int? audioSampleRate, + @Query('maxAudioBitDepth') int? maxAudioBitDepth, + @Query('audioBitRate') int? audioBitRate, + @Query('audioChannels') int? audioChannels, + @Query('maxAudioChannels') int? maxAudioChannels, + @Query('profile') String? profile, + @Query('level') String? level, + @Query('framerate') num? framerate, + @Query('maxFramerate') num? maxFramerate, + @Query('copyTimestamps') bool? copyTimestamps, + @Query('startTimeTicks') int? startTimeTicks, + @Query('width') int? width, + @Query('height') int? height, + @Query('videoBitRate') int? videoBitRate, + @Query('subtitleStreamIndex') int? subtitleStreamIndex, + @Query('subtitleMethod') String? subtitleMethod, + @Query('maxRefFrames') int? maxRefFrames, + @Query('maxVideoBitDepth') int? maxVideoBitDepth, + @Query('requireAvc') bool? requireAvc, + @Query('deInterlace') bool? deInterlace, + @Query('requireNonAnamorphic') bool? requireNonAnamorphic, + @Query('transcodingMaxAudioChannels') int? transcodingMaxAudioChannels, + @Query('cpuCoreLimit') int? cpuCoreLimit, + @Query('liveStreamId') String? liveStreamId, + @Query('enableMpegtsM2TsMode') bool? enableMpegtsM2TsMode, + @Query('videoCodec') String? videoCodec, + @Query('subtitleCodec') String? subtitleCodec, + @Query('transcodeReasons') String? transcodeReasons, + @Query('audioStreamIndex') int? audioStreamIndex, + @Query('videoStreamIndex') int? videoStreamIndex, + @Query('context') String? context, + @Query('streamOptions') Object? streamOptions, + }); + + ///Gets an audio stream. + ///@param itemId The item id. + ///@param container The audio container. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamporphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + Future> audioItemIdStreamContainerHead({ + required String? itemId, + required String? container, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? videoBitRate, + int? subtitleStreamIndex, + enums.AudioItemIdStreamContainerHeadSubtitleMethod? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + enums.AudioItemIdStreamContainerHeadContext? context, + Object? streamOptions, + }) { + return _audioItemIdStreamContainerHead( + itemId: itemId, + container: container, + $static: $static, + params: params, + tag: tag, + deviceProfileId: deviceProfileId, + playSessionId: playSessionId, + segmentContainer: segmentContainer, + segmentLength: segmentLength, + minSegments: minSegments, + mediaSourceId: mediaSourceId, + deviceId: deviceId, + audioCodec: audioCodec, + enableAutoStreamCopy: enableAutoStreamCopy, + allowVideoStreamCopy: allowVideoStreamCopy, + allowAudioStreamCopy: allowAudioStreamCopy, + breakOnNonKeyFrames: breakOnNonKeyFrames, + audioSampleRate: audioSampleRate, + maxAudioBitDepth: maxAudioBitDepth, + audioBitRate: audioBitRate, + audioChannels: audioChannels, + maxAudioChannels: maxAudioChannels, + profile: profile, + level: level, + framerate: framerate, + maxFramerate: maxFramerate, + copyTimestamps: copyTimestamps, + startTimeTicks: startTimeTicks, + width: width, + height: height, + videoBitRate: videoBitRate, + subtitleStreamIndex: subtitleStreamIndex, + subtitleMethod: subtitleMethod?.value?.toString(), + maxRefFrames: maxRefFrames, + maxVideoBitDepth: maxVideoBitDepth, + requireAvc: requireAvc, + deInterlace: deInterlace, + requireNonAnamorphic: requireNonAnamorphic, + transcodingMaxAudioChannels: transcodingMaxAudioChannels, + cpuCoreLimit: cpuCoreLimit, + liveStreamId: liveStreamId, + enableMpegtsM2TsMode: enableMpegtsM2TsMode, + videoCodec: videoCodec, + subtitleCodec: subtitleCodec, + transcodeReasons: transcodeReasons, + audioStreamIndex: audioStreamIndex, + videoStreamIndex: videoStreamIndex, + context: context?.value?.toString(), + streamOptions: streamOptions); + } + + ///Gets an audio stream. + ///@param itemId The item id. + ///@param container The audio container. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamporphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + @Head(path: '/Audio/{itemId}/stream.{container}') + Future> _audioItemIdStreamContainerHead({ + @Path('itemId') required String? itemId, + @Path('container') required String? container, + @Query('static') bool? $static, + @Query('params') String? params, + @Query('tag') String? tag, + @Query('deviceProfileId') String? deviceProfileId, + @Query('playSessionId') String? playSessionId, + @Query('segmentContainer') String? segmentContainer, + @Query('segmentLength') int? segmentLength, + @Query('minSegments') int? minSegments, + @Query('mediaSourceId') String? mediaSourceId, + @Query('deviceId') String? deviceId, + @Query('audioCodec') String? audioCodec, + @Query('enableAutoStreamCopy') bool? enableAutoStreamCopy, + @Query('allowVideoStreamCopy') bool? allowVideoStreamCopy, + @Query('allowAudioStreamCopy') bool? allowAudioStreamCopy, + @Query('breakOnNonKeyFrames') bool? breakOnNonKeyFrames, + @Query('audioSampleRate') int? audioSampleRate, + @Query('maxAudioBitDepth') int? maxAudioBitDepth, + @Query('audioBitRate') int? audioBitRate, + @Query('audioChannels') int? audioChannels, + @Query('maxAudioChannels') int? maxAudioChannels, + @Query('profile') String? profile, + @Query('level') String? level, + @Query('framerate') num? framerate, + @Query('maxFramerate') num? maxFramerate, + @Query('copyTimestamps') bool? copyTimestamps, + @Query('startTimeTicks') int? startTimeTicks, + @Query('width') int? width, + @Query('height') int? height, + @Query('videoBitRate') int? videoBitRate, + @Query('subtitleStreamIndex') int? subtitleStreamIndex, + @Query('subtitleMethod') String? subtitleMethod, + @Query('maxRefFrames') int? maxRefFrames, + @Query('maxVideoBitDepth') int? maxVideoBitDepth, + @Query('requireAvc') bool? requireAvc, + @Query('deInterlace') bool? deInterlace, + @Query('requireNonAnamorphic') bool? requireNonAnamorphic, + @Query('transcodingMaxAudioChannels') int? transcodingMaxAudioChannels, + @Query('cpuCoreLimit') int? cpuCoreLimit, + @Query('liveStreamId') String? liveStreamId, + @Query('enableMpegtsM2TsMode') bool? enableMpegtsM2TsMode, + @Query('videoCodec') String? videoCodec, + @Query('subtitleCodec') String? subtitleCodec, + @Query('transcodeReasons') String? transcodeReasons, + @Query('audioStreamIndex') int? audioStreamIndex, + @Query('videoStreamIndex') int? videoStreamIndex, + @Query('context') String? context, + @Query('streamOptions') Object? streamOptions, + }); + + ///Gets branding configuration. + Future> brandingConfigurationGet() { + generatedMapping.putIfAbsent( + BrandingOptions, () => BrandingOptions.fromJsonFactory); + + return _brandingConfigurationGet(); + } + + ///Gets branding configuration. + @Get(path: '/Branding/Configuration') + Future> _brandingConfigurationGet(); + + ///Gets branding css. + Future> brandingCssGet() { + return _brandingCssGet(); + } + + ///Gets branding css. + @Get(path: '/Branding/Css') + Future> _brandingCssGet(); + + ///Gets branding css. + Future> brandingCssCssGet() { + return _brandingCssCssGet(); + } + + ///Gets branding css. + @Get(path: '/Branding/Css.css') + Future> _brandingCssCssGet(); + + ///Gets available channels. + ///@param userId User Id to filter by. Use System.Guid.Empty to not filter by user. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param supportsLatestItems Optional. Filter by channels that support getting latest items. + ///@param supportsMediaDeletion Optional. Filter by channels that support media deletion. + ///@param isFavorite Optional. Filter by channels that are favorite. + Future> channelsGet({ + String? userId, + int? startIndex, + int? limit, + bool? supportsLatestItems, + bool? supportsMediaDeletion, + bool? isFavorite, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _channelsGet( + userId: userId, + startIndex: startIndex, + limit: limit, + supportsLatestItems: supportsLatestItems, + supportsMediaDeletion: supportsMediaDeletion, + isFavorite: isFavorite); + } + + ///Gets available channels. + ///@param userId User Id to filter by. Use System.Guid.Empty to not filter by user. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param supportsLatestItems Optional. Filter by channels that support getting latest items. + ///@param supportsMediaDeletion Optional. Filter by channels that support media deletion. + ///@param isFavorite Optional. Filter by channels that are favorite. + @Get(path: '/Channels') + Future> _channelsGet({ + @Query('userId') String? userId, + @Query('startIndex') int? startIndex, + @Query('limit') int? limit, + @Query('supportsLatestItems') bool? supportsLatestItems, + @Query('supportsMediaDeletion') bool? supportsMediaDeletion, + @Query('isFavorite') bool? isFavorite, + }); + + ///Get channel features. + ///@param channelId Channel id. + Future> channelsChannelIdFeaturesGet( + {required String? channelId}) { + generatedMapping.putIfAbsent( + ChannelFeatures, () => ChannelFeatures.fromJsonFactory); + + return _channelsChannelIdFeaturesGet(channelId: channelId); + } + + ///Get channel features. + ///@param channelId Channel id. + @Get(path: '/Channels/{channelId}/Features') + Future> _channelsChannelIdFeaturesGet( + {@Path('channelId') required String? channelId}); + + ///Get channel items. + ///@param channelId Channel Id. + ///@param folderId Optional. Folder Id. + ///@param userId Optional. User Id. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param sortOrder Optional. Sort Order - Ascending,Descending. + ///@param filters Optional. Specify additional filters to apply. + ///@param sortBy Optional. Specify one or more sort orders, comma delimited. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime. + ///@param fields Optional. Specify additional fields of information to return in the output. + Future> channelsChannelIdItemsGet({ + required String? channelId, + String? folderId, + String? userId, + int? startIndex, + int? limit, + List? sortOrder, + List? filters, + List? sortBy, + List? fields, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _channelsChannelIdItemsGet( + channelId: channelId, + folderId: folderId, + userId: userId, + startIndex: startIndex, + limit: limit, + sortOrder: sortOrderListToJson(sortOrder), + filters: itemFilterListToJson(filters), + sortBy: itemSortByListToJson(sortBy), + fields: itemFieldsListToJson(fields)); + } + + ///Get channel items. + ///@param channelId Channel Id. + ///@param folderId Optional. Folder Id. + ///@param userId Optional. User Id. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param sortOrder Optional. Sort Order - Ascending,Descending. + ///@param filters Optional. Specify additional filters to apply. + ///@param sortBy Optional. Specify one or more sort orders, comma delimited. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime. + ///@param fields Optional. Specify additional fields of information to return in the output. + @Get(path: '/Channels/{channelId}/Items') + Future> _channelsChannelIdItemsGet({ + @Path('channelId') required String? channelId, + @Query('folderId') String? folderId, + @Query('userId') String? userId, + @Query('startIndex') int? startIndex, + @Query('limit') int? limit, + @Query('sortOrder') List? sortOrder, + @Query('filters') List? filters, + @Query('sortBy') List? sortBy, + @Query('fields') List? fields, + }); + + ///Get all channel features. + Future>> channelsFeaturesGet() { + generatedMapping.putIfAbsent( + ChannelFeatures, () => ChannelFeatures.fromJsonFactory); + + return _channelsFeaturesGet(); + } + + ///Get all channel features. + @Get(path: '/Channels/Features') + Future>> _channelsFeaturesGet(); + + ///Gets latest channel items. + ///@param userId Optional. User Id. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param filters Optional. Specify additional filters to apply. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param channelIds Optional. Specify one or more channel id's, comma delimited. + Future> channelsItemsLatestGet({ + String? userId, + int? startIndex, + int? limit, + List? filters, + List? fields, + List? channelIds, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _channelsItemsLatestGet( + userId: userId, + startIndex: startIndex, + limit: limit, + filters: itemFilterListToJson(filters), + fields: itemFieldsListToJson(fields), + channelIds: channelIds); + } + + ///Gets latest channel items. + ///@param userId Optional. User Id. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param filters Optional. Specify additional filters to apply. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param channelIds Optional. Specify one or more channel id's, comma delimited. + @Get(path: '/Channels/Items/Latest') + Future> _channelsItemsLatestGet({ + @Query('userId') String? userId, + @Query('startIndex') int? startIndex, + @Query('limit') int? limit, + @Query('filters') List? filters, + @Query('fields') List? fields, + @Query('channelIds') List? channelIds, + }); + + ///Upload a document. + Future> clientLogDocumentPost( + {required Object? body}) { + generatedMapping.putIfAbsent(ClientLogDocumentResponseDto, + () => ClientLogDocumentResponseDto.fromJsonFactory); + + return _clientLogDocumentPost(body: body); + } + + ///Upload a document. + @Post( + path: '/ClientLog/Document', + optionalBody: true, + ) + Future> _clientLogDocumentPost( + {@Body() required Object? body}); + + ///Creates a new collection. + ///@param name The name of the collection. + ///@param ids Item Ids to add to the collection. + ///@param parentId Optional. Create the collection within a specific folder. + ///@param isLocked Whether or not to lock the new collection. + Future> collectionsPost({ + String? name, + List? ids, + String? parentId, + bool? isLocked, + }) { + generatedMapping.putIfAbsent(CollectionCreationResult, + () => CollectionCreationResult.fromJsonFactory); + + return _collectionsPost( + name: name, ids: ids, parentId: parentId, isLocked: isLocked); + } + + ///Creates a new collection. + ///@param name The name of the collection. + ///@param ids Item Ids to add to the collection. + ///@param parentId Optional. Create the collection within a specific folder. + ///@param isLocked Whether or not to lock the new collection. + @Post( + path: '/Collections', + optionalBody: true, + ) + Future> _collectionsPost({ + @Query('name') String? name, + @Query('ids') List? ids, + @Query('parentId') String? parentId, + @Query('isLocked') bool? isLocked, + }); + + ///Adds items to a collection. + ///@param collectionId The collection id. + ///@param ids Item ids, comma delimited. + Future collectionsCollectionIdItemsPost({ + required String? collectionId, + required List? ids, + }) { + return _collectionsCollectionIdItemsPost( + collectionId: collectionId, ids: ids); + } + + ///Adds items to a collection. + ///@param collectionId The collection id. + ///@param ids Item ids, comma delimited. + @Post( + path: '/Collections/{collectionId}/Items', + optionalBody: true, + ) + Future _collectionsCollectionIdItemsPost({ + @Path('collectionId') required String? collectionId, + @Query('ids') required List? ids, + }); + + ///Removes items from a collection. + ///@param collectionId The collection id. + ///@param ids Item ids, comma delimited. + Future collectionsCollectionIdItemsDelete({ + required String? collectionId, + required List? ids, + }) { + return _collectionsCollectionIdItemsDelete( + collectionId: collectionId, ids: ids); + } + + ///Removes items from a collection. + ///@param collectionId The collection id. + ///@param ids Item ids, comma delimited. + @Delete(path: '/Collections/{collectionId}/Items') + Future _collectionsCollectionIdItemsDelete({ + @Path('collectionId') required String? collectionId, + @Query('ids') required List? ids, + }); + + ///Gets application configuration. + Future> systemConfigurationGet() { + generatedMapping.putIfAbsent( + ServerConfiguration, () => ServerConfiguration.fromJsonFactory); + + return _systemConfigurationGet(); + } + + ///Gets application configuration. + @Get(path: '/System/Configuration') + Future> _systemConfigurationGet(); + + ///Updates application configuration. + Future systemConfigurationPost( + {required ServerConfiguration? body}) { + return _systemConfigurationPost(body: body); + } + + ///Updates application configuration. + @Post( + path: '/System/Configuration', + optionalBody: true, + ) + Future _systemConfigurationPost( + {@Body() required ServerConfiguration? body}); + + ///Gets a named configuration. + ///@param key Configuration key. + Future> systemConfigurationKeyGet( + {required String? key}) { + return _systemConfigurationKeyGet(key: key); + } + + ///Gets a named configuration. + ///@param key Configuration key. + @Get(path: '/System/Configuration/{key}') + Future> _systemConfigurationKeyGet( + {@Path('key') required String? key}); + + ///Updates named configuration. + ///@param key Configuration key. + Future systemConfigurationKeyPost({ + required String? key, + required Object? body, + }) { + return _systemConfigurationKeyPost(key: key, body: body); + } + + ///Updates named configuration. + ///@param key Configuration key. + @Post( + path: '/System/Configuration/{key}', + optionalBody: true, + ) + Future _systemConfigurationKeyPost({ + @Path('key') required String? key, + @Body() required Object? body, + }); + + ///Gets a default MetadataOptions object. + Future> + systemConfigurationMetadataOptionsDefaultGet() { + generatedMapping.putIfAbsent( + MetadataOptions, () => MetadataOptions.fromJsonFactory); + + return _systemConfigurationMetadataOptionsDefaultGet(); + } + + ///Gets a default MetadataOptions object. + @Get(path: '/System/Configuration/MetadataOptions/Default') + Future> + _systemConfigurationMetadataOptionsDefaultGet(); + + ///Gets a dashboard configuration page. + ///@param name The name of the page. + Future> webConfigurationPageGet({String? name}) { + return _webConfigurationPageGet(name: name); + } + + ///Gets a dashboard configuration page. + ///@param name The name of the page. + @Get(path: '/web/ConfigurationPage') + Future> _webConfigurationPageGet( + {@Query('name') String? name}); + + ///Gets the configuration pages. + ///@param enableInMainMenu Whether to enable in the main menu. + Future>> + webConfigurationPagesGet({bool? enableInMainMenu}) { + generatedMapping.putIfAbsent( + ConfigurationPageInfo, () => ConfigurationPageInfo.fromJsonFactory); + + return _webConfigurationPagesGet(enableInMainMenu: enableInMainMenu); + } + + ///Gets the configuration pages. + ///@param enableInMainMenu Whether to enable in the main menu. + @Get(path: '/web/ConfigurationPages') + Future>> + _webConfigurationPagesGet( + {@Query('enableInMainMenu') bool? enableInMainMenu}); + + ///Get Devices. + ///@param userId Gets or sets the user identifier. + Future> devicesGet({String? userId}) { + generatedMapping.putIfAbsent( + DeviceInfoQueryResult, () => DeviceInfoQueryResult.fromJsonFactory); + + return _devicesGet(userId: userId); + } + + ///Get Devices. + ///@param userId Gets or sets the user identifier. + @Get(path: '/Devices') + Future> _devicesGet( + {@Query('userId') String? userId}); + + ///Deletes a device. + ///@param id Device Id. + Future devicesDelete({required String? id}) { + return _devicesDelete(id: id); + } + + ///Deletes a device. + ///@param id Device Id. + @Delete(path: '/Devices') + Future _devicesDelete({@Query('id') required String? id}); + + ///Get info for a device. + ///@param id Device Id. + Future> devicesInfoGet({required String? id}) { + generatedMapping.putIfAbsent(DeviceInfo, () => DeviceInfo.fromJsonFactory); + + return _devicesInfoGet(id: id); + } + + ///Get info for a device. + ///@param id Device Id. + @Get(path: '/Devices/Info') + Future> _devicesInfoGet( + {@Query('id') required String? id}); + + ///Get options for a device. + ///@param id Device Id. + Future> devicesOptionsGet( + {required String? id}) { + generatedMapping.putIfAbsent( + DeviceOptions, () => DeviceOptions.fromJsonFactory); + + return _devicesOptionsGet(id: id); + } + + ///Get options for a device. + ///@param id Device Id. + @Get(path: '/Devices/Options') + Future> _devicesOptionsGet( + {@Query('id') required String? id}); + + ///Update device options. + ///@param id Device Id. + Future devicesOptionsPost({ + required String? id, + required DeviceOptionsDto? body, + }) { + return _devicesOptionsPost(id: id, body: body); + } + + ///Update device options. + ///@param id Device Id. + @Post( + path: '/Devices/Options', + optionalBody: true, + ) + Future _devicesOptionsPost({ + @Query('id') required String? id, + @Body() required DeviceOptionsDto? body, + }); + + ///Get Display Preferences. + ///@param displayPreferencesId Display preferences id. + ///@param userId User id. + ///@param client Client. + Future> + displayPreferencesDisplayPreferencesIdGet({ + required String? displayPreferencesId, + String? userId, + required String? $client, + }) { + generatedMapping.putIfAbsent( + DisplayPreferencesDto, () => DisplayPreferencesDto.fromJsonFactory); + + return _displayPreferencesDisplayPreferencesIdGet( + displayPreferencesId: displayPreferencesId, + userId: userId, + $client: $client); + } + + ///Get Display Preferences. + ///@param displayPreferencesId Display preferences id. + ///@param userId User id. + ///@param client Client. + @Get(path: '/DisplayPreferences/{displayPreferencesId}') + Future> + _displayPreferencesDisplayPreferencesIdGet({ + @Path('displayPreferencesId') required String? displayPreferencesId, + @Query('userId') String? userId, + @Query('client') required String? $client, + }); + + ///Update Display Preferences. + ///@param displayPreferencesId Display preferences id. + ///@param userId User Id. + ///@param client Client. + Future displayPreferencesDisplayPreferencesIdPost({ + required String? displayPreferencesId, + String? userId, + required String? $client, + required DisplayPreferencesDto? body, + }) { + return _displayPreferencesDisplayPreferencesIdPost( + displayPreferencesId: displayPreferencesId, + userId: userId, + $client: $client, + body: body); + } + + ///Update Display Preferences. + ///@param displayPreferencesId Display preferences id. + ///@param userId User Id. + ///@param client Client. + @Post( + path: '/DisplayPreferences/{displayPreferencesId}', + optionalBody: true, + ) + Future _displayPreferencesDisplayPreferencesIdPost({ + @Path('displayPreferencesId') required String? displayPreferencesId, + @Query('userId') String? userId, + @Query('client') required String? $client, + @Body() required DisplayPreferencesDto? body, + }); + + ///Gets a video stream using HTTP live streaming. + ///@param itemId The item id. + ///@param playlistId The playlist id. + ///@param segmentId The segment id. + ///@param container The video container. Possible values are: ts, webm, asf, wmv, ogv, mp4, m4v, mkv, mpeg, mpg, avi, 3gp, wmv, wtv, m2ts, mov, iso, flv. + ///@param runtimeTicks The position of the requested segment in ticks. + ///@param actualSegmentLengthTicks The length of the requested segment in ticks. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param maxStreamingBitrate Optional. The maximum streaming bitrate. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vpx, wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + Future> + audioItemIdHls1PlaylistIdSegmentIdContainerGet({ + required String? itemId, + required String? playlistId, + required int? segmentId, + required String? container, + required int? runtimeTicks, + required int? actualSegmentLengthTicks, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? maxStreamingBitrate, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? videoBitRate, + int? subtitleStreamIndex, + enums.AudioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod? + subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + enums.AudioItemIdHls1PlaylistIdSegmentIdContainerGetContext? context, + Object? streamOptions, + }) { + return _audioItemIdHls1PlaylistIdSegmentIdContainerGet( + itemId: itemId, + playlistId: playlistId, + segmentId: segmentId, + container: container, + runtimeTicks: runtimeTicks, + actualSegmentLengthTicks: actualSegmentLengthTicks, + $static: $static, + params: params, + tag: tag, + deviceProfileId: deviceProfileId, + playSessionId: playSessionId, + segmentContainer: segmentContainer, + segmentLength: segmentLength, + minSegments: minSegments, + mediaSourceId: mediaSourceId, + deviceId: deviceId, + audioCodec: audioCodec, + enableAutoStreamCopy: enableAutoStreamCopy, + allowVideoStreamCopy: allowVideoStreamCopy, + allowAudioStreamCopy: allowAudioStreamCopy, + breakOnNonKeyFrames: breakOnNonKeyFrames, + audioSampleRate: audioSampleRate, + maxAudioBitDepth: maxAudioBitDepth, + maxStreamingBitrate: maxStreamingBitrate, + audioBitRate: audioBitRate, + audioChannels: audioChannels, + maxAudioChannels: maxAudioChannels, + profile: profile, + level: level, + framerate: framerate, + maxFramerate: maxFramerate, + copyTimestamps: copyTimestamps, + startTimeTicks: startTimeTicks, + width: width, + height: height, + videoBitRate: videoBitRate, + subtitleStreamIndex: subtitleStreamIndex, + subtitleMethod: subtitleMethod?.value?.toString(), + maxRefFrames: maxRefFrames, + maxVideoBitDepth: maxVideoBitDepth, + requireAvc: requireAvc, + deInterlace: deInterlace, + requireNonAnamorphic: requireNonAnamorphic, + transcodingMaxAudioChannels: transcodingMaxAudioChannels, + cpuCoreLimit: cpuCoreLimit, + liveStreamId: liveStreamId, + enableMpegtsM2TsMode: enableMpegtsM2TsMode, + videoCodec: videoCodec, + subtitleCodec: subtitleCodec, + transcodeReasons: transcodeReasons, + audioStreamIndex: audioStreamIndex, + videoStreamIndex: videoStreamIndex, + context: context?.value?.toString(), + streamOptions: streamOptions); + } + + ///Gets a video stream using HTTP live streaming. + ///@param itemId The item id. + ///@param playlistId The playlist id. + ///@param segmentId The segment id. + ///@param container The video container. Possible values are: ts, webm, asf, wmv, ogv, mp4, m4v, mkv, mpeg, mpg, avi, 3gp, wmv, wtv, m2ts, mov, iso, flv. + ///@param runtimeTicks The position of the requested segment in ticks. + ///@param actualSegmentLengthTicks The length of the requested segment in ticks. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param maxStreamingBitrate Optional. The maximum streaming bitrate. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vpx, wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + @Get(path: '/Audio/{itemId}/hls1/{playlistId}/{segmentId}.{container}') + Future> + _audioItemIdHls1PlaylistIdSegmentIdContainerGet({ + @Path('itemId') required String? itemId, + @Path('playlistId') required String? playlistId, + @Path('segmentId') required int? segmentId, + @Path('container') required String? container, + @Query('runtimeTicks') required int? runtimeTicks, + @Query('actualSegmentLengthTicks') required int? actualSegmentLengthTicks, + @Query('static') bool? $static, + @Query('params') String? params, + @Query('tag') String? tag, + @Query('deviceProfileId') String? deviceProfileId, + @Query('playSessionId') String? playSessionId, + @Query('segmentContainer') String? segmentContainer, + @Query('segmentLength') int? segmentLength, + @Query('minSegments') int? minSegments, + @Query('mediaSourceId') String? mediaSourceId, + @Query('deviceId') String? deviceId, + @Query('audioCodec') String? audioCodec, + @Query('enableAutoStreamCopy') bool? enableAutoStreamCopy, + @Query('allowVideoStreamCopy') bool? allowVideoStreamCopy, + @Query('allowAudioStreamCopy') bool? allowAudioStreamCopy, + @Query('breakOnNonKeyFrames') bool? breakOnNonKeyFrames, + @Query('audioSampleRate') int? audioSampleRate, + @Query('maxAudioBitDepth') int? maxAudioBitDepth, + @Query('maxStreamingBitrate') int? maxStreamingBitrate, + @Query('audioBitRate') int? audioBitRate, + @Query('audioChannels') int? audioChannels, + @Query('maxAudioChannels') int? maxAudioChannels, + @Query('profile') String? profile, + @Query('level') String? level, + @Query('framerate') num? framerate, + @Query('maxFramerate') num? maxFramerate, + @Query('copyTimestamps') bool? copyTimestamps, + @Query('startTimeTicks') int? startTimeTicks, + @Query('width') int? width, + @Query('height') int? height, + @Query('videoBitRate') int? videoBitRate, + @Query('subtitleStreamIndex') int? subtitleStreamIndex, + @Query('subtitleMethod') String? subtitleMethod, + @Query('maxRefFrames') int? maxRefFrames, + @Query('maxVideoBitDepth') int? maxVideoBitDepth, + @Query('requireAvc') bool? requireAvc, + @Query('deInterlace') bool? deInterlace, + @Query('requireNonAnamorphic') bool? requireNonAnamorphic, + @Query('transcodingMaxAudioChannels') int? transcodingMaxAudioChannels, + @Query('cpuCoreLimit') int? cpuCoreLimit, + @Query('liveStreamId') String? liveStreamId, + @Query('enableMpegtsM2TsMode') bool? enableMpegtsM2TsMode, + @Query('videoCodec') String? videoCodec, + @Query('subtitleCodec') String? subtitleCodec, + @Query('transcodeReasons') String? transcodeReasons, + @Query('audioStreamIndex') int? audioStreamIndex, + @Query('videoStreamIndex') int? videoStreamIndex, + @Query('context') String? context, + @Query('streamOptions') Object? streamOptions, + }); + + ///Gets an audio stream using HTTP live streaming. + ///@param itemId The item id. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param maxStreamingBitrate Optional. The maximum streaming bitrate. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vpx, wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + Future> audioItemIdMainM3u8Get({ + required String? itemId, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? maxStreamingBitrate, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? videoBitRate, + int? subtitleStreamIndex, + enums.AudioItemIdMainM3u8GetSubtitleMethod? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + enums.AudioItemIdMainM3u8GetContext? context, + Object? streamOptions, + }) { + return _audioItemIdMainM3u8Get( + itemId: itemId, + $static: $static, + params: params, + tag: tag, + deviceProfileId: deviceProfileId, + playSessionId: playSessionId, + segmentContainer: segmentContainer, + segmentLength: segmentLength, + minSegments: minSegments, + mediaSourceId: mediaSourceId, + deviceId: deviceId, + audioCodec: audioCodec, + enableAutoStreamCopy: enableAutoStreamCopy, + allowVideoStreamCopy: allowVideoStreamCopy, + allowAudioStreamCopy: allowAudioStreamCopy, + breakOnNonKeyFrames: breakOnNonKeyFrames, + audioSampleRate: audioSampleRate, + maxAudioBitDepth: maxAudioBitDepth, + maxStreamingBitrate: maxStreamingBitrate, + audioBitRate: audioBitRate, + audioChannels: audioChannels, + maxAudioChannels: maxAudioChannels, + profile: profile, + level: level, + framerate: framerate, + maxFramerate: maxFramerate, + copyTimestamps: copyTimestamps, + startTimeTicks: startTimeTicks, + width: width, + height: height, + videoBitRate: videoBitRate, + subtitleStreamIndex: subtitleStreamIndex, + subtitleMethod: subtitleMethod?.value?.toString(), + maxRefFrames: maxRefFrames, + maxVideoBitDepth: maxVideoBitDepth, + requireAvc: requireAvc, + deInterlace: deInterlace, + requireNonAnamorphic: requireNonAnamorphic, + transcodingMaxAudioChannels: transcodingMaxAudioChannels, + cpuCoreLimit: cpuCoreLimit, + liveStreamId: liveStreamId, + enableMpegtsM2TsMode: enableMpegtsM2TsMode, + videoCodec: videoCodec, + subtitleCodec: subtitleCodec, + transcodeReasons: transcodeReasons, + audioStreamIndex: audioStreamIndex, + videoStreamIndex: videoStreamIndex, + context: context?.value?.toString(), + streamOptions: streamOptions); + } + + ///Gets an audio stream using HTTP live streaming. + ///@param itemId The item id. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param maxStreamingBitrate Optional. The maximum streaming bitrate. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vpx, wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + @Get(path: '/Audio/{itemId}/main.m3u8') + Future> _audioItemIdMainM3u8Get({ + @Path('itemId') required String? itemId, + @Query('static') bool? $static, + @Query('params') String? params, + @Query('tag') String? tag, + @Query('deviceProfileId') String? deviceProfileId, + @Query('playSessionId') String? playSessionId, + @Query('segmentContainer') String? segmentContainer, + @Query('segmentLength') int? segmentLength, + @Query('minSegments') int? minSegments, + @Query('mediaSourceId') String? mediaSourceId, + @Query('deviceId') String? deviceId, + @Query('audioCodec') String? audioCodec, + @Query('enableAutoStreamCopy') bool? enableAutoStreamCopy, + @Query('allowVideoStreamCopy') bool? allowVideoStreamCopy, + @Query('allowAudioStreamCopy') bool? allowAudioStreamCopy, + @Query('breakOnNonKeyFrames') bool? breakOnNonKeyFrames, + @Query('audioSampleRate') int? audioSampleRate, + @Query('maxAudioBitDepth') int? maxAudioBitDepth, + @Query('maxStreamingBitrate') int? maxStreamingBitrate, + @Query('audioBitRate') int? audioBitRate, + @Query('audioChannels') int? audioChannels, + @Query('maxAudioChannels') int? maxAudioChannels, + @Query('profile') String? profile, + @Query('level') String? level, + @Query('framerate') num? framerate, + @Query('maxFramerate') num? maxFramerate, + @Query('copyTimestamps') bool? copyTimestamps, + @Query('startTimeTicks') int? startTimeTicks, + @Query('width') int? width, + @Query('height') int? height, + @Query('videoBitRate') int? videoBitRate, + @Query('subtitleStreamIndex') int? subtitleStreamIndex, + @Query('subtitleMethod') String? subtitleMethod, + @Query('maxRefFrames') int? maxRefFrames, + @Query('maxVideoBitDepth') int? maxVideoBitDepth, + @Query('requireAvc') bool? requireAvc, + @Query('deInterlace') bool? deInterlace, + @Query('requireNonAnamorphic') bool? requireNonAnamorphic, + @Query('transcodingMaxAudioChannels') int? transcodingMaxAudioChannels, + @Query('cpuCoreLimit') int? cpuCoreLimit, + @Query('liveStreamId') String? liveStreamId, + @Query('enableMpegtsM2TsMode') bool? enableMpegtsM2TsMode, + @Query('videoCodec') String? videoCodec, + @Query('subtitleCodec') String? subtitleCodec, + @Query('transcodeReasons') String? transcodeReasons, + @Query('audioStreamIndex') int? audioStreamIndex, + @Query('videoStreamIndex') int? videoStreamIndex, + @Query('context') String? context, + @Query('streamOptions') Object? streamOptions, + }); + + ///Gets an audio hls playlist stream. + ///@param itemId The item id. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param maxStreamingBitrate Optional. The maximum streaming bitrate. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + ///@param enableAdaptiveBitrateStreaming Enable adaptive bitrate streaming. + Future> audioItemIdMasterM3u8Get({ + required String? itemId, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + required String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? maxStreamingBitrate, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? videoBitRate, + int? subtitleStreamIndex, + enums.AudioItemIdMasterM3u8GetSubtitleMethod? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + enums.AudioItemIdMasterM3u8GetContext? context, + Object? streamOptions, + bool? enableAdaptiveBitrateStreaming, + }) { + return _audioItemIdMasterM3u8Get( + itemId: itemId, + $static: $static, + params: params, + tag: tag, + deviceProfileId: deviceProfileId, + playSessionId: playSessionId, + segmentContainer: segmentContainer, + segmentLength: segmentLength, + minSegments: minSegments, + mediaSourceId: mediaSourceId, + deviceId: deviceId, + audioCodec: audioCodec, + enableAutoStreamCopy: enableAutoStreamCopy, + allowVideoStreamCopy: allowVideoStreamCopy, + allowAudioStreamCopy: allowAudioStreamCopy, + breakOnNonKeyFrames: breakOnNonKeyFrames, + audioSampleRate: audioSampleRate, + maxAudioBitDepth: maxAudioBitDepth, + maxStreamingBitrate: maxStreamingBitrate, + audioBitRate: audioBitRate, + audioChannels: audioChannels, + maxAudioChannels: maxAudioChannels, + profile: profile, + level: level, + framerate: framerate, + maxFramerate: maxFramerate, + copyTimestamps: copyTimestamps, + startTimeTicks: startTimeTicks, + width: width, + height: height, + videoBitRate: videoBitRate, + subtitleStreamIndex: subtitleStreamIndex, + subtitleMethod: subtitleMethod?.value?.toString(), + maxRefFrames: maxRefFrames, + maxVideoBitDepth: maxVideoBitDepth, + requireAvc: requireAvc, + deInterlace: deInterlace, + requireNonAnamorphic: requireNonAnamorphic, + transcodingMaxAudioChannels: transcodingMaxAudioChannels, + cpuCoreLimit: cpuCoreLimit, + liveStreamId: liveStreamId, + enableMpegtsM2TsMode: enableMpegtsM2TsMode, + videoCodec: videoCodec, + subtitleCodec: subtitleCodec, + transcodeReasons: transcodeReasons, + audioStreamIndex: audioStreamIndex, + videoStreamIndex: videoStreamIndex, + context: context?.value?.toString(), + streamOptions: streamOptions, + enableAdaptiveBitrateStreaming: enableAdaptiveBitrateStreaming); + } + + ///Gets an audio hls playlist stream. + ///@param itemId The item id. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param maxStreamingBitrate Optional. The maximum streaming bitrate. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + ///@param enableAdaptiveBitrateStreaming Enable adaptive bitrate streaming. + @Get(path: '/Audio/{itemId}/master.m3u8') + Future> _audioItemIdMasterM3u8Get({ + @Path('itemId') required String? itemId, + @Query('static') bool? $static, + @Query('params') String? params, + @Query('tag') String? tag, + @Query('deviceProfileId') String? deviceProfileId, + @Query('playSessionId') String? playSessionId, + @Query('segmentContainer') String? segmentContainer, + @Query('segmentLength') int? segmentLength, + @Query('minSegments') int? minSegments, + @Query('mediaSourceId') required String? mediaSourceId, + @Query('deviceId') String? deviceId, + @Query('audioCodec') String? audioCodec, + @Query('enableAutoStreamCopy') bool? enableAutoStreamCopy, + @Query('allowVideoStreamCopy') bool? allowVideoStreamCopy, + @Query('allowAudioStreamCopy') bool? allowAudioStreamCopy, + @Query('breakOnNonKeyFrames') bool? breakOnNonKeyFrames, + @Query('audioSampleRate') int? audioSampleRate, + @Query('maxAudioBitDepth') int? maxAudioBitDepth, + @Query('maxStreamingBitrate') int? maxStreamingBitrate, + @Query('audioBitRate') int? audioBitRate, + @Query('audioChannels') int? audioChannels, + @Query('maxAudioChannels') int? maxAudioChannels, + @Query('profile') String? profile, + @Query('level') String? level, + @Query('framerate') num? framerate, + @Query('maxFramerate') num? maxFramerate, + @Query('copyTimestamps') bool? copyTimestamps, + @Query('startTimeTicks') int? startTimeTicks, + @Query('width') int? width, + @Query('height') int? height, + @Query('videoBitRate') int? videoBitRate, + @Query('subtitleStreamIndex') int? subtitleStreamIndex, + @Query('subtitleMethod') String? subtitleMethod, + @Query('maxRefFrames') int? maxRefFrames, + @Query('maxVideoBitDepth') int? maxVideoBitDepth, + @Query('requireAvc') bool? requireAvc, + @Query('deInterlace') bool? deInterlace, + @Query('requireNonAnamorphic') bool? requireNonAnamorphic, + @Query('transcodingMaxAudioChannels') int? transcodingMaxAudioChannels, + @Query('cpuCoreLimit') int? cpuCoreLimit, + @Query('liveStreamId') String? liveStreamId, + @Query('enableMpegtsM2TsMode') bool? enableMpegtsM2TsMode, + @Query('videoCodec') String? videoCodec, + @Query('subtitleCodec') String? subtitleCodec, + @Query('transcodeReasons') String? transcodeReasons, + @Query('audioStreamIndex') int? audioStreamIndex, + @Query('videoStreamIndex') int? videoStreamIndex, + @Query('context') String? context, + @Query('streamOptions') Object? streamOptions, + @Query('enableAdaptiveBitrateStreaming') + bool? enableAdaptiveBitrateStreaming, + }); + + ///Gets an audio hls playlist stream. + ///@param itemId The item id. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param maxStreamingBitrate Optional. The maximum streaming bitrate. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + ///@param enableAdaptiveBitrateStreaming Enable adaptive bitrate streaming. + Future> audioItemIdMasterM3u8Head({ + required String? itemId, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + required String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? maxStreamingBitrate, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? videoBitRate, + int? subtitleStreamIndex, + enums.AudioItemIdMasterM3u8HeadSubtitleMethod? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + enums.AudioItemIdMasterM3u8HeadContext? context, + Object? streamOptions, + bool? enableAdaptiveBitrateStreaming, + }) { + return _audioItemIdMasterM3u8Head( + itemId: itemId, + $static: $static, + params: params, + tag: tag, + deviceProfileId: deviceProfileId, + playSessionId: playSessionId, + segmentContainer: segmentContainer, + segmentLength: segmentLength, + minSegments: minSegments, + mediaSourceId: mediaSourceId, + deviceId: deviceId, + audioCodec: audioCodec, + enableAutoStreamCopy: enableAutoStreamCopy, + allowVideoStreamCopy: allowVideoStreamCopy, + allowAudioStreamCopy: allowAudioStreamCopy, + breakOnNonKeyFrames: breakOnNonKeyFrames, + audioSampleRate: audioSampleRate, + maxAudioBitDepth: maxAudioBitDepth, + maxStreamingBitrate: maxStreamingBitrate, + audioBitRate: audioBitRate, + audioChannels: audioChannels, + maxAudioChannels: maxAudioChannels, + profile: profile, + level: level, + framerate: framerate, + maxFramerate: maxFramerate, + copyTimestamps: copyTimestamps, + startTimeTicks: startTimeTicks, + width: width, + height: height, + videoBitRate: videoBitRate, + subtitleStreamIndex: subtitleStreamIndex, + subtitleMethod: subtitleMethod?.value?.toString(), + maxRefFrames: maxRefFrames, + maxVideoBitDepth: maxVideoBitDepth, + requireAvc: requireAvc, + deInterlace: deInterlace, + requireNonAnamorphic: requireNonAnamorphic, + transcodingMaxAudioChannels: transcodingMaxAudioChannels, + cpuCoreLimit: cpuCoreLimit, + liveStreamId: liveStreamId, + enableMpegtsM2TsMode: enableMpegtsM2TsMode, + videoCodec: videoCodec, + subtitleCodec: subtitleCodec, + transcodeReasons: transcodeReasons, + audioStreamIndex: audioStreamIndex, + videoStreamIndex: videoStreamIndex, + context: context?.value?.toString(), + streamOptions: streamOptions, + enableAdaptiveBitrateStreaming: enableAdaptiveBitrateStreaming); + } + + ///Gets an audio hls playlist stream. + ///@param itemId The item id. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param maxStreamingBitrate Optional. The maximum streaming bitrate. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + ///@param enableAdaptiveBitrateStreaming Enable adaptive bitrate streaming. + @Head(path: '/Audio/{itemId}/master.m3u8') + Future> _audioItemIdMasterM3u8Head({ + @Path('itemId') required String? itemId, + @Query('static') bool? $static, + @Query('params') String? params, + @Query('tag') String? tag, + @Query('deviceProfileId') String? deviceProfileId, + @Query('playSessionId') String? playSessionId, + @Query('segmentContainer') String? segmentContainer, + @Query('segmentLength') int? segmentLength, + @Query('minSegments') int? minSegments, + @Query('mediaSourceId') required String? mediaSourceId, + @Query('deviceId') String? deviceId, + @Query('audioCodec') String? audioCodec, + @Query('enableAutoStreamCopy') bool? enableAutoStreamCopy, + @Query('allowVideoStreamCopy') bool? allowVideoStreamCopy, + @Query('allowAudioStreamCopy') bool? allowAudioStreamCopy, + @Query('breakOnNonKeyFrames') bool? breakOnNonKeyFrames, + @Query('audioSampleRate') int? audioSampleRate, + @Query('maxAudioBitDepth') int? maxAudioBitDepth, + @Query('maxStreamingBitrate') int? maxStreamingBitrate, + @Query('audioBitRate') int? audioBitRate, + @Query('audioChannels') int? audioChannels, + @Query('maxAudioChannels') int? maxAudioChannels, + @Query('profile') String? profile, + @Query('level') String? level, + @Query('framerate') num? framerate, + @Query('maxFramerate') num? maxFramerate, + @Query('copyTimestamps') bool? copyTimestamps, + @Query('startTimeTicks') int? startTimeTicks, + @Query('width') int? width, + @Query('height') int? height, + @Query('videoBitRate') int? videoBitRate, + @Query('subtitleStreamIndex') int? subtitleStreamIndex, + @Query('subtitleMethod') String? subtitleMethod, + @Query('maxRefFrames') int? maxRefFrames, + @Query('maxVideoBitDepth') int? maxVideoBitDepth, + @Query('requireAvc') bool? requireAvc, + @Query('deInterlace') bool? deInterlace, + @Query('requireNonAnamorphic') bool? requireNonAnamorphic, + @Query('transcodingMaxAudioChannels') int? transcodingMaxAudioChannels, + @Query('cpuCoreLimit') int? cpuCoreLimit, + @Query('liveStreamId') String? liveStreamId, + @Query('enableMpegtsM2TsMode') bool? enableMpegtsM2TsMode, + @Query('videoCodec') String? videoCodec, + @Query('subtitleCodec') String? subtitleCodec, + @Query('transcodeReasons') String? transcodeReasons, + @Query('audioStreamIndex') int? audioStreamIndex, + @Query('videoStreamIndex') int? videoStreamIndex, + @Query('context') String? context, + @Query('streamOptions') Object? streamOptions, + @Query('enableAdaptiveBitrateStreaming') + bool? enableAdaptiveBitrateStreaming, + }); + + ///Gets a video stream using HTTP live streaming. + ///@param itemId The item id. + ///@param playlistId The playlist id. + ///@param segmentId The segment id. + ///@param container The video container. Possible values are: ts, webm, asf, wmv, ogv, mp4, m4v, mkv, mpeg, mpg, avi, 3gp, wmv, wtv, m2ts, mov, iso, flv. + ///@param runtimeTicks The position of the requested segment in ticks. + ///@param actualSegmentLengthTicks The length of the requested segment in ticks. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The desired segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param maxWidth Optional. The maximum horizontal resolution of the encoded video. + ///@param maxHeight Optional. The maximum vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + Future> + videosItemIdHls1PlaylistIdSegmentIdContainerGet({ + required String? itemId, + required String? playlistId, + required int? segmentId, + required String? container, + required int? runtimeTicks, + required int? actualSegmentLengthTicks, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? maxWidth, + int? maxHeight, + int? videoBitRate, + int? subtitleStreamIndex, + enums.VideosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod? + subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + enums.VideosItemIdHls1PlaylistIdSegmentIdContainerGetContext? context, + Object? streamOptions, + }) { + return _videosItemIdHls1PlaylistIdSegmentIdContainerGet( + itemId: itemId, + playlistId: playlistId, + segmentId: segmentId, + container: container, + runtimeTicks: runtimeTicks, + actualSegmentLengthTicks: actualSegmentLengthTicks, + $static: $static, + params: params, + tag: tag, + deviceProfileId: deviceProfileId, + playSessionId: playSessionId, + segmentContainer: segmentContainer, + segmentLength: segmentLength, + minSegments: minSegments, + mediaSourceId: mediaSourceId, + deviceId: deviceId, + audioCodec: audioCodec, + enableAutoStreamCopy: enableAutoStreamCopy, + allowVideoStreamCopy: allowVideoStreamCopy, + allowAudioStreamCopy: allowAudioStreamCopy, + breakOnNonKeyFrames: breakOnNonKeyFrames, + audioSampleRate: audioSampleRate, + maxAudioBitDepth: maxAudioBitDepth, + audioBitRate: audioBitRate, + audioChannels: audioChannels, + maxAudioChannels: maxAudioChannels, + profile: profile, + level: level, + framerate: framerate, + maxFramerate: maxFramerate, + copyTimestamps: copyTimestamps, + startTimeTicks: startTimeTicks, + width: width, + height: height, + maxWidth: maxWidth, + maxHeight: maxHeight, + videoBitRate: videoBitRate, + subtitleStreamIndex: subtitleStreamIndex, + subtitleMethod: subtitleMethod?.value?.toString(), + maxRefFrames: maxRefFrames, + maxVideoBitDepth: maxVideoBitDepth, + requireAvc: requireAvc, + deInterlace: deInterlace, + requireNonAnamorphic: requireNonAnamorphic, + transcodingMaxAudioChannels: transcodingMaxAudioChannels, + cpuCoreLimit: cpuCoreLimit, + liveStreamId: liveStreamId, + enableMpegtsM2TsMode: enableMpegtsM2TsMode, + videoCodec: videoCodec, + subtitleCodec: subtitleCodec, + transcodeReasons: transcodeReasons, + audioStreamIndex: audioStreamIndex, + videoStreamIndex: videoStreamIndex, + context: context?.value?.toString(), + streamOptions: streamOptions); + } + + ///Gets a video stream using HTTP live streaming. + ///@param itemId The item id. + ///@param playlistId The playlist id. + ///@param segmentId The segment id. + ///@param container The video container. Possible values are: ts, webm, asf, wmv, ogv, mp4, m4v, mkv, mpeg, mpg, avi, 3gp, wmv, wtv, m2ts, mov, iso, flv. + ///@param runtimeTicks The position of the requested segment in ticks. + ///@param actualSegmentLengthTicks The length of the requested segment in ticks. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The desired segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param maxWidth Optional. The maximum horizontal resolution of the encoded video. + ///@param maxHeight Optional. The maximum vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + @Get(path: '/Videos/{itemId}/hls1/{playlistId}/{segmentId}.{container}') + Future> + _videosItemIdHls1PlaylistIdSegmentIdContainerGet({ + @Path('itemId') required String? itemId, + @Path('playlistId') required String? playlistId, + @Path('segmentId') required int? segmentId, + @Path('container') required String? container, + @Query('runtimeTicks') required int? runtimeTicks, + @Query('actualSegmentLengthTicks') required int? actualSegmentLengthTicks, + @Query('static') bool? $static, + @Query('params') String? params, + @Query('tag') String? tag, + @Query('deviceProfileId') String? deviceProfileId, + @Query('playSessionId') String? playSessionId, + @Query('segmentContainer') String? segmentContainer, + @Query('segmentLength') int? segmentLength, + @Query('minSegments') int? minSegments, + @Query('mediaSourceId') String? mediaSourceId, + @Query('deviceId') String? deviceId, + @Query('audioCodec') String? audioCodec, + @Query('enableAutoStreamCopy') bool? enableAutoStreamCopy, + @Query('allowVideoStreamCopy') bool? allowVideoStreamCopy, + @Query('allowAudioStreamCopy') bool? allowAudioStreamCopy, + @Query('breakOnNonKeyFrames') bool? breakOnNonKeyFrames, + @Query('audioSampleRate') int? audioSampleRate, + @Query('maxAudioBitDepth') int? maxAudioBitDepth, + @Query('audioBitRate') int? audioBitRate, + @Query('audioChannels') int? audioChannels, + @Query('maxAudioChannels') int? maxAudioChannels, + @Query('profile') String? profile, + @Query('level') String? level, + @Query('framerate') num? framerate, + @Query('maxFramerate') num? maxFramerate, + @Query('copyTimestamps') bool? copyTimestamps, + @Query('startTimeTicks') int? startTimeTicks, + @Query('width') int? width, + @Query('height') int? height, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('videoBitRate') int? videoBitRate, + @Query('subtitleStreamIndex') int? subtitleStreamIndex, + @Query('subtitleMethod') String? subtitleMethod, + @Query('maxRefFrames') int? maxRefFrames, + @Query('maxVideoBitDepth') int? maxVideoBitDepth, + @Query('requireAvc') bool? requireAvc, + @Query('deInterlace') bool? deInterlace, + @Query('requireNonAnamorphic') bool? requireNonAnamorphic, + @Query('transcodingMaxAudioChannels') int? transcodingMaxAudioChannels, + @Query('cpuCoreLimit') int? cpuCoreLimit, + @Query('liveStreamId') String? liveStreamId, + @Query('enableMpegtsM2TsMode') bool? enableMpegtsM2TsMode, + @Query('videoCodec') String? videoCodec, + @Query('subtitleCodec') String? subtitleCodec, + @Query('transcodeReasons') String? transcodeReasons, + @Query('audioStreamIndex') int? audioStreamIndex, + @Query('videoStreamIndex') int? videoStreamIndex, + @Query('context') String? context, + @Query('streamOptions') Object? streamOptions, + }); + + ///Gets a hls live stream. + ///@param itemId The item id. + ///@param container The audio container. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + ///@param maxWidth Optional. The max width. + ///@param maxHeight Optional. The max height. + ///@param enableSubtitlesInManifest Optional. Whether to enable subtitles in the manifest. + Future> videosItemIdLiveM3u8Get({ + required String? itemId, + String? container, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? videoBitRate, + int? subtitleStreamIndex, + enums.VideosItemIdLiveM3u8GetSubtitleMethod? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + enums.VideosItemIdLiveM3u8GetContext? context, + Object? streamOptions, + int? maxWidth, + int? maxHeight, + bool? enableSubtitlesInManifest, + }) { + return _videosItemIdLiveM3u8Get( + itemId: itemId, + container: container, + $static: $static, + params: params, + tag: tag, + deviceProfileId: deviceProfileId, + playSessionId: playSessionId, + segmentContainer: segmentContainer, + segmentLength: segmentLength, + minSegments: minSegments, + mediaSourceId: mediaSourceId, + deviceId: deviceId, + audioCodec: audioCodec, + enableAutoStreamCopy: enableAutoStreamCopy, + allowVideoStreamCopy: allowVideoStreamCopy, + allowAudioStreamCopy: allowAudioStreamCopy, + breakOnNonKeyFrames: breakOnNonKeyFrames, + audioSampleRate: audioSampleRate, + maxAudioBitDepth: maxAudioBitDepth, + audioBitRate: audioBitRate, + audioChannels: audioChannels, + maxAudioChannels: maxAudioChannels, + profile: profile, + level: level, + framerate: framerate, + maxFramerate: maxFramerate, + copyTimestamps: copyTimestamps, + startTimeTicks: startTimeTicks, + width: width, + height: height, + videoBitRate: videoBitRate, + subtitleStreamIndex: subtitleStreamIndex, + subtitleMethod: subtitleMethod?.value?.toString(), + maxRefFrames: maxRefFrames, + maxVideoBitDepth: maxVideoBitDepth, + requireAvc: requireAvc, + deInterlace: deInterlace, + requireNonAnamorphic: requireNonAnamorphic, + transcodingMaxAudioChannels: transcodingMaxAudioChannels, + cpuCoreLimit: cpuCoreLimit, + liveStreamId: liveStreamId, + enableMpegtsM2TsMode: enableMpegtsM2TsMode, + videoCodec: videoCodec, + subtitleCodec: subtitleCodec, + transcodeReasons: transcodeReasons, + audioStreamIndex: audioStreamIndex, + videoStreamIndex: videoStreamIndex, + context: context?.value?.toString(), + streamOptions: streamOptions, + maxWidth: maxWidth, + maxHeight: maxHeight, + enableSubtitlesInManifest: enableSubtitlesInManifest); + } + + ///Gets a hls live stream. + ///@param itemId The item id. + ///@param container The audio container. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + ///@param maxWidth Optional. The max width. + ///@param maxHeight Optional. The max height. + ///@param enableSubtitlesInManifest Optional. Whether to enable subtitles in the manifest. + @Get(path: '/Videos/{itemId}/live.m3u8') + Future> _videosItemIdLiveM3u8Get({ + @Path('itemId') required String? itemId, + @Query('container') String? container, + @Query('static') bool? $static, + @Query('params') String? params, + @Query('tag') String? tag, + @Query('deviceProfileId') String? deviceProfileId, + @Query('playSessionId') String? playSessionId, + @Query('segmentContainer') String? segmentContainer, + @Query('segmentLength') int? segmentLength, + @Query('minSegments') int? minSegments, + @Query('mediaSourceId') String? mediaSourceId, + @Query('deviceId') String? deviceId, + @Query('audioCodec') String? audioCodec, + @Query('enableAutoStreamCopy') bool? enableAutoStreamCopy, + @Query('allowVideoStreamCopy') bool? allowVideoStreamCopy, + @Query('allowAudioStreamCopy') bool? allowAudioStreamCopy, + @Query('breakOnNonKeyFrames') bool? breakOnNonKeyFrames, + @Query('audioSampleRate') int? audioSampleRate, + @Query('maxAudioBitDepth') int? maxAudioBitDepth, + @Query('audioBitRate') int? audioBitRate, + @Query('audioChannels') int? audioChannels, + @Query('maxAudioChannels') int? maxAudioChannels, + @Query('profile') String? profile, + @Query('level') String? level, + @Query('framerate') num? framerate, + @Query('maxFramerate') num? maxFramerate, + @Query('copyTimestamps') bool? copyTimestamps, + @Query('startTimeTicks') int? startTimeTicks, + @Query('width') int? width, + @Query('height') int? height, + @Query('videoBitRate') int? videoBitRate, + @Query('subtitleStreamIndex') int? subtitleStreamIndex, + @Query('subtitleMethod') String? subtitleMethod, + @Query('maxRefFrames') int? maxRefFrames, + @Query('maxVideoBitDepth') int? maxVideoBitDepth, + @Query('requireAvc') bool? requireAvc, + @Query('deInterlace') bool? deInterlace, + @Query('requireNonAnamorphic') bool? requireNonAnamorphic, + @Query('transcodingMaxAudioChannels') int? transcodingMaxAudioChannels, + @Query('cpuCoreLimit') int? cpuCoreLimit, + @Query('liveStreamId') String? liveStreamId, + @Query('enableMpegtsM2TsMode') bool? enableMpegtsM2TsMode, + @Query('videoCodec') String? videoCodec, + @Query('subtitleCodec') String? subtitleCodec, + @Query('transcodeReasons') String? transcodeReasons, + @Query('audioStreamIndex') int? audioStreamIndex, + @Query('videoStreamIndex') int? videoStreamIndex, + @Query('context') String? context, + @Query('streamOptions') Object? streamOptions, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('enableSubtitlesInManifest') bool? enableSubtitlesInManifest, + }); + + ///Gets a video stream using HTTP live streaming. + ///@param itemId The item id. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param maxWidth Optional. The maximum horizontal resolution of the encoded video. + ///@param maxHeight Optional. The maximum vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + Future> videosItemIdMainM3u8Get({ + required String? itemId, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? maxWidth, + int? maxHeight, + int? videoBitRate, + int? subtitleStreamIndex, + enums.VideosItemIdMainM3u8GetSubtitleMethod? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + enums.VideosItemIdMainM3u8GetContext? context, + Object? streamOptions, + }) { + return _videosItemIdMainM3u8Get( + itemId: itemId, + $static: $static, + params: params, + tag: tag, + deviceProfileId: deviceProfileId, + playSessionId: playSessionId, + segmentContainer: segmentContainer, + segmentLength: segmentLength, + minSegments: minSegments, + mediaSourceId: mediaSourceId, + deviceId: deviceId, + audioCodec: audioCodec, + enableAutoStreamCopy: enableAutoStreamCopy, + allowVideoStreamCopy: allowVideoStreamCopy, + allowAudioStreamCopy: allowAudioStreamCopy, + breakOnNonKeyFrames: breakOnNonKeyFrames, + audioSampleRate: audioSampleRate, + maxAudioBitDepth: maxAudioBitDepth, + audioBitRate: audioBitRate, + audioChannels: audioChannels, + maxAudioChannels: maxAudioChannels, + profile: profile, + level: level, + framerate: framerate, + maxFramerate: maxFramerate, + copyTimestamps: copyTimestamps, + startTimeTicks: startTimeTicks, + width: width, + height: height, + maxWidth: maxWidth, + maxHeight: maxHeight, + videoBitRate: videoBitRate, + subtitleStreamIndex: subtitleStreamIndex, + subtitleMethod: subtitleMethod?.value?.toString(), + maxRefFrames: maxRefFrames, + maxVideoBitDepth: maxVideoBitDepth, + requireAvc: requireAvc, + deInterlace: deInterlace, + requireNonAnamorphic: requireNonAnamorphic, + transcodingMaxAudioChannels: transcodingMaxAudioChannels, + cpuCoreLimit: cpuCoreLimit, + liveStreamId: liveStreamId, + enableMpegtsM2TsMode: enableMpegtsM2TsMode, + videoCodec: videoCodec, + subtitleCodec: subtitleCodec, + transcodeReasons: transcodeReasons, + audioStreamIndex: audioStreamIndex, + videoStreamIndex: videoStreamIndex, + context: context?.value?.toString(), + streamOptions: streamOptions); + } + + ///Gets a video stream using HTTP live streaming. + ///@param itemId The item id. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param maxWidth Optional. The maximum horizontal resolution of the encoded video. + ///@param maxHeight Optional. The maximum vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + @Get(path: '/Videos/{itemId}/main.m3u8') + Future> _videosItemIdMainM3u8Get({ + @Path('itemId') required String? itemId, + @Query('static') bool? $static, + @Query('params') String? params, + @Query('tag') String? tag, + @Query('deviceProfileId') String? deviceProfileId, + @Query('playSessionId') String? playSessionId, + @Query('segmentContainer') String? segmentContainer, + @Query('segmentLength') int? segmentLength, + @Query('minSegments') int? minSegments, + @Query('mediaSourceId') String? mediaSourceId, + @Query('deviceId') String? deviceId, + @Query('audioCodec') String? audioCodec, + @Query('enableAutoStreamCopy') bool? enableAutoStreamCopy, + @Query('allowVideoStreamCopy') bool? allowVideoStreamCopy, + @Query('allowAudioStreamCopy') bool? allowAudioStreamCopy, + @Query('breakOnNonKeyFrames') bool? breakOnNonKeyFrames, + @Query('audioSampleRate') int? audioSampleRate, + @Query('maxAudioBitDepth') int? maxAudioBitDepth, + @Query('audioBitRate') int? audioBitRate, + @Query('audioChannels') int? audioChannels, + @Query('maxAudioChannels') int? maxAudioChannels, + @Query('profile') String? profile, + @Query('level') String? level, + @Query('framerate') num? framerate, + @Query('maxFramerate') num? maxFramerate, + @Query('copyTimestamps') bool? copyTimestamps, + @Query('startTimeTicks') int? startTimeTicks, + @Query('width') int? width, + @Query('height') int? height, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('videoBitRate') int? videoBitRate, + @Query('subtitleStreamIndex') int? subtitleStreamIndex, + @Query('subtitleMethod') String? subtitleMethod, + @Query('maxRefFrames') int? maxRefFrames, + @Query('maxVideoBitDepth') int? maxVideoBitDepth, + @Query('requireAvc') bool? requireAvc, + @Query('deInterlace') bool? deInterlace, + @Query('requireNonAnamorphic') bool? requireNonAnamorphic, + @Query('transcodingMaxAudioChannels') int? transcodingMaxAudioChannels, + @Query('cpuCoreLimit') int? cpuCoreLimit, + @Query('liveStreamId') String? liveStreamId, + @Query('enableMpegtsM2TsMode') bool? enableMpegtsM2TsMode, + @Query('videoCodec') String? videoCodec, + @Query('subtitleCodec') String? subtitleCodec, + @Query('transcodeReasons') String? transcodeReasons, + @Query('audioStreamIndex') int? audioStreamIndex, + @Query('videoStreamIndex') int? videoStreamIndex, + @Query('context') String? context, + @Query('streamOptions') Object? streamOptions, + }); + + ///Gets a video hls playlist stream. + ///@param itemId The item id. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param maxWidth Optional. The maximum horizontal resolution of the encoded video. + ///@param maxHeight Optional. The maximum vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + ///@param enableAdaptiveBitrateStreaming Enable adaptive bitrate streaming. + ///@param enableTrickplay Enable trickplay image playlists being added to master playlist. + Future> videosItemIdMasterM3u8Get({ + required String? itemId, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + required String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? maxWidth, + int? maxHeight, + int? videoBitRate, + int? subtitleStreamIndex, + enums.VideosItemIdMasterM3u8GetSubtitleMethod? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + enums.VideosItemIdMasterM3u8GetContext? context, + Object? streamOptions, + bool? enableAdaptiveBitrateStreaming, + bool? enableTrickplay, + }) { + return _videosItemIdMasterM3u8Get( + itemId: itemId, + $static: $static, + params: params, + tag: tag, + deviceProfileId: deviceProfileId, + playSessionId: playSessionId, + segmentContainer: segmentContainer, + segmentLength: segmentLength, + minSegments: minSegments, + mediaSourceId: mediaSourceId, + deviceId: deviceId, + audioCodec: audioCodec, + enableAutoStreamCopy: enableAutoStreamCopy, + allowVideoStreamCopy: allowVideoStreamCopy, + allowAudioStreamCopy: allowAudioStreamCopy, + breakOnNonKeyFrames: breakOnNonKeyFrames, + audioSampleRate: audioSampleRate, + maxAudioBitDepth: maxAudioBitDepth, + audioBitRate: audioBitRate, + audioChannels: audioChannels, + maxAudioChannels: maxAudioChannels, + profile: profile, + level: level, + framerate: framerate, + maxFramerate: maxFramerate, + copyTimestamps: copyTimestamps, + startTimeTicks: startTimeTicks, + width: width, + height: height, + maxWidth: maxWidth, + maxHeight: maxHeight, + videoBitRate: videoBitRate, + subtitleStreamIndex: subtitleStreamIndex, + subtitleMethod: subtitleMethod?.value?.toString(), + maxRefFrames: maxRefFrames, + maxVideoBitDepth: maxVideoBitDepth, + requireAvc: requireAvc, + deInterlace: deInterlace, + requireNonAnamorphic: requireNonAnamorphic, + transcodingMaxAudioChannels: transcodingMaxAudioChannels, + cpuCoreLimit: cpuCoreLimit, + liveStreamId: liveStreamId, + enableMpegtsM2TsMode: enableMpegtsM2TsMode, + videoCodec: videoCodec, + subtitleCodec: subtitleCodec, + transcodeReasons: transcodeReasons, + audioStreamIndex: audioStreamIndex, + videoStreamIndex: videoStreamIndex, + context: context?.value?.toString(), + streamOptions: streamOptions, + enableAdaptiveBitrateStreaming: enableAdaptiveBitrateStreaming, + enableTrickplay: enableTrickplay); + } + + ///Gets a video hls playlist stream. + ///@param itemId The item id. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param maxWidth Optional. The maximum horizontal resolution of the encoded video. + ///@param maxHeight Optional. The maximum vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + ///@param enableAdaptiveBitrateStreaming Enable adaptive bitrate streaming. + ///@param enableTrickplay Enable trickplay image playlists being added to master playlist. + @Get(path: '/Videos/{itemId}/master.m3u8') + Future> _videosItemIdMasterM3u8Get({ + @Path('itemId') required String? itemId, + @Query('static') bool? $static, + @Query('params') String? params, + @Query('tag') String? tag, + @Query('deviceProfileId') String? deviceProfileId, + @Query('playSessionId') String? playSessionId, + @Query('segmentContainer') String? segmentContainer, + @Query('segmentLength') int? segmentLength, + @Query('minSegments') int? minSegments, + @Query('mediaSourceId') required String? mediaSourceId, + @Query('deviceId') String? deviceId, + @Query('audioCodec') String? audioCodec, + @Query('enableAutoStreamCopy') bool? enableAutoStreamCopy, + @Query('allowVideoStreamCopy') bool? allowVideoStreamCopy, + @Query('allowAudioStreamCopy') bool? allowAudioStreamCopy, + @Query('breakOnNonKeyFrames') bool? breakOnNonKeyFrames, + @Query('audioSampleRate') int? audioSampleRate, + @Query('maxAudioBitDepth') int? maxAudioBitDepth, + @Query('audioBitRate') int? audioBitRate, + @Query('audioChannels') int? audioChannels, + @Query('maxAudioChannels') int? maxAudioChannels, + @Query('profile') String? profile, + @Query('level') String? level, + @Query('framerate') num? framerate, + @Query('maxFramerate') num? maxFramerate, + @Query('copyTimestamps') bool? copyTimestamps, + @Query('startTimeTicks') int? startTimeTicks, + @Query('width') int? width, + @Query('height') int? height, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('videoBitRate') int? videoBitRate, + @Query('subtitleStreamIndex') int? subtitleStreamIndex, + @Query('subtitleMethod') String? subtitleMethod, + @Query('maxRefFrames') int? maxRefFrames, + @Query('maxVideoBitDepth') int? maxVideoBitDepth, + @Query('requireAvc') bool? requireAvc, + @Query('deInterlace') bool? deInterlace, + @Query('requireNonAnamorphic') bool? requireNonAnamorphic, + @Query('transcodingMaxAudioChannels') int? transcodingMaxAudioChannels, + @Query('cpuCoreLimit') int? cpuCoreLimit, + @Query('liveStreamId') String? liveStreamId, + @Query('enableMpegtsM2TsMode') bool? enableMpegtsM2TsMode, + @Query('videoCodec') String? videoCodec, + @Query('subtitleCodec') String? subtitleCodec, + @Query('transcodeReasons') String? transcodeReasons, + @Query('audioStreamIndex') int? audioStreamIndex, + @Query('videoStreamIndex') int? videoStreamIndex, + @Query('context') String? context, + @Query('streamOptions') Object? streamOptions, + @Query('enableAdaptiveBitrateStreaming') + bool? enableAdaptiveBitrateStreaming, + @Query('enableTrickplay') bool? enableTrickplay, + }); + + ///Gets a video hls playlist stream. + ///@param itemId The item id. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param maxWidth Optional. The maximum horizontal resolution of the encoded video. + ///@param maxHeight Optional. The maximum vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + ///@param enableAdaptiveBitrateStreaming Enable adaptive bitrate streaming. + ///@param enableTrickplay Enable trickplay image playlists being added to master playlist. + Future> videosItemIdMasterM3u8Head({ + required String? itemId, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + required String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? maxWidth, + int? maxHeight, + int? videoBitRate, + int? subtitleStreamIndex, + enums.VideosItemIdMasterM3u8HeadSubtitleMethod? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + enums.VideosItemIdMasterM3u8HeadContext? context, + Object? streamOptions, + bool? enableAdaptiveBitrateStreaming, + bool? enableTrickplay, + }) { + return _videosItemIdMasterM3u8Head( + itemId: itemId, + $static: $static, + params: params, + tag: tag, + deviceProfileId: deviceProfileId, + playSessionId: playSessionId, + segmentContainer: segmentContainer, + segmentLength: segmentLength, + minSegments: minSegments, + mediaSourceId: mediaSourceId, + deviceId: deviceId, + audioCodec: audioCodec, + enableAutoStreamCopy: enableAutoStreamCopy, + allowVideoStreamCopy: allowVideoStreamCopy, + allowAudioStreamCopy: allowAudioStreamCopy, + breakOnNonKeyFrames: breakOnNonKeyFrames, + audioSampleRate: audioSampleRate, + maxAudioBitDepth: maxAudioBitDepth, + audioBitRate: audioBitRate, + audioChannels: audioChannels, + maxAudioChannels: maxAudioChannels, + profile: profile, + level: level, + framerate: framerate, + maxFramerate: maxFramerate, + copyTimestamps: copyTimestamps, + startTimeTicks: startTimeTicks, + width: width, + height: height, + maxWidth: maxWidth, + maxHeight: maxHeight, + videoBitRate: videoBitRate, + subtitleStreamIndex: subtitleStreamIndex, + subtitleMethod: subtitleMethod?.value?.toString(), + maxRefFrames: maxRefFrames, + maxVideoBitDepth: maxVideoBitDepth, + requireAvc: requireAvc, + deInterlace: deInterlace, + requireNonAnamorphic: requireNonAnamorphic, + transcodingMaxAudioChannels: transcodingMaxAudioChannels, + cpuCoreLimit: cpuCoreLimit, + liveStreamId: liveStreamId, + enableMpegtsM2TsMode: enableMpegtsM2TsMode, + videoCodec: videoCodec, + subtitleCodec: subtitleCodec, + transcodeReasons: transcodeReasons, + audioStreamIndex: audioStreamIndex, + videoStreamIndex: videoStreamIndex, + context: context?.value?.toString(), + streamOptions: streamOptions, + enableAdaptiveBitrateStreaming: enableAdaptiveBitrateStreaming, + enableTrickplay: enableTrickplay); + } + + ///Gets a video hls playlist stream. + ///@param itemId The item id. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param maxWidth Optional. The maximum horizontal resolution of the encoded video. + ///@param maxHeight Optional. The maximum vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + ///@param enableAdaptiveBitrateStreaming Enable adaptive bitrate streaming. + ///@param enableTrickplay Enable trickplay image playlists being added to master playlist. + @Head(path: '/Videos/{itemId}/master.m3u8') + Future> _videosItemIdMasterM3u8Head({ + @Path('itemId') required String? itemId, + @Query('static') bool? $static, + @Query('params') String? params, + @Query('tag') String? tag, + @Query('deviceProfileId') String? deviceProfileId, + @Query('playSessionId') String? playSessionId, + @Query('segmentContainer') String? segmentContainer, + @Query('segmentLength') int? segmentLength, + @Query('minSegments') int? minSegments, + @Query('mediaSourceId') required String? mediaSourceId, + @Query('deviceId') String? deviceId, + @Query('audioCodec') String? audioCodec, + @Query('enableAutoStreamCopy') bool? enableAutoStreamCopy, + @Query('allowVideoStreamCopy') bool? allowVideoStreamCopy, + @Query('allowAudioStreamCopy') bool? allowAudioStreamCopy, + @Query('breakOnNonKeyFrames') bool? breakOnNonKeyFrames, + @Query('audioSampleRate') int? audioSampleRate, + @Query('maxAudioBitDepth') int? maxAudioBitDepth, + @Query('audioBitRate') int? audioBitRate, + @Query('audioChannels') int? audioChannels, + @Query('maxAudioChannels') int? maxAudioChannels, + @Query('profile') String? profile, + @Query('level') String? level, + @Query('framerate') num? framerate, + @Query('maxFramerate') num? maxFramerate, + @Query('copyTimestamps') bool? copyTimestamps, + @Query('startTimeTicks') int? startTimeTicks, + @Query('width') int? width, + @Query('height') int? height, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('videoBitRate') int? videoBitRate, + @Query('subtitleStreamIndex') int? subtitleStreamIndex, + @Query('subtitleMethod') String? subtitleMethod, + @Query('maxRefFrames') int? maxRefFrames, + @Query('maxVideoBitDepth') int? maxVideoBitDepth, + @Query('requireAvc') bool? requireAvc, + @Query('deInterlace') bool? deInterlace, + @Query('requireNonAnamorphic') bool? requireNonAnamorphic, + @Query('transcodingMaxAudioChannels') int? transcodingMaxAudioChannels, + @Query('cpuCoreLimit') int? cpuCoreLimit, + @Query('liveStreamId') String? liveStreamId, + @Query('enableMpegtsM2TsMode') bool? enableMpegtsM2TsMode, + @Query('videoCodec') String? videoCodec, + @Query('subtitleCodec') String? subtitleCodec, + @Query('transcodeReasons') String? transcodeReasons, + @Query('audioStreamIndex') int? audioStreamIndex, + @Query('videoStreamIndex') int? videoStreamIndex, + @Query('context') String? context, + @Query('streamOptions') Object? streamOptions, + @Query('enableAdaptiveBitrateStreaming') + bool? enableAdaptiveBitrateStreaming, + @Query('enableTrickplay') bool? enableTrickplay, + }); + + ///Get Default directory browser. + Future> + environmentDefaultDirectoryBrowserGet() { + generatedMapping.putIfAbsent(DefaultDirectoryBrowserInfoDto, + () => DefaultDirectoryBrowserInfoDto.fromJsonFactory); + + return _environmentDefaultDirectoryBrowserGet(); + } + + ///Get Default directory browser. + @Get(path: '/Environment/DefaultDirectoryBrowser') + Future> + _environmentDefaultDirectoryBrowserGet(); + + ///Gets the contents of a given directory in the file system. + ///@param path The path. + ///@param includeFiles An optional filter to include or exclude files from the results. true/false. + ///@param includeDirectories An optional filter to include or exclude folders from the results. true/false. + Future>> + environmentDirectoryContentsGet({ + required String? path, + bool? includeFiles, + bool? includeDirectories, + }) { + generatedMapping.putIfAbsent( + FileSystemEntryInfo, () => FileSystemEntryInfo.fromJsonFactory); + + return _environmentDirectoryContentsGet( + path: path, + includeFiles: includeFiles, + includeDirectories: includeDirectories); + } + + ///Gets the contents of a given directory in the file system. + ///@param path The path. + ///@param includeFiles An optional filter to include or exclude files from the results. true/false. + ///@param includeDirectories An optional filter to include or exclude folders from the results. true/false. + @Get(path: '/Environment/DirectoryContents') + Future>> + _environmentDirectoryContentsGet({ + @Query('path') required String? path, + @Query('includeFiles') bool? includeFiles, + @Query('includeDirectories') bool? includeDirectories, + }); + + ///Gets available drives from the server's file system. + Future>> environmentDrivesGet() { + generatedMapping.putIfAbsent( + FileSystemEntryInfo, () => FileSystemEntryInfo.fromJsonFactory); + + return _environmentDrivesGet(); + } + + ///Gets available drives from the server's file system. + @Get(path: '/Environment/Drives') + Future>> _environmentDrivesGet(); + + ///Gets network paths. + @deprecated + Future>> + environmentNetworkSharesGet() { + generatedMapping.putIfAbsent( + FileSystemEntryInfo, () => FileSystemEntryInfo.fromJsonFactory); + + return _environmentNetworkSharesGet(); + } + + ///Gets network paths. + @deprecated + @Get(path: '/Environment/NetworkShares') + Future>> + _environmentNetworkSharesGet(); + + ///Gets the parent path of a given path. + ///@param path The path. + Future> environmentParentPathGet( + {required String? path}) { + return _environmentParentPathGet(path: path); + } + + ///Gets the parent path of a given path. + ///@param path The path. + @Get(path: '/Environment/ParentPath') + Future> _environmentParentPathGet( + {@Query('path') required String? path}); + + ///Validates path. + Future environmentValidatePathPost( + {required ValidatePathDto? body}) { + return _environmentValidatePathPost(body: body); + } + + ///Validates path. + @Post( + path: '/Environment/ValidatePath', + optionalBody: true, + ) + Future _environmentValidatePathPost( + {@Body() required ValidatePathDto? body}); + + ///Gets legacy query filters. + ///@param userId Optional. User id. + ///@param parentId Optional. Parent id. + ///@param includeItemTypes Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited. + ///@param mediaTypes Optional. Filter by MediaType. Allows multiple, comma delimited. + Future> itemsFiltersGet({ + String? userId, + String? parentId, + List? includeItemTypes, + List? mediaTypes, + }) { + generatedMapping.putIfAbsent( + QueryFiltersLegacy, () => QueryFiltersLegacy.fromJsonFactory); + + return _itemsFiltersGet( + userId: userId, + parentId: parentId, + includeItemTypes: baseItemKindListToJson(includeItemTypes), + mediaTypes: mediaTypeListToJson(mediaTypes)); + } + + ///Gets legacy query filters. + ///@param userId Optional. User id. + ///@param parentId Optional. Parent id. + ///@param includeItemTypes Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited. + ///@param mediaTypes Optional. Filter by MediaType. Allows multiple, comma delimited. + @Get(path: '/Items/Filters') + Future> _itemsFiltersGet({ + @Query('userId') String? userId, + @Query('parentId') String? parentId, + @Query('includeItemTypes') List? includeItemTypes, + @Query('mediaTypes') List? mediaTypes, + }); + + ///Gets query filters. + ///@param userId Optional. User id. + ///@param parentId Optional. Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param includeItemTypes Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited. + ///@param isAiring Optional. Is item airing. + ///@param isMovie Optional. Is item movie. + ///@param isSports Optional. Is item sports. + ///@param isKids Optional. Is item kids. + ///@param isNews Optional. Is item news. + ///@param isSeries Optional. Is item series. + ///@param recursive Optional. Search recursive. + Future> itemsFilters2Get({ + String? userId, + String? parentId, + List? includeItemTypes, + bool? isAiring, + bool? isMovie, + bool? isSports, + bool? isKids, + bool? isNews, + bool? isSeries, + bool? recursive, + }) { + generatedMapping.putIfAbsent( + QueryFilters, () => QueryFilters.fromJsonFactory); + + return _itemsFilters2Get( + userId: userId, + parentId: parentId, + includeItemTypes: baseItemKindListToJson(includeItemTypes), + isAiring: isAiring, + isMovie: isMovie, + isSports: isSports, + isKids: isKids, + isNews: isNews, + isSeries: isSeries, + recursive: recursive); + } + + ///Gets query filters. + ///@param userId Optional. User id. + ///@param parentId Optional. Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param includeItemTypes Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited. + ///@param isAiring Optional. Is item airing. + ///@param isMovie Optional. Is item movie. + ///@param isSports Optional. Is item sports. + ///@param isKids Optional. Is item kids. + ///@param isNews Optional. Is item news. + ///@param isSeries Optional. Is item series. + ///@param recursive Optional. Search recursive. + @Get(path: '/Items/Filters2') + Future> _itemsFilters2Get({ + @Query('userId') String? userId, + @Query('parentId') String? parentId, + @Query('includeItemTypes') List? includeItemTypes, + @Query('isAiring') bool? isAiring, + @Query('isMovie') bool? isMovie, + @Query('isSports') bool? isSports, + @Query('isKids') bool? isKids, + @Query('isNews') bool? isNews, + @Query('isSeries') bool? isSeries, + @Query('recursive') bool? recursive, + }); + + ///Gets all genres from a given item, folder, or the entire library. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param searchTerm The search term. + ///@param parentId Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param excludeItemTypes Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited. + ///@param includeItemTypes Optional. If specified, results will be filtered in based on item type. This allows multiple, comma delimited. + ///@param isFavorite Optional filter by items that are marked as favorite, or not. + ///@param imageTypeLimit Optional, the max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param userId User id. + ///@param nameStartsWithOrGreater Optional filter by items whose name is sorted equally or greater than a given input string. + ///@param nameStartsWith Optional filter by items whose name is sorted equally than a given input string. + ///@param nameLessThan Optional filter by items whose name is equally or lesser than a given input string. + ///@param sortBy Optional. Specify one or more sort orders, comma delimited. + ///@param sortOrder Sort Order - Ascending,Descending. + ///@param enableImages Optional, include image information in output. + ///@param enableTotalRecordCount Optional. Include total record count. + Future> genresGet({ + int? startIndex, + int? limit, + String? searchTerm, + String? parentId, + List? fields, + List? excludeItemTypes, + List? includeItemTypes, + bool? isFavorite, + int? imageTypeLimit, + List? enableImageTypes, + String? userId, + String? nameStartsWithOrGreater, + String? nameStartsWith, + String? nameLessThan, + List? sortBy, + List? sortOrder, + bool? enableImages, + bool? enableTotalRecordCount, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _genresGet( + startIndex: startIndex, + limit: limit, + searchTerm: searchTerm, + parentId: parentId, + fields: itemFieldsListToJson(fields), + excludeItemTypes: baseItemKindListToJson(excludeItemTypes), + includeItemTypes: baseItemKindListToJson(includeItemTypes), + isFavorite: isFavorite, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes), + userId: userId, + nameStartsWithOrGreater: nameStartsWithOrGreater, + nameStartsWith: nameStartsWith, + nameLessThan: nameLessThan, + sortBy: itemSortByListToJson(sortBy), + sortOrder: sortOrderListToJson(sortOrder), + enableImages: enableImages, + enableTotalRecordCount: enableTotalRecordCount); + } + + ///Gets all genres from a given item, folder, or the entire library. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param searchTerm The search term. + ///@param parentId Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param excludeItemTypes Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited. + ///@param includeItemTypes Optional. If specified, results will be filtered in based on item type. This allows multiple, comma delimited. + ///@param isFavorite Optional filter by items that are marked as favorite, or not. + ///@param imageTypeLimit Optional, the max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param userId User id. + ///@param nameStartsWithOrGreater Optional filter by items whose name is sorted equally or greater than a given input string. + ///@param nameStartsWith Optional filter by items whose name is sorted equally than a given input string. + ///@param nameLessThan Optional filter by items whose name is equally or lesser than a given input string. + ///@param sortBy Optional. Specify one or more sort orders, comma delimited. + ///@param sortOrder Sort Order - Ascending,Descending. + ///@param enableImages Optional, include image information in output. + ///@param enableTotalRecordCount Optional. Include total record count. + @Get(path: '/Genres') + Future> _genresGet({ + @Query('startIndex') int? startIndex, + @Query('limit') int? limit, + @Query('searchTerm') String? searchTerm, + @Query('parentId') String? parentId, + @Query('fields') List? fields, + @Query('excludeItemTypes') List? excludeItemTypes, + @Query('includeItemTypes') List? includeItemTypes, + @Query('isFavorite') bool? isFavorite, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + @Query('userId') String? userId, + @Query('nameStartsWithOrGreater') String? nameStartsWithOrGreater, + @Query('nameStartsWith') String? nameStartsWith, + @Query('nameLessThan') String? nameLessThan, + @Query('sortBy') List? sortBy, + @Query('sortOrder') List? sortOrder, + @Query('enableImages') bool? enableImages, + @Query('enableTotalRecordCount') bool? enableTotalRecordCount, + }); + + ///Gets a genre, by name. + ///@param genreName The genre name. + ///@param userId The user id. + Future> genresGenreNameGet({ + required String? genreName, + String? userId, + }) { + generatedMapping.putIfAbsent( + BaseItemDto, () => BaseItemDto.fromJsonFactory); + + return _genresGenreNameGet(genreName: genreName, userId: userId); + } + + ///Gets a genre, by name. + ///@param genreName The genre name. + ///@param userId The user id. + @Get(path: '/Genres/{genreName}') + Future> _genresGenreNameGet({ + @Path('genreName') required String? genreName, + @Query('userId') String? userId, + }); + + ///Gets the specified audio segment for an audio item. + ///@param itemId The item id. + ///@param segmentId The segment id. + Future> audioItemIdHlsSegmentIdStreamAacGet({ + required String? itemId, + required String? segmentId, + }) { + return _audioItemIdHlsSegmentIdStreamAacGet( + itemId: itemId, segmentId: segmentId); + } + + ///Gets the specified audio segment for an audio item. + ///@param itemId The item id. + ///@param segmentId The segment id. + @Get(path: '/Audio/{itemId}/hls/{segmentId}/stream.aac') + Future> _audioItemIdHlsSegmentIdStreamAacGet({ + @Path('itemId') required String? itemId, + @Path('segmentId') required String? segmentId, + }); + + ///Gets the specified audio segment for an audio item. + ///@param itemId The item id. + ///@param segmentId The segment id. + Future> audioItemIdHlsSegmentIdStreamMp3Get({ + required String? itemId, + required String? segmentId, + }) { + return _audioItemIdHlsSegmentIdStreamMp3Get( + itemId: itemId, segmentId: segmentId); + } + + ///Gets the specified audio segment for an audio item. + ///@param itemId The item id. + ///@param segmentId The segment id. + @Get(path: '/Audio/{itemId}/hls/{segmentId}/stream.mp3') + Future> _audioItemIdHlsSegmentIdStreamMp3Get({ + @Path('itemId') required String? itemId, + @Path('segmentId') required String? segmentId, + }); + + ///Gets a hls video segment. + ///@param itemId The item id. + ///@param playlistId The playlist id. + ///@param segmentId The segment id. + ///@param segmentContainer The segment container. + Future> + videosItemIdHlsPlaylistIdSegmentIdSegmentContainerGet({ + required String? itemId, + required String? playlistId, + required String? segmentId, + required String? segmentContainer, + }) { + return _videosItemIdHlsPlaylistIdSegmentIdSegmentContainerGet( + itemId: itemId, + playlistId: playlistId, + segmentId: segmentId, + segmentContainer: segmentContainer); + } + + ///Gets a hls video segment. + ///@param itemId The item id. + ///@param playlistId The playlist id. + ///@param segmentId The segment id. + ///@param segmentContainer The segment container. + @Get(path: '/Videos/{itemId}/hls/{playlistId}/{segmentId}.{segmentContainer}') + Future> + _videosItemIdHlsPlaylistIdSegmentIdSegmentContainerGet({ + @Path('itemId') required String? itemId, + @Path('playlistId') required String? playlistId, + @Path('segmentId') required String? segmentId, + @Path('segmentContainer') required String? segmentContainer, + }); + + ///Gets a hls video playlist. + ///@param itemId The video id. + ///@param playlistId The playlist id. + Future> videosItemIdHlsPlaylistIdStreamM3u8Get({ + required String? itemId, + required String? playlistId, + }) { + return _videosItemIdHlsPlaylistIdStreamM3u8Get( + itemId: itemId, playlistId: playlistId); + } + + ///Gets a hls video playlist. + ///@param itemId The video id. + ///@param playlistId The playlist id. + @Get(path: '/Videos/{itemId}/hls/{playlistId}/stream.m3u8') + Future> _videosItemIdHlsPlaylistIdStreamM3u8Get({ + @Path('itemId') required String? itemId, + @Path('playlistId') required String? playlistId, + }); + + ///Stops an active encoding. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param playSessionId The play session id. + Future videosActiveEncodingsDelete({ + required String? deviceId, + required String? playSessionId, + }) { + return _videosActiveEncodingsDelete( + deviceId: deviceId, playSessionId: playSessionId); + } + + ///Stops an active encoding. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param playSessionId The play session id. + @Delete(path: '/Videos/ActiveEncodings') + Future _videosActiveEncodingsDelete({ + @Query('deviceId') required String? deviceId, + @Query('playSessionId') required String? playSessionId, + }); + + ///Get artist image by name. + ///@param name Artist name. + ///@param imageType Image type. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + Future> artistsNameImagesImageTypeImageIndexGet({ + required String? name, + required enums.ArtistsNameImagesImageTypeImageIndexGetImageType? imageType, + String? tag, + enums.ArtistsNameImagesImageTypeImageIndexGetFormat? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + required int? imageIndex, + }) { + return _artistsNameImagesImageTypeImageIndexGet( + name: name, + imageType: imageType?.value?.toString(), + tag: tag, + format: format?.value?.toString(), + maxWidth: maxWidth, + maxHeight: maxHeight, + percentPlayed: percentPlayed, + unplayedCount: unplayedCount, + width: width, + height: height, + quality: quality, + fillWidth: fillWidth, + fillHeight: fillHeight, + blur: blur, + backgroundColor: backgroundColor, + foregroundLayer: foregroundLayer, + imageIndex: imageIndex); + } + + ///Get artist image by name. + ///@param name Artist name. + ///@param imageType Image type. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + @Get(path: '/Artists/{name}/Images/{imageType}/{imageIndex}') + Future> _artistsNameImagesImageTypeImageIndexGet({ + @Path('name') required String? name, + @Path('imageType') required String? imageType, + @Query('tag') String? tag, + @Query('format') String? format, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('percentPlayed') num? percentPlayed, + @Query('unplayedCount') int? unplayedCount, + @Query('width') int? width, + @Query('height') int? height, + @Query('quality') int? quality, + @Query('fillWidth') int? fillWidth, + @Query('fillHeight') int? fillHeight, + @Query('blur') int? blur, + @Query('backgroundColor') String? backgroundColor, + @Query('foregroundLayer') String? foregroundLayer, + @Path('imageIndex') required int? imageIndex, + }); + + ///Get artist image by name. + ///@param name Artist name. + ///@param imageType Image type. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + Future> artistsNameImagesImageTypeImageIndexHead({ + required String? name, + required enums.ArtistsNameImagesImageTypeImageIndexHeadImageType? imageType, + String? tag, + enums.ArtistsNameImagesImageTypeImageIndexHeadFormat? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + required int? imageIndex, + }) { + return _artistsNameImagesImageTypeImageIndexHead( + name: name, + imageType: imageType?.value?.toString(), + tag: tag, + format: format?.value?.toString(), + maxWidth: maxWidth, + maxHeight: maxHeight, + percentPlayed: percentPlayed, + unplayedCount: unplayedCount, + width: width, + height: height, + quality: quality, + fillWidth: fillWidth, + fillHeight: fillHeight, + blur: blur, + backgroundColor: backgroundColor, + foregroundLayer: foregroundLayer, + imageIndex: imageIndex); + } + + ///Get artist image by name. + ///@param name Artist name. + ///@param imageType Image type. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + @Head(path: '/Artists/{name}/Images/{imageType}/{imageIndex}') + Future> _artistsNameImagesImageTypeImageIndexHead({ + @Path('name') required String? name, + @Path('imageType') required String? imageType, + @Query('tag') String? tag, + @Query('format') String? format, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('percentPlayed') num? percentPlayed, + @Query('unplayedCount') int? unplayedCount, + @Query('width') int? width, + @Query('height') int? height, + @Query('quality') int? quality, + @Query('fillWidth') int? fillWidth, + @Query('fillHeight') int? fillHeight, + @Query('blur') int? blur, + @Query('backgroundColor') String? backgroundColor, + @Query('foregroundLayer') String? foregroundLayer, + @Path('imageIndex') required int? imageIndex, + }); + + ///Generates or gets the splashscreen. + ///@param tag Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Blur image. + ///@param backgroundColor Apply a background color for transparent images. + ///@param foregroundLayer Apply a foreground layer on top of the image. + ///@param quality Quality setting, from 0-100. + Future> brandingSplashscreenGet({ + String? tag, + enums.BrandingSplashscreenGetFormat? format, + int? maxWidth, + int? maxHeight, + int? width, + int? height, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + int? quality, + }) { + return _brandingSplashscreenGet( + tag: tag, + format: format?.value?.toString(), + maxWidth: maxWidth, + maxHeight: maxHeight, + width: width, + height: height, + fillWidth: fillWidth, + fillHeight: fillHeight, + blur: blur, + backgroundColor: backgroundColor, + foregroundLayer: foregroundLayer, + quality: quality); + } + + ///Generates or gets the splashscreen. + ///@param tag Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Blur image. + ///@param backgroundColor Apply a background color for transparent images. + ///@param foregroundLayer Apply a foreground layer on top of the image. + ///@param quality Quality setting, from 0-100. + @Get(path: '/Branding/Splashscreen') + Future> _brandingSplashscreenGet({ + @Query('tag') String? tag, + @Query('format') String? format, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('width') int? width, + @Query('height') int? height, + @Query('fillWidth') int? fillWidth, + @Query('fillHeight') int? fillHeight, + @Query('blur') int? blur, + @Query('backgroundColor') String? backgroundColor, + @Query('foregroundLayer') String? foregroundLayer, + @Query('quality') int? quality, + }); + + ///Uploads a custom splashscreen. + ///The body is expected to the image contents base64 encoded. + Future brandingSplashscreenPost({required Object? body}) { + return _brandingSplashscreenPost(body: body); + } + + ///Uploads a custom splashscreen. + ///The body is expected to the image contents base64 encoded. + @Post( + path: '/Branding/Splashscreen', + optionalBody: true, + ) + Future _brandingSplashscreenPost( + {@Body() required Object? body}); + + ///Delete a custom splashscreen. + Future brandingSplashscreenDelete() { + return _brandingSplashscreenDelete(); + } + + ///Delete a custom splashscreen. + @Delete(path: '/Branding/Splashscreen') + Future _brandingSplashscreenDelete(); + + ///Get genre image by name. + ///@param name Genre name. + ///@param imageType Image type. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + Future> genresNameImagesImageTypeGet({ + required String? name, + required enums.GenresNameImagesImageTypeGetImageType? imageType, + String? tag, + enums.GenresNameImagesImageTypeGetFormat? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + int? imageIndex, + }) { + return _genresNameImagesImageTypeGet( + name: name, + imageType: imageType?.value?.toString(), + tag: tag, + format: format?.value?.toString(), + maxWidth: maxWidth, + maxHeight: maxHeight, + percentPlayed: percentPlayed, + unplayedCount: unplayedCount, + width: width, + height: height, + quality: quality, + fillWidth: fillWidth, + fillHeight: fillHeight, + blur: blur, + backgroundColor: backgroundColor, + foregroundLayer: foregroundLayer, + imageIndex: imageIndex); + } + + ///Get genre image by name. + ///@param name Genre name. + ///@param imageType Image type. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + @Get(path: '/Genres/{name}/Images/{imageType}') + Future> _genresNameImagesImageTypeGet({ + @Path('name') required String? name, + @Path('imageType') required String? imageType, + @Query('tag') String? tag, + @Query('format') String? format, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('percentPlayed') num? percentPlayed, + @Query('unplayedCount') int? unplayedCount, + @Query('width') int? width, + @Query('height') int? height, + @Query('quality') int? quality, + @Query('fillWidth') int? fillWidth, + @Query('fillHeight') int? fillHeight, + @Query('blur') int? blur, + @Query('backgroundColor') String? backgroundColor, + @Query('foregroundLayer') String? foregroundLayer, + @Query('imageIndex') int? imageIndex, + }); + + ///Get genre image by name. + ///@param name Genre name. + ///@param imageType Image type. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + Future> genresNameImagesImageTypeHead({ + required String? name, + required enums.GenresNameImagesImageTypeHeadImageType? imageType, + String? tag, + enums.GenresNameImagesImageTypeHeadFormat? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + int? imageIndex, + }) { + return _genresNameImagesImageTypeHead( + name: name, + imageType: imageType?.value?.toString(), + tag: tag, + format: format?.value?.toString(), + maxWidth: maxWidth, + maxHeight: maxHeight, + percentPlayed: percentPlayed, + unplayedCount: unplayedCount, + width: width, + height: height, + quality: quality, + fillWidth: fillWidth, + fillHeight: fillHeight, + blur: blur, + backgroundColor: backgroundColor, + foregroundLayer: foregroundLayer, + imageIndex: imageIndex); + } + + ///Get genre image by name. + ///@param name Genre name. + ///@param imageType Image type. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + @Head(path: '/Genres/{name}/Images/{imageType}') + Future> _genresNameImagesImageTypeHead({ + @Path('name') required String? name, + @Path('imageType') required String? imageType, + @Query('tag') String? tag, + @Query('format') String? format, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('percentPlayed') num? percentPlayed, + @Query('unplayedCount') int? unplayedCount, + @Query('width') int? width, + @Query('height') int? height, + @Query('quality') int? quality, + @Query('fillWidth') int? fillWidth, + @Query('fillHeight') int? fillHeight, + @Query('blur') int? blur, + @Query('backgroundColor') String? backgroundColor, + @Query('foregroundLayer') String? foregroundLayer, + @Query('imageIndex') int? imageIndex, + }); + + ///Get genre image by name. + ///@param name Genre name. + ///@param imageType Image type. + ///@param imageIndex Image index. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + Future> genresNameImagesImageTypeImageIndexGet({ + required String? name, + required enums.GenresNameImagesImageTypeImageIndexGetImageType? imageType, + required int? imageIndex, + String? tag, + enums.GenresNameImagesImageTypeImageIndexGetFormat? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + }) { + return _genresNameImagesImageTypeImageIndexGet( + name: name, + imageType: imageType?.value?.toString(), + imageIndex: imageIndex, + tag: tag, + format: format?.value?.toString(), + maxWidth: maxWidth, + maxHeight: maxHeight, + percentPlayed: percentPlayed, + unplayedCount: unplayedCount, + width: width, + height: height, + quality: quality, + fillWidth: fillWidth, + fillHeight: fillHeight, + blur: blur, + backgroundColor: backgroundColor, + foregroundLayer: foregroundLayer); + } + + ///Get genre image by name. + ///@param name Genre name. + ///@param imageType Image type. + ///@param imageIndex Image index. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + @Get(path: '/Genres/{name}/Images/{imageType}/{imageIndex}') + Future> _genresNameImagesImageTypeImageIndexGet({ + @Path('name') required String? name, + @Path('imageType') required String? imageType, + @Path('imageIndex') required int? imageIndex, + @Query('tag') String? tag, + @Query('format') String? format, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('percentPlayed') num? percentPlayed, + @Query('unplayedCount') int? unplayedCount, + @Query('width') int? width, + @Query('height') int? height, + @Query('quality') int? quality, + @Query('fillWidth') int? fillWidth, + @Query('fillHeight') int? fillHeight, + @Query('blur') int? blur, + @Query('backgroundColor') String? backgroundColor, + @Query('foregroundLayer') String? foregroundLayer, + }); + + ///Get genre image by name. + ///@param name Genre name. + ///@param imageType Image type. + ///@param imageIndex Image index. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + Future> genresNameImagesImageTypeImageIndexHead({ + required String? name, + required enums.GenresNameImagesImageTypeImageIndexHeadImageType? imageType, + required int? imageIndex, + String? tag, + enums.GenresNameImagesImageTypeImageIndexHeadFormat? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + }) { + return _genresNameImagesImageTypeImageIndexHead( + name: name, + imageType: imageType?.value?.toString(), + imageIndex: imageIndex, + tag: tag, + format: format?.value?.toString(), + maxWidth: maxWidth, + maxHeight: maxHeight, + percentPlayed: percentPlayed, + unplayedCount: unplayedCount, + width: width, + height: height, + quality: quality, + fillWidth: fillWidth, + fillHeight: fillHeight, + blur: blur, + backgroundColor: backgroundColor, + foregroundLayer: foregroundLayer); + } + + ///Get genre image by name. + ///@param name Genre name. + ///@param imageType Image type. + ///@param imageIndex Image index. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + @Head(path: '/Genres/{name}/Images/{imageType}/{imageIndex}') + Future> _genresNameImagesImageTypeImageIndexHead({ + @Path('name') required String? name, + @Path('imageType') required String? imageType, + @Path('imageIndex') required int? imageIndex, + @Query('tag') String? tag, + @Query('format') String? format, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('percentPlayed') num? percentPlayed, + @Query('unplayedCount') int? unplayedCount, + @Query('width') int? width, + @Query('height') int? height, + @Query('quality') int? quality, + @Query('fillWidth') int? fillWidth, + @Query('fillHeight') int? fillHeight, + @Query('blur') int? blur, + @Query('backgroundColor') String? backgroundColor, + @Query('foregroundLayer') String? foregroundLayer, + }); + + ///Get item image infos. + ///@param itemId Item id. + Future>> itemsItemIdImagesGet( + {required String? itemId}) { + generatedMapping.putIfAbsent(ImageInfo, () => ImageInfo.fromJsonFactory); + + return _itemsItemIdImagesGet(itemId: itemId); + } + + ///Get item image infos. + ///@param itemId Item id. + @Get(path: '/Items/{itemId}/Images') + Future>> _itemsItemIdImagesGet( + {@Path('itemId') required String? itemId}); + + ///Delete an item's image. + ///@param itemId Item id. + ///@param imageType Image type. + ///@param imageIndex The image index. + Future itemsItemIdImagesImageTypeDelete({ + required String? itemId, + required enums.ItemsItemIdImagesImageTypeDeleteImageType? imageType, + int? imageIndex, + }) { + return _itemsItemIdImagesImageTypeDelete( + itemId: itemId, + imageType: imageType?.value?.toString(), + imageIndex: imageIndex); + } + + ///Delete an item's image. + ///@param itemId Item id. + ///@param imageType Image type. + ///@param imageIndex The image index. + @Delete(path: '/Items/{itemId}/Images/{imageType}') + Future _itemsItemIdImagesImageTypeDelete({ + @Path('itemId') required String? itemId, + @Path('imageType') required String? imageType, + @Query('imageIndex') int? imageIndex, + }); + + ///Set item image. + ///@param itemId Item id. + ///@param imageType Image type. + Future itemsItemIdImagesImageTypePost({ + required String? itemId, + required enums.ItemsItemIdImagesImageTypePostImageType? imageType, + required Object? body, + }) { + return _itemsItemIdImagesImageTypePost( + itemId: itemId, imageType: imageType?.value?.toString(), body: body); + } + + ///Set item image. + ///@param itemId Item id. + ///@param imageType Image type. + @Post( + path: '/Items/{itemId}/Images/{imageType}', + optionalBody: true, + ) + Future _itemsItemIdImagesImageTypePost({ + @Path('itemId') required String? itemId, + @Path('imageType') required String? imageType, + @Body() required Object? body, + }); + + ///Gets the item's image. + ///@param itemId Item id. + ///@param imageType Image type. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Optional. The MediaBrowser.Model.Drawing.ImageFormat of the returned image. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + Future> itemsItemIdImagesImageTypeGet({ + required String? itemId, + required enums.ItemsItemIdImagesImageTypeGetImageType? imageType, + int? maxWidth, + int? maxHeight, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + String? tag, + enums.ItemsItemIdImagesImageTypeGetFormat? format, + num? percentPlayed, + int? unplayedCount, + int? blur, + String? backgroundColor, + String? foregroundLayer, + int? imageIndex, + }) { + return _itemsItemIdImagesImageTypeGet( + itemId: itemId, + imageType: imageType?.value?.toString(), + maxWidth: maxWidth, + maxHeight: maxHeight, + width: width, + height: height, + quality: quality, + fillWidth: fillWidth, + fillHeight: fillHeight, + tag: tag, + format: format?.value?.toString(), + percentPlayed: percentPlayed, + unplayedCount: unplayedCount, + blur: blur, + backgroundColor: backgroundColor, + foregroundLayer: foregroundLayer, + imageIndex: imageIndex); + } + + ///Gets the item's image. + ///@param itemId Item id. + ///@param imageType Image type. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Optional. The MediaBrowser.Model.Drawing.ImageFormat of the returned image. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + @Get(path: '/Items/{itemId}/Images/{imageType}') + Future> _itemsItemIdImagesImageTypeGet({ + @Path('itemId') required String? itemId, + @Path('imageType') required String? imageType, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('width') int? width, + @Query('height') int? height, + @Query('quality') int? quality, + @Query('fillWidth') int? fillWidth, + @Query('fillHeight') int? fillHeight, + @Query('tag') String? tag, + @Query('format') String? format, + @Query('percentPlayed') num? percentPlayed, + @Query('unplayedCount') int? unplayedCount, + @Query('blur') int? blur, + @Query('backgroundColor') String? backgroundColor, + @Query('foregroundLayer') String? foregroundLayer, + @Query('imageIndex') int? imageIndex, + }); + + ///Gets the item's image. + ///@param itemId Item id. + ///@param imageType Image type. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Optional. The MediaBrowser.Model.Drawing.ImageFormat of the returned image. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + Future> itemsItemIdImagesImageTypeHead({ + required String? itemId, + required enums.ItemsItemIdImagesImageTypeHeadImageType? imageType, + int? maxWidth, + int? maxHeight, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + String? tag, + enums.ItemsItemIdImagesImageTypeHeadFormat? format, + num? percentPlayed, + int? unplayedCount, + int? blur, + String? backgroundColor, + String? foregroundLayer, + int? imageIndex, + }) { + return _itemsItemIdImagesImageTypeHead( + itemId: itemId, + imageType: imageType?.value?.toString(), + maxWidth: maxWidth, + maxHeight: maxHeight, + width: width, + height: height, + quality: quality, + fillWidth: fillWidth, + fillHeight: fillHeight, + tag: tag, + format: format?.value?.toString(), + percentPlayed: percentPlayed, + unplayedCount: unplayedCount, + blur: blur, + backgroundColor: backgroundColor, + foregroundLayer: foregroundLayer, + imageIndex: imageIndex); + } + + ///Gets the item's image. + ///@param itemId Item id. + ///@param imageType Image type. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Optional. The MediaBrowser.Model.Drawing.ImageFormat of the returned image. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + @Head(path: '/Items/{itemId}/Images/{imageType}') + Future> _itemsItemIdImagesImageTypeHead({ + @Path('itemId') required String? itemId, + @Path('imageType') required String? imageType, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('width') int? width, + @Query('height') int? height, + @Query('quality') int? quality, + @Query('fillWidth') int? fillWidth, + @Query('fillHeight') int? fillHeight, + @Query('tag') String? tag, + @Query('format') String? format, + @Query('percentPlayed') num? percentPlayed, + @Query('unplayedCount') int? unplayedCount, + @Query('blur') int? blur, + @Query('backgroundColor') String? backgroundColor, + @Query('foregroundLayer') String? foregroundLayer, + @Query('imageIndex') int? imageIndex, + }); + + ///Delete an item's image. + ///@param itemId Item id. + ///@param imageType Image type. + ///@param imageIndex The image index. + Future itemsItemIdImagesImageTypeImageIndexDelete({ + required String? itemId, + required enums.ItemsItemIdImagesImageTypeImageIndexDeleteImageType? + imageType, + required int? imageIndex, + }) { + return _itemsItemIdImagesImageTypeImageIndexDelete( + itemId: itemId, + imageType: imageType?.value?.toString(), + imageIndex: imageIndex); + } + + ///Delete an item's image. + ///@param itemId Item id. + ///@param imageType Image type. + ///@param imageIndex The image index. + @Delete(path: '/Items/{itemId}/Images/{imageType}/{imageIndex}') + Future _itemsItemIdImagesImageTypeImageIndexDelete({ + @Path('itemId') required String? itemId, + @Path('imageType') required String? imageType, + @Path('imageIndex') required int? imageIndex, + }); + + ///Set item image. + ///@param itemId Item id. + ///@param imageType Image type. + ///@param imageIndex (Unused) Image index. + Future itemsItemIdImagesImageTypeImageIndexPost({ + required String? itemId, + required enums.ItemsItemIdImagesImageTypeImageIndexPostImageType? imageType, + required int? imageIndex, + required Object? body, + }) { + return _itemsItemIdImagesImageTypeImageIndexPost( + itemId: itemId, + imageType: imageType?.value?.toString(), + imageIndex: imageIndex, + body: body); + } + + ///Set item image. + ///@param itemId Item id. + ///@param imageType Image type. + ///@param imageIndex (Unused) Image index. + @Post( + path: '/Items/{itemId}/Images/{imageType}/{imageIndex}', + optionalBody: true, + ) + Future _itemsItemIdImagesImageTypeImageIndexPost({ + @Path('itemId') required String? itemId, + @Path('imageType') required String? imageType, + @Path('imageIndex') required int? imageIndex, + @Body() required Object? body, + }); + + ///Gets the item's image. + ///@param itemId Item id. + ///@param imageType Image type. + ///@param imageIndex Image index. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Optional. The MediaBrowser.Model.Drawing.ImageFormat of the returned image. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + Future> itemsItemIdImagesImageTypeImageIndexGet({ + required String? itemId, + required enums.ItemsItemIdImagesImageTypeImageIndexGetImageType? imageType, + required int? imageIndex, + int? maxWidth, + int? maxHeight, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + String? tag, + enums.ItemsItemIdImagesImageTypeImageIndexGetFormat? format, + num? percentPlayed, + int? unplayedCount, + int? blur, + String? backgroundColor, + String? foregroundLayer, + }) { + return _itemsItemIdImagesImageTypeImageIndexGet( + itemId: itemId, + imageType: imageType?.value?.toString(), + imageIndex: imageIndex, + maxWidth: maxWidth, + maxHeight: maxHeight, + width: width, + height: height, + quality: quality, + fillWidth: fillWidth, + fillHeight: fillHeight, + tag: tag, + format: format?.value?.toString(), + percentPlayed: percentPlayed, + unplayedCount: unplayedCount, + blur: blur, + backgroundColor: backgroundColor, + foregroundLayer: foregroundLayer); + } + + ///Gets the item's image. + ///@param itemId Item id. + ///@param imageType Image type. + ///@param imageIndex Image index. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Optional. The MediaBrowser.Model.Drawing.ImageFormat of the returned image. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + @Get(path: '/Items/{itemId}/Images/{imageType}/{imageIndex}') + Future> _itemsItemIdImagesImageTypeImageIndexGet({ + @Path('itemId') required String? itemId, + @Path('imageType') required String? imageType, + @Path('imageIndex') required int? imageIndex, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('width') int? width, + @Query('height') int? height, + @Query('quality') int? quality, + @Query('fillWidth') int? fillWidth, + @Query('fillHeight') int? fillHeight, + @Query('tag') String? tag, + @Query('format') String? format, + @Query('percentPlayed') num? percentPlayed, + @Query('unplayedCount') int? unplayedCount, + @Query('blur') int? blur, + @Query('backgroundColor') String? backgroundColor, + @Query('foregroundLayer') String? foregroundLayer, + }); + + ///Gets the item's image. + ///@param itemId Item id. + ///@param imageType Image type. + ///@param imageIndex Image index. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Optional. The MediaBrowser.Model.Drawing.ImageFormat of the returned image. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + Future> itemsItemIdImagesImageTypeImageIndexHead({ + required String? itemId, + required enums.ItemsItemIdImagesImageTypeImageIndexHeadImageType? imageType, + required int? imageIndex, + int? maxWidth, + int? maxHeight, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + String? tag, + enums.ItemsItemIdImagesImageTypeImageIndexHeadFormat? format, + num? percentPlayed, + int? unplayedCount, + int? blur, + String? backgroundColor, + String? foregroundLayer, + }) { + return _itemsItemIdImagesImageTypeImageIndexHead( + itemId: itemId, + imageType: imageType?.value?.toString(), + imageIndex: imageIndex, + maxWidth: maxWidth, + maxHeight: maxHeight, + width: width, + height: height, + quality: quality, + fillWidth: fillWidth, + fillHeight: fillHeight, + tag: tag, + format: format?.value?.toString(), + percentPlayed: percentPlayed, + unplayedCount: unplayedCount, + blur: blur, + backgroundColor: backgroundColor, + foregroundLayer: foregroundLayer); + } + + ///Gets the item's image. + ///@param itemId Item id. + ///@param imageType Image type. + ///@param imageIndex Image index. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Optional. The MediaBrowser.Model.Drawing.ImageFormat of the returned image. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + @Head(path: '/Items/{itemId}/Images/{imageType}/{imageIndex}') + Future> _itemsItemIdImagesImageTypeImageIndexHead({ + @Path('itemId') required String? itemId, + @Path('imageType') required String? imageType, + @Path('imageIndex') required int? imageIndex, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('width') int? width, + @Query('height') int? height, + @Query('quality') int? quality, + @Query('fillWidth') int? fillWidth, + @Query('fillHeight') int? fillHeight, + @Query('tag') String? tag, + @Query('format') String? format, + @Query('percentPlayed') num? percentPlayed, + @Query('unplayedCount') int? unplayedCount, + @Query('blur') int? blur, + @Query('backgroundColor') String? backgroundColor, + @Query('foregroundLayer') String? foregroundLayer, + }); + + ///Gets the item's image. + ///@param itemId Item id. + ///@param imageType Image type. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + Future> + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGet({ + required String? itemId, + required enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType? + imageType, + required int? maxWidth, + required int? maxHeight, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + required String? tag, + required enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat? + format, + required num? percentPlayed, + required int? unplayedCount, + int? blur, + String? backgroundColor, + String? foregroundLayer, + required int? imageIndex, + }) { + return _itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGet( + itemId: itemId, + imageType: imageType?.value?.toString(), + maxWidth: maxWidth, + maxHeight: maxHeight, + width: width, + height: height, + quality: quality, + fillWidth: fillWidth, + fillHeight: fillHeight, + tag: tag, + format: format?.value?.toString(), + percentPlayed: percentPlayed, + unplayedCount: unplayedCount, + blur: blur, + backgroundColor: backgroundColor, + foregroundLayer: foregroundLayer, + imageIndex: imageIndex); + } + + ///Gets the item's image. + ///@param itemId Item id. + ///@param imageType Image type. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + @Get( + path: + '/Items/{itemId}/Images/{imageType}/{imageIndex}/{tag}/{format}/{maxWidth}/{maxHeight}/{percentPlayed}/{unplayedCount}') + Future> + _itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGet({ + @Path('itemId') required String? itemId, + @Path('imageType') required String? imageType, + @Path('maxWidth') required int? maxWidth, + @Path('maxHeight') required int? maxHeight, + @Query('width') int? width, + @Query('height') int? height, + @Query('quality') int? quality, + @Query('fillWidth') int? fillWidth, + @Query('fillHeight') int? fillHeight, + @Path('tag') required String? tag, + @Path('format') required String? format, + @Path('percentPlayed') required num? percentPlayed, + @Path('unplayedCount') required int? unplayedCount, + @Query('blur') int? blur, + @Query('backgroundColor') String? backgroundColor, + @Query('foregroundLayer') String? foregroundLayer, + @Path('imageIndex') required int? imageIndex, + }); + + ///Gets the item's image. + ///@param itemId Item id. + ///@param imageType Image type. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + Future> + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHead({ + required String? itemId, + required enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType? + imageType, + required int? maxWidth, + required int? maxHeight, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + required String? tag, + required enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat? + format, + required num? percentPlayed, + required int? unplayedCount, + int? blur, + String? backgroundColor, + String? foregroundLayer, + required int? imageIndex, + }) { + return _itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHead( + itemId: itemId, + imageType: imageType?.value?.toString(), + maxWidth: maxWidth, + maxHeight: maxHeight, + width: width, + height: height, + quality: quality, + fillWidth: fillWidth, + fillHeight: fillHeight, + tag: tag, + format: format?.value?.toString(), + percentPlayed: percentPlayed, + unplayedCount: unplayedCount, + blur: blur, + backgroundColor: backgroundColor, + foregroundLayer: foregroundLayer, + imageIndex: imageIndex); + } + + ///Gets the item's image. + ///@param itemId Item id. + ///@param imageType Image type. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + @Head( + path: + '/Items/{itemId}/Images/{imageType}/{imageIndex}/{tag}/{format}/{maxWidth}/{maxHeight}/{percentPlayed}/{unplayedCount}') + Future> + _itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHead({ + @Path('itemId') required String? itemId, + @Path('imageType') required String? imageType, + @Path('maxWidth') required int? maxWidth, + @Path('maxHeight') required int? maxHeight, + @Query('width') int? width, + @Query('height') int? height, + @Query('quality') int? quality, + @Query('fillWidth') int? fillWidth, + @Query('fillHeight') int? fillHeight, + @Path('tag') required String? tag, + @Path('format') required String? format, + @Path('percentPlayed') required num? percentPlayed, + @Path('unplayedCount') required int? unplayedCount, + @Query('blur') int? blur, + @Query('backgroundColor') String? backgroundColor, + @Query('foregroundLayer') String? foregroundLayer, + @Path('imageIndex') required int? imageIndex, + }); + + ///Updates the index for an item image. + ///@param itemId Item id. + ///@param imageType Image type. + ///@param imageIndex Old image index. + ///@param newIndex New image index. + Future itemsItemIdImagesImageTypeImageIndexIndexPost({ + required String? itemId, + required enums.ItemsItemIdImagesImageTypeImageIndexIndexPostImageType? + imageType, + required int? imageIndex, + required int? newIndex, + }) { + return _itemsItemIdImagesImageTypeImageIndexIndexPost( + itemId: itemId, + imageType: imageType?.value?.toString(), + imageIndex: imageIndex, + newIndex: newIndex); + } + + ///Updates the index for an item image. + ///@param itemId Item id. + ///@param imageType Image type. + ///@param imageIndex Old image index. + ///@param newIndex New image index. + @Post( + path: '/Items/{itemId}/Images/{imageType}/{imageIndex}/Index', + optionalBody: true, + ) + Future _itemsItemIdImagesImageTypeImageIndexIndexPost({ + @Path('itemId') required String? itemId, + @Path('imageType') required String? imageType, + @Path('imageIndex') required int? imageIndex, + @Query('newIndex') required int? newIndex, + }); + + ///Get music genre image by name. + ///@param name Music genre name. + ///@param imageType Image type. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + Future> musicGenresNameImagesImageTypeGet({ + required String? name, + required enums.MusicGenresNameImagesImageTypeGetImageType? imageType, + String? tag, + enums.MusicGenresNameImagesImageTypeGetFormat? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + int? imageIndex, + }) { + return _musicGenresNameImagesImageTypeGet( + name: name, + imageType: imageType?.value?.toString(), + tag: tag, + format: format?.value?.toString(), + maxWidth: maxWidth, + maxHeight: maxHeight, + percentPlayed: percentPlayed, + unplayedCount: unplayedCount, + width: width, + height: height, + quality: quality, + fillWidth: fillWidth, + fillHeight: fillHeight, + blur: blur, + backgroundColor: backgroundColor, + foregroundLayer: foregroundLayer, + imageIndex: imageIndex); + } + + ///Get music genre image by name. + ///@param name Music genre name. + ///@param imageType Image type. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + @Get(path: '/MusicGenres/{name}/Images/{imageType}') + Future> _musicGenresNameImagesImageTypeGet({ + @Path('name') required String? name, + @Path('imageType') required String? imageType, + @Query('tag') String? tag, + @Query('format') String? format, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('percentPlayed') num? percentPlayed, + @Query('unplayedCount') int? unplayedCount, + @Query('width') int? width, + @Query('height') int? height, + @Query('quality') int? quality, + @Query('fillWidth') int? fillWidth, + @Query('fillHeight') int? fillHeight, + @Query('blur') int? blur, + @Query('backgroundColor') String? backgroundColor, + @Query('foregroundLayer') String? foregroundLayer, + @Query('imageIndex') int? imageIndex, + }); + + ///Get music genre image by name. + ///@param name Music genre name. + ///@param imageType Image type. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + Future> musicGenresNameImagesImageTypeHead({ + required String? name, + required enums.MusicGenresNameImagesImageTypeHeadImageType? imageType, + String? tag, + enums.MusicGenresNameImagesImageTypeHeadFormat? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + int? imageIndex, + }) { + return _musicGenresNameImagesImageTypeHead( + name: name, + imageType: imageType?.value?.toString(), + tag: tag, + format: format?.value?.toString(), + maxWidth: maxWidth, + maxHeight: maxHeight, + percentPlayed: percentPlayed, + unplayedCount: unplayedCount, + width: width, + height: height, + quality: quality, + fillWidth: fillWidth, + fillHeight: fillHeight, + blur: blur, + backgroundColor: backgroundColor, + foregroundLayer: foregroundLayer, + imageIndex: imageIndex); + } + + ///Get music genre image by name. + ///@param name Music genre name. + ///@param imageType Image type. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + @Head(path: '/MusicGenres/{name}/Images/{imageType}') + Future> _musicGenresNameImagesImageTypeHead({ + @Path('name') required String? name, + @Path('imageType') required String? imageType, + @Query('tag') String? tag, + @Query('format') String? format, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('percentPlayed') num? percentPlayed, + @Query('unplayedCount') int? unplayedCount, + @Query('width') int? width, + @Query('height') int? height, + @Query('quality') int? quality, + @Query('fillWidth') int? fillWidth, + @Query('fillHeight') int? fillHeight, + @Query('blur') int? blur, + @Query('backgroundColor') String? backgroundColor, + @Query('foregroundLayer') String? foregroundLayer, + @Query('imageIndex') int? imageIndex, + }); + + ///Get music genre image by name. + ///@param name Music genre name. + ///@param imageType Image type. + ///@param imageIndex Image index. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + Future> musicGenresNameImagesImageTypeImageIndexGet({ + required String? name, + required enums.MusicGenresNameImagesImageTypeImageIndexGetImageType? + imageType, + required int? imageIndex, + String? tag, + enums.MusicGenresNameImagesImageTypeImageIndexGetFormat? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + }) { + return _musicGenresNameImagesImageTypeImageIndexGet( + name: name, + imageType: imageType?.value?.toString(), + imageIndex: imageIndex, + tag: tag, + format: format?.value?.toString(), + maxWidth: maxWidth, + maxHeight: maxHeight, + percentPlayed: percentPlayed, + unplayedCount: unplayedCount, + width: width, + height: height, + quality: quality, + fillWidth: fillWidth, + fillHeight: fillHeight, + blur: blur, + backgroundColor: backgroundColor, + foregroundLayer: foregroundLayer); + } + + ///Get music genre image by name. + ///@param name Music genre name. + ///@param imageType Image type. + ///@param imageIndex Image index. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + @Get(path: '/MusicGenres/{name}/Images/{imageType}/{imageIndex}') + Future> + _musicGenresNameImagesImageTypeImageIndexGet({ + @Path('name') required String? name, + @Path('imageType') required String? imageType, + @Path('imageIndex') required int? imageIndex, + @Query('tag') String? tag, + @Query('format') String? format, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('percentPlayed') num? percentPlayed, + @Query('unplayedCount') int? unplayedCount, + @Query('width') int? width, + @Query('height') int? height, + @Query('quality') int? quality, + @Query('fillWidth') int? fillWidth, + @Query('fillHeight') int? fillHeight, + @Query('blur') int? blur, + @Query('backgroundColor') String? backgroundColor, + @Query('foregroundLayer') String? foregroundLayer, + }); + + ///Get music genre image by name. + ///@param name Music genre name. + ///@param imageType Image type. + ///@param imageIndex Image index. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + Future> + musicGenresNameImagesImageTypeImageIndexHead({ + required String? name, + required enums.MusicGenresNameImagesImageTypeImageIndexHeadImageType? + imageType, + required int? imageIndex, + String? tag, + enums.MusicGenresNameImagesImageTypeImageIndexHeadFormat? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + }) { + return _musicGenresNameImagesImageTypeImageIndexHead( + name: name, + imageType: imageType?.value?.toString(), + imageIndex: imageIndex, + tag: tag, + format: format?.value?.toString(), + maxWidth: maxWidth, + maxHeight: maxHeight, + percentPlayed: percentPlayed, + unplayedCount: unplayedCount, + width: width, + height: height, + quality: quality, + fillWidth: fillWidth, + fillHeight: fillHeight, + blur: blur, + backgroundColor: backgroundColor, + foregroundLayer: foregroundLayer); + } + + ///Get music genre image by name. + ///@param name Music genre name. + ///@param imageType Image type. + ///@param imageIndex Image index. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + @Head(path: '/MusicGenres/{name}/Images/{imageType}/{imageIndex}') + Future> + _musicGenresNameImagesImageTypeImageIndexHead({ + @Path('name') required String? name, + @Path('imageType') required String? imageType, + @Path('imageIndex') required int? imageIndex, + @Query('tag') String? tag, + @Query('format') String? format, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('percentPlayed') num? percentPlayed, + @Query('unplayedCount') int? unplayedCount, + @Query('width') int? width, + @Query('height') int? height, + @Query('quality') int? quality, + @Query('fillWidth') int? fillWidth, + @Query('fillHeight') int? fillHeight, + @Query('blur') int? blur, + @Query('backgroundColor') String? backgroundColor, + @Query('foregroundLayer') String? foregroundLayer, + }); + + ///Get person image by name. + ///@param name Person name. + ///@param imageType Image type. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + Future> personsNameImagesImageTypeGet({ + required String? name, + required enums.PersonsNameImagesImageTypeGetImageType? imageType, + String? tag, + enums.PersonsNameImagesImageTypeGetFormat? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + int? imageIndex, + }) { + return _personsNameImagesImageTypeGet( + name: name, + imageType: imageType?.value?.toString(), + tag: tag, + format: format?.value?.toString(), + maxWidth: maxWidth, + maxHeight: maxHeight, + percentPlayed: percentPlayed, + unplayedCount: unplayedCount, + width: width, + height: height, + quality: quality, + fillWidth: fillWidth, + fillHeight: fillHeight, + blur: blur, + backgroundColor: backgroundColor, + foregroundLayer: foregroundLayer, + imageIndex: imageIndex); + } + + ///Get person image by name. + ///@param name Person name. + ///@param imageType Image type. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + @Get(path: '/Persons/{name}/Images/{imageType}') + Future> _personsNameImagesImageTypeGet({ + @Path('name') required String? name, + @Path('imageType') required String? imageType, + @Query('tag') String? tag, + @Query('format') String? format, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('percentPlayed') num? percentPlayed, + @Query('unplayedCount') int? unplayedCount, + @Query('width') int? width, + @Query('height') int? height, + @Query('quality') int? quality, + @Query('fillWidth') int? fillWidth, + @Query('fillHeight') int? fillHeight, + @Query('blur') int? blur, + @Query('backgroundColor') String? backgroundColor, + @Query('foregroundLayer') String? foregroundLayer, + @Query('imageIndex') int? imageIndex, + }); + + ///Get person image by name. + ///@param name Person name. + ///@param imageType Image type. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + Future> personsNameImagesImageTypeHead({ + required String? name, + required enums.PersonsNameImagesImageTypeHeadImageType? imageType, + String? tag, + enums.PersonsNameImagesImageTypeHeadFormat? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + int? imageIndex, + }) { + return _personsNameImagesImageTypeHead( + name: name, + imageType: imageType?.value?.toString(), + tag: tag, + format: format?.value?.toString(), + maxWidth: maxWidth, + maxHeight: maxHeight, + percentPlayed: percentPlayed, + unplayedCount: unplayedCount, + width: width, + height: height, + quality: quality, + fillWidth: fillWidth, + fillHeight: fillHeight, + blur: blur, + backgroundColor: backgroundColor, + foregroundLayer: foregroundLayer, + imageIndex: imageIndex); + } + + ///Get person image by name. + ///@param name Person name. + ///@param imageType Image type. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + @Head(path: '/Persons/{name}/Images/{imageType}') + Future> _personsNameImagesImageTypeHead({ + @Path('name') required String? name, + @Path('imageType') required String? imageType, + @Query('tag') String? tag, + @Query('format') String? format, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('percentPlayed') num? percentPlayed, + @Query('unplayedCount') int? unplayedCount, + @Query('width') int? width, + @Query('height') int? height, + @Query('quality') int? quality, + @Query('fillWidth') int? fillWidth, + @Query('fillHeight') int? fillHeight, + @Query('blur') int? blur, + @Query('backgroundColor') String? backgroundColor, + @Query('foregroundLayer') String? foregroundLayer, + @Query('imageIndex') int? imageIndex, + }); + + ///Get person image by name. + ///@param name Person name. + ///@param imageType Image type. + ///@param imageIndex Image index. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + Future> personsNameImagesImageTypeImageIndexGet({ + required String? name, + required enums.PersonsNameImagesImageTypeImageIndexGetImageType? imageType, + required int? imageIndex, + String? tag, + enums.PersonsNameImagesImageTypeImageIndexGetFormat? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + }) { + return _personsNameImagesImageTypeImageIndexGet( + name: name, + imageType: imageType?.value?.toString(), + imageIndex: imageIndex, + tag: tag, + format: format?.value?.toString(), + maxWidth: maxWidth, + maxHeight: maxHeight, + percentPlayed: percentPlayed, + unplayedCount: unplayedCount, + width: width, + height: height, + quality: quality, + fillWidth: fillWidth, + fillHeight: fillHeight, + blur: blur, + backgroundColor: backgroundColor, + foregroundLayer: foregroundLayer); + } + + ///Get person image by name. + ///@param name Person name. + ///@param imageType Image type. + ///@param imageIndex Image index. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + @Get(path: '/Persons/{name}/Images/{imageType}/{imageIndex}') + Future> _personsNameImagesImageTypeImageIndexGet({ + @Path('name') required String? name, + @Path('imageType') required String? imageType, + @Path('imageIndex') required int? imageIndex, + @Query('tag') String? tag, + @Query('format') String? format, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('percentPlayed') num? percentPlayed, + @Query('unplayedCount') int? unplayedCount, + @Query('width') int? width, + @Query('height') int? height, + @Query('quality') int? quality, + @Query('fillWidth') int? fillWidth, + @Query('fillHeight') int? fillHeight, + @Query('blur') int? blur, + @Query('backgroundColor') String? backgroundColor, + @Query('foregroundLayer') String? foregroundLayer, + }); + + ///Get person image by name. + ///@param name Person name. + ///@param imageType Image type. + ///@param imageIndex Image index. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + Future> personsNameImagesImageTypeImageIndexHead({ + required String? name, + required enums.PersonsNameImagesImageTypeImageIndexHeadImageType? imageType, + required int? imageIndex, + String? tag, + enums.PersonsNameImagesImageTypeImageIndexHeadFormat? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + }) { + return _personsNameImagesImageTypeImageIndexHead( + name: name, + imageType: imageType?.value?.toString(), + imageIndex: imageIndex, + tag: tag, + format: format?.value?.toString(), + maxWidth: maxWidth, + maxHeight: maxHeight, + percentPlayed: percentPlayed, + unplayedCount: unplayedCount, + width: width, + height: height, + quality: quality, + fillWidth: fillWidth, + fillHeight: fillHeight, + blur: blur, + backgroundColor: backgroundColor, + foregroundLayer: foregroundLayer); + } + + ///Get person image by name. + ///@param name Person name. + ///@param imageType Image type. + ///@param imageIndex Image index. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + @Head(path: '/Persons/{name}/Images/{imageType}/{imageIndex}') + Future> _personsNameImagesImageTypeImageIndexHead({ + @Path('name') required String? name, + @Path('imageType') required String? imageType, + @Path('imageIndex') required int? imageIndex, + @Query('tag') String? tag, + @Query('format') String? format, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('percentPlayed') num? percentPlayed, + @Query('unplayedCount') int? unplayedCount, + @Query('width') int? width, + @Query('height') int? height, + @Query('quality') int? quality, + @Query('fillWidth') int? fillWidth, + @Query('fillHeight') int? fillHeight, + @Query('blur') int? blur, + @Query('backgroundColor') String? backgroundColor, + @Query('foregroundLayer') String? foregroundLayer, + }); + + ///Get studio image by name. + ///@param name Studio name. + ///@param imageType Image type. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + Future> studiosNameImagesImageTypeGet({ + required String? name, + required enums.StudiosNameImagesImageTypeGetImageType? imageType, + String? tag, + enums.StudiosNameImagesImageTypeGetFormat? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + int? imageIndex, + }) { + return _studiosNameImagesImageTypeGet( + name: name, + imageType: imageType?.value?.toString(), + tag: tag, + format: format?.value?.toString(), + maxWidth: maxWidth, + maxHeight: maxHeight, + percentPlayed: percentPlayed, + unplayedCount: unplayedCount, + width: width, + height: height, + quality: quality, + fillWidth: fillWidth, + fillHeight: fillHeight, + blur: blur, + backgroundColor: backgroundColor, + foregroundLayer: foregroundLayer, + imageIndex: imageIndex); + } + + ///Get studio image by name. + ///@param name Studio name. + ///@param imageType Image type. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + @Get(path: '/Studios/{name}/Images/{imageType}') + Future> _studiosNameImagesImageTypeGet({ + @Path('name') required String? name, + @Path('imageType') required String? imageType, + @Query('tag') String? tag, + @Query('format') String? format, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('percentPlayed') num? percentPlayed, + @Query('unplayedCount') int? unplayedCount, + @Query('width') int? width, + @Query('height') int? height, + @Query('quality') int? quality, + @Query('fillWidth') int? fillWidth, + @Query('fillHeight') int? fillHeight, + @Query('blur') int? blur, + @Query('backgroundColor') String? backgroundColor, + @Query('foregroundLayer') String? foregroundLayer, + @Query('imageIndex') int? imageIndex, + }); + + ///Get studio image by name. + ///@param name Studio name. + ///@param imageType Image type. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + Future> studiosNameImagesImageTypeHead({ + required String? name, + required enums.StudiosNameImagesImageTypeHeadImageType? imageType, + String? tag, + enums.StudiosNameImagesImageTypeHeadFormat? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + int? imageIndex, + }) { + return _studiosNameImagesImageTypeHead( + name: name, + imageType: imageType?.value?.toString(), + tag: tag, + format: format?.value?.toString(), + maxWidth: maxWidth, + maxHeight: maxHeight, + percentPlayed: percentPlayed, + unplayedCount: unplayedCount, + width: width, + height: height, + quality: quality, + fillWidth: fillWidth, + fillHeight: fillHeight, + blur: blur, + backgroundColor: backgroundColor, + foregroundLayer: foregroundLayer, + imageIndex: imageIndex); + } + + ///Get studio image by name. + ///@param name Studio name. + ///@param imageType Image type. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + @Head(path: '/Studios/{name}/Images/{imageType}') + Future> _studiosNameImagesImageTypeHead({ + @Path('name') required String? name, + @Path('imageType') required String? imageType, + @Query('tag') String? tag, + @Query('format') String? format, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('percentPlayed') num? percentPlayed, + @Query('unplayedCount') int? unplayedCount, + @Query('width') int? width, + @Query('height') int? height, + @Query('quality') int? quality, + @Query('fillWidth') int? fillWidth, + @Query('fillHeight') int? fillHeight, + @Query('blur') int? blur, + @Query('backgroundColor') String? backgroundColor, + @Query('foregroundLayer') String? foregroundLayer, + @Query('imageIndex') int? imageIndex, + }); + + ///Get studio image by name. + ///@param name Studio name. + ///@param imageType Image type. + ///@param imageIndex Image index. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + Future> studiosNameImagesImageTypeImageIndexGet({ + required String? name, + required enums.StudiosNameImagesImageTypeImageIndexGetImageType? imageType, + required int? imageIndex, + String? tag, + enums.StudiosNameImagesImageTypeImageIndexGetFormat? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + }) { + return _studiosNameImagesImageTypeImageIndexGet( + name: name, + imageType: imageType?.value?.toString(), + imageIndex: imageIndex, + tag: tag, + format: format?.value?.toString(), + maxWidth: maxWidth, + maxHeight: maxHeight, + percentPlayed: percentPlayed, + unplayedCount: unplayedCount, + width: width, + height: height, + quality: quality, + fillWidth: fillWidth, + fillHeight: fillHeight, + blur: blur, + backgroundColor: backgroundColor, + foregroundLayer: foregroundLayer); + } + + ///Get studio image by name. + ///@param name Studio name. + ///@param imageType Image type. + ///@param imageIndex Image index. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + @Get(path: '/Studios/{name}/Images/{imageType}/{imageIndex}') + Future> _studiosNameImagesImageTypeImageIndexGet({ + @Path('name') required String? name, + @Path('imageType') required String? imageType, + @Path('imageIndex') required int? imageIndex, + @Query('tag') String? tag, + @Query('format') String? format, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('percentPlayed') num? percentPlayed, + @Query('unplayedCount') int? unplayedCount, + @Query('width') int? width, + @Query('height') int? height, + @Query('quality') int? quality, + @Query('fillWidth') int? fillWidth, + @Query('fillHeight') int? fillHeight, + @Query('blur') int? blur, + @Query('backgroundColor') String? backgroundColor, + @Query('foregroundLayer') String? foregroundLayer, + }); + + ///Get studio image by name. + ///@param name Studio name. + ///@param imageType Image type. + ///@param imageIndex Image index. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + Future> studiosNameImagesImageTypeImageIndexHead({ + required String? name, + required enums.StudiosNameImagesImageTypeImageIndexHeadImageType? imageType, + required int? imageIndex, + String? tag, + enums.StudiosNameImagesImageTypeImageIndexHeadFormat? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + }) { + return _studiosNameImagesImageTypeImageIndexHead( + name: name, + imageType: imageType?.value?.toString(), + imageIndex: imageIndex, + tag: tag, + format: format?.value?.toString(), + maxWidth: maxWidth, + maxHeight: maxHeight, + percentPlayed: percentPlayed, + unplayedCount: unplayedCount, + width: width, + height: height, + quality: quality, + fillWidth: fillWidth, + fillHeight: fillHeight, + blur: blur, + backgroundColor: backgroundColor, + foregroundLayer: foregroundLayer); + } + + ///Get studio image by name. + ///@param name Studio name. + ///@param imageType Image type. + ///@param imageIndex Image index. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + @Head(path: '/Studios/{name}/Images/{imageType}/{imageIndex}') + Future> _studiosNameImagesImageTypeImageIndexHead({ + @Path('name') required String? name, + @Path('imageType') required String? imageType, + @Path('imageIndex') required int? imageIndex, + @Query('tag') String? tag, + @Query('format') String? format, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('percentPlayed') num? percentPlayed, + @Query('unplayedCount') int? unplayedCount, + @Query('width') int? width, + @Query('height') int? height, + @Query('quality') int? quality, + @Query('fillWidth') int? fillWidth, + @Query('fillHeight') int? fillHeight, + @Query('blur') int? blur, + @Query('backgroundColor') String? backgroundColor, + @Query('foregroundLayer') String? foregroundLayer, + }); + + ///Sets the user image. + ///@param userId User Id. + Future userImagePost({ + String? userId, + required Object? body, + }) { + return _userImagePost(userId: userId, body: body); + } + + ///Sets the user image. + ///@param userId User Id. + @Post( + path: '/UserImage', + optionalBody: true, + ) + Future _userImagePost({ + @Query('userId') String? userId, + @Body() required Object? body, + }); + + ///Delete the user's image. + ///@param userId User Id. + Future userImageDelete({String? userId}) { + return _userImageDelete(userId: userId); + } + + ///Delete the user's image. + ///@param userId User Id. + @Delete(path: '/UserImage') + Future _userImageDelete({@Query('userId') String? userId}); + + ///Get user profile image. + ///@param userId User id. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + Future> userImageGet({ + String? userId, + String? tag, + enums.UserImageGetFormat? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + int? imageIndex, + }) { + return _userImageGet( + userId: userId, + tag: tag, + format: format?.value?.toString(), + maxWidth: maxWidth, + maxHeight: maxHeight, + percentPlayed: percentPlayed, + unplayedCount: unplayedCount, + width: width, + height: height, + quality: quality, + fillWidth: fillWidth, + fillHeight: fillHeight, + blur: blur, + backgroundColor: backgroundColor, + foregroundLayer: foregroundLayer, + imageIndex: imageIndex); + } + + ///Get user profile image. + ///@param userId User id. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + @Get(path: '/UserImage') + Future> _userImageGet({ + @Query('userId') String? userId, + @Query('tag') String? tag, + @Query('format') String? format, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('percentPlayed') num? percentPlayed, + @Query('unplayedCount') int? unplayedCount, + @Query('width') int? width, + @Query('height') int? height, + @Query('quality') int? quality, + @Query('fillWidth') int? fillWidth, + @Query('fillHeight') int? fillHeight, + @Query('blur') int? blur, + @Query('backgroundColor') String? backgroundColor, + @Query('foregroundLayer') String? foregroundLayer, + @Query('imageIndex') int? imageIndex, + }); + + ///Get user profile image. + ///@param userId User id. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + Future> userImageHead({ + String? userId, + String? tag, + enums.UserImageHeadFormat? format, + int? maxWidth, + int? maxHeight, + num? percentPlayed, + int? unplayedCount, + int? width, + int? height, + int? quality, + int? fillWidth, + int? fillHeight, + int? blur, + String? backgroundColor, + String? foregroundLayer, + int? imageIndex, + }) { + return _userImageHead( + userId: userId, + tag: tag, + format: format?.value?.toString(), + maxWidth: maxWidth, + maxHeight: maxHeight, + percentPlayed: percentPlayed, + unplayedCount: unplayedCount, + width: width, + height: height, + quality: quality, + fillWidth: fillWidth, + fillHeight: fillHeight, + blur: blur, + backgroundColor: backgroundColor, + foregroundLayer: foregroundLayer, + imageIndex: imageIndex); + } + + ///Get user profile image. + ///@param userId User id. + ///@param tag Optional. Supply the cache tag from the item object to receive strong caching headers. + ///@param format Determines the output format of the image - original,gif,jpg,png. + ///@param maxWidth The maximum image width to return. + ///@param maxHeight The maximum image height to return. + ///@param percentPlayed Optional. Percent to render for the percent played overlay. + ///@param unplayedCount Optional. Unplayed count overlay to render. + ///@param width The fixed image width to return. + ///@param height The fixed image height to return. + ///@param quality Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + ///@param fillWidth Width of box to fill. + ///@param fillHeight Height of box to fill. + ///@param blur Optional. Blur image. + ///@param backgroundColor Optional. Apply a background color for transparent images. + ///@param foregroundLayer Optional. Apply a foreground layer on top of the image. + ///@param imageIndex Image index. + @Head(path: '/UserImage') + Future> _userImageHead({ + @Query('userId') String? userId, + @Query('tag') String? tag, + @Query('format') String? format, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('percentPlayed') num? percentPlayed, + @Query('unplayedCount') int? unplayedCount, + @Query('width') int? width, + @Query('height') int? height, + @Query('quality') int? quality, + @Query('fillWidth') int? fillWidth, + @Query('fillHeight') int? fillHeight, + @Query('blur') int? blur, + @Query('backgroundColor') String? backgroundColor, + @Query('foregroundLayer') String? foregroundLayer, + @Query('imageIndex') int? imageIndex, + }); + + ///Creates an instant playlist based on a given album. + ///@param itemId The item id. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableImages Optional. Include image information in output. + ///@param enableUserData Optional. Include user data. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + Future> albumsItemIdInstantMixGet({ + required String? itemId, + String? userId, + int? limit, + List? fields, + bool? enableImages, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _albumsItemIdInstantMixGet( + itemId: itemId, + userId: userId, + limit: limit, + fields: itemFieldsListToJson(fields), + enableImages: enableImages, + enableUserData: enableUserData, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes)); + } + + ///Creates an instant playlist based on a given album. + ///@param itemId The item id. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableImages Optional. Include image information in output. + ///@param enableUserData Optional. Include user data. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + @Get(path: '/Albums/{itemId}/InstantMix') + Future> _albumsItemIdInstantMixGet({ + @Path('itemId') required String? itemId, + @Query('userId') String? userId, + @Query('limit') int? limit, + @Query('fields') List? fields, + @Query('enableImages') bool? enableImages, + @Query('enableUserData') bool? enableUserData, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + }); + + ///Creates an instant playlist based on a given artist. + ///@param itemId The item id. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableImages Optional. Include image information in output. + ///@param enableUserData Optional. Include user data. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + Future> artistsItemIdInstantMixGet({ + required String? itemId, + String? userId, + int? limit, + List? fields, + bool? enableImages, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _artistsItemIdInstantMixGet( + itemId: itemId, + userId: userId, + limit: limit, + fields: itemFieldsListToJson(fields), + enableImages: enableImages, + enableUserData: enableUserData, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes)); + } + + ///Creates an instant playlist based on a given artist. + ///@param itemId The item id. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableImages Optional. Include image information in output. + ///@param enableUserData Optional. Include user data. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + @Get(path: '/Artists/{itemId}/InstantMix') + Future> _artistsItemIdInstantMixGet({ + @Path('itemId') required String? itemId, + @Query('userId') String? userId, + @Query('limit') int? limit, + @Query('fields') List? fields, + @Query('enableImages') bool? enableImages, + @Query('enableUserData') bool? enableUserData, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + }); + + ///Creates an instant playlist based on a given artist. + ///@param id The item id. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableImages Optional. Include image information in output. + ///@param enableUserData Optional. Include user data. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + @deprecated + Future> artistsInstantMixGet({ + required String? id, + String? userId, + int? limit, + List? fields, + bool? enableImages, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _artistsInstantMixGet( + id: id, + userId: userId, + limit: limit, + fields: itemFieldsListToJson(fields), + enableImages: enableImages, + enableUserData: enableUserData, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes)); + } + + ///Creates an instant playlist based on a given artist. + ///@param id The item id. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableImages Optional. Include image information in output. + ///@param enableUserData Optional. Include user data. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + @deprecated + @Get(path: '/Artists/InstantMix') + Future> _artistsInstantMixGet({ + @Query('id') required String? id, + @Query('userId') String? userId, + @Query('limit') int? limit, + @Query('fields') List? fields, + @Query('enableImages') bool? enableImages, + @Query('enableUserData') bool? enableUserData, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + }); + + ///Creates an instant playlist based on a given item. + ///@param itemId The item id. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableImages Optional. Include image information in output. + ///@param enableUserData Optional. Include user data. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + Future> itemsItemIdInstantMixGet({ + required String? itemId, + String? userId, + int? limit, + List? fields, + bool? enableImages, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _itemsItemIdInstantMixGet( + itemId: itemId, + userId: userId, + limit: limit, + fields: itemFieldsListToJson(fields), + enableImages: enableImages, + enableUserData: enableUserData, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes)); + } + + ///Creates an instant playlist based on a given item. + ///@param itemId The item id. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableImages Optional. Include image information in output. + ///@param enableUserData Optional. Include user data. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + @Get(path: '/Items/{itemId}/InstantMix') + Future> _itemsItemIdInstantMixGet({ + @Path('itemId') required String? itemId, + @Query('userId') String? userId, + @Query('limit') int? limit, + @Query('fields') List? fields, + @Query('enableImages') bool? enableImages, + @Query('enableUserData') bool? enableUserData, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + }); + + ///Creates an instant playlist based on a given genre. + ///@param name The genre name. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableImages Optional. Include image information in output. + ///@param enableUserData Optional. Include user data. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + Future> + musicGenresNameInstantMixGet({ + required String? name, + String? userId, + int? limit, + List? fields, + bool? enableImages, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _musicGenresNameInstantMixGet( + name: name, + userId: userId, + limit: limit, + fields: itemFieldsListToJson(fields), + enableImages: enableImages, + enableUserData: enableUserData, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes)); + } + + ///Creates an instant playlist based on a given genre. + ///@param name The genre name. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableImages Optional. Include image information in output. + ///@param enableUserData Optional. Include user data. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + @Get(path: '/MusicGenres/{name}/InstantMix') + Future> + _musicGenresNameInstantMixGet({ + @Path('name') required String? name, + @Query('userId') String? userId, + @Query('limit') int? limit, + @Query('fields') List? fields, + @Query('enableImages') bool? enableImages, + @Query('enableUserData') bool? enableUserData, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + }); + + ///Creates an instant playlist based on a given genre. + ///@param id The item id. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableImages Optional. Include image information in output. + ///@param enableUserData Optional. Include user data. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + Future> musicGenresInstantMixGet({ + required String? id, + String? userId, + int? limit, + List? fields, + bool? enableImages, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _musicGenresInstantMixGet( + id: id, + userId: userId, + limit: limit, + fields: itemFieldsListToJson(fields), + enableImages: enableImages, + enableUserData: enableUserData, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes)); + } + + ///Creates an instant playlist based on a given genre. + ///@param id The item id. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableImages Optional. Include image information in output. + ///@param enableUserData Optional. Include user data. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + @Get(path: '/MusicGenres/InstantMix') + Future> _musicGenresInstantMixGet({ + @Query('id') required String? id, + @Query('userId') String? userId, + @Query('limit') int? limit, + @Query('fields') List? fields, + @Query('enableImages') bool? enableImages, + @Query('enableUserData') bool? enableUserData, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + }); + + ///Creates an instant playlist based on a given playlist. + ///@param itemId The item id. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableImages Optional. Include image information in output. + ///@param enableUserData Optional. Include user data. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + Future> + playlistsItemIdInstantMixGet({ + required String? itemId, + String? userId, + int? limit, + List? fields, + bool? enableImages, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _playlistsItemIdInstantMixGet( + itemId: itemId, + userId: userId, + limit: limit, + fields: itemFieldsListToJson(fields), + enableImages: enableImages, + enableUserData: enableUserData, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes)); + } + + ///Creates an instant playlist based on a given playlist. + ///@param itemId The item id. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableImages Optional. Include image information in output. + ///@param enableUserData Optional. Include user data. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + @Get(path: '/Playlists/{itemId}/InstantMix') + Future> + _playlistsItemIdInstantMixGet({ + @Path('itemId') required String? itemId, + @Query('userId') String? userId, + @Query('limit') int? limit, + @Query('fields') List? fields, + @Query('enableImages') bool? enableImages, + @Query('enableUserData') bool? enableUserData, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + }); + + ///Creates an instant playlist based on a given song. + ///@param itemId The item id. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableImages Optional. Include image information in output. + ///@param enableUserData Optional. Include user data. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + Future> songsItemIdInstantMixGet({ + required String? itemId, + String? userId, + int? limit, + List? fields, + bool? enableImages, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _songsItemIdInstantMixGet( + itemId: itemId, + userId: userId, + limit: limit, + fields: itemFieldsListToJson(fields), + enableImages: enableImages, + enableUserData: enableUserData, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes)); + } + + ///Creates an instant playlist based on a given song. + ///@param itemId The item id. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableImages Optional. Include image information in output. + ///@param enableUserData Optional. Include user data. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + @Get(path: '/Songs/{itemId}/InstantMix') + Future> _songsItemIdInstantMixGet({ + @Path('itemId') required String? itemId, + @Query('userId') String? userId, + @Query('limit') int? limit, + @Query('fields') List? fields, + @Query('enableImages') bool? enableImages, + @Query('enableUserData') bool? enableUserData, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + }); + + ///Get the item's external id info. + ///@param itemId Item id. + Future>> itemsItemIdExternalIdInfosGet( + {required String? itemId}) { + generatedMapping.putIfAbsent( + ExternalIdInfo, () => ExternalIdInfo.fromJsonFactory); + + return _itemsItemIdExternalIdInfosGet(itemId: itemId); + } + + ///Get the item's external id info. + ///@param itemId Item id. + @Get(path: '/Items/{itemId}/ExternalIdInfos') + Future>> _itemsItemIdExternalIdInfosGet( + {@Path('itemId') required String? itemId}); + + ///Applies search criteria to an item and refreshes metadata. + ///@param itemId Item id. + ///@param replaceAllImages Optional. Whether or not to replace all images. Default: True. + Future itemsRemoteSearchApplyItemIdPost({ + required String? itemId, + bool? replaceAllImages, + required RemoteSearchResult? body, + }) { + return _itemsRemoteSearchApplyItemIdPost( + itemId: itemId, replaceAllImages: replaceAllImages, body: body); + } + + ///Applies search criteria to an item and refreshes metadata. + ///@param itemId Item id. + ///@param replaceAllImages Optional. Whether or not to replace all images. Default: True. + @Post( + path: '/Items/RemoteSearch/Apply/{itemId}', + optionalBody: true, + ) + Future _itemsRemoteSearchApplyItemIdPost({ + @Path('itemId') required String? itemId, + @Query('replaceAllImages') bool? replaceAllImages, + @Body() required RemoteSearchResult? body, + }); + + ///Get book remote search. + Future>> itemsRemoteSearchBookPost( + {required BookInfoRemoteSearchQuery? body}) { + generatedMapping.putIfAbsent( + RemoteSearchResult, () => RemoteSearchResult.fromJsonFactory); + + return _itemsRemoteSearchBookPost(body: body); + } + + ///Get book remote search. + @Post( + path: '/Items/RemoteSearch/Book', + optionalBody: true, + ) + Future>> _itemsRemoteSearchBookPost( + {@Body() required BookInfoRemoteSearchQuery? body}); + + ///Get box set remote search. + Future>> + itemsRemoteSearchBoxSetPost( + {required BoxSetInfoRemoteSearchQuery? body}) { + generatedMapping.putIfAbsent( + RemoteSearchResult, () => RemoteSearchResult.fromJsonFactory); + + return _itemsRemoteSearchBoxSetPost(body: body); + } + + ///Get box set remote search. + @Post( + path: '/Items/RemoteSearch/BoxSet', + optionalBody: true, + ) + Future>> + _itemsRemoteSearchBoxSetPost( + {@Body() required BoxSetInfoRemoteSearchQuery? body}); + + ///Get movie remote search. + Future>> itemsRemoteSearchMoviePost( + {required MovieInfoRemoteSearchQuery? body}) { + generatedMapping.putIfAbsent( + RemoteSearchResult, () => RemoteSearchResult.fromJsonFactory); + + return _itemsRemoteSearchMoviePost(body: body); + } + + ///Get movie remote search. + @Post( + path: '/Items/RemoteSearch/Movie', + optionalBody: true, + ) + Future>> + _itemsRemoteSearchMoviePost( + {@Body() required MovieInfoRemoteSearchQuery? body}); + + ///Get music album remote search. + Future>> + itemsRemoteSearchMusicAlbumPost( + {required AlbumInfoRemoteSearchQuery? body}) { + generatedMapping.putIfAbsent( + RemoteSearchResult, () => RemoteSearchResult.fromJsonFactory); + + return _itemsRemoteSearchMusicAlbumPost(body: body); + } + + ///Get music album remote search. + @Post( + path: '/Items/RemoteSearch/MusicAlbum', + optionalBody: true, + ) + Future>> + _itemsRemoteSearchMusicAlbumPost( + {@Body() required AlbumInfoRemoteSearchQuery? body}); + + ///Get music artist remote search. + Future>> + itemsRemoteSearchMusicArtistPost( + {required ArtistInfoRemoteSearchQuery? body}) { + generatedMapping.putIfAbsent( + RemoteSearchResult, () => RemoteSearchResult.fromJsonFactory); + + return _itemsRemoteSearchMusicArtistPost(body: body); + } + + ///Get music artist remote search. + @Post( + path: '/Items/RemoteSearch/MusicArtist', + optionalBody: true, + ) + Future>> + _itemsRemoteSearchMusicArtistPost( + {@Body() required ArtistInfoRemoteSearchQuery? body}); + + ///Get music video remote search. + Future>> + itemsRemoteSearchMusicVideoPost( + {required MusicVideoInfoRemoteSearchQuery? body}) { + generatedMapping.putIfAbsent( + RemoteSearchResult, () => RemoteSearchResult.fromJsonFactory); + + return _itemsRemoteSearchMusicVideoPost(body: body); + } + + ///Get music video remote search. + @Post( + path: '/Items/RemoteSearch/MusicVideo', + optionalBody: true, + ) + Future>> + _itemsRemoteSearchMusicVideoPost( + {@Body() required MusicVideoInfoRemoteSearchQuery? body}); + + ///Get person remote search. + Future>> + itemsRemoteSearchPersonPost( + {required PersonLookupInfoRemoteSearchQuery? body}) { + generatedMapping.putIfAbsent( + RemoteSearchResult, () => RemoteSearchResult.fromJsonFactory); + + return _itemsRemoteSearchPersonPost(body: body); + } + + ///Get person remote search. + @Post( + path: '/Items/RemoteSearch/Person', + optionalBody: true, + ) + Future>> + _itemsRemoteSearchPersonPost( + {@Body() required PersonLookupInfoRemoteSearchQuery? body}); + + ///Get series remote search. + Future>> + itemsRemoteSearchSeriesPost( + {required SeriesInfoRemoteSearchQuery? body}) { + generatedMapping.putIfAbsent( + RemoteSearchResult, () => RemoteSearchResult.fromJsonFactory); + + return _itemsRemoteSearchSeriesPost(body: body); + } + + ///Get series remote search. + @Post( + path: '/Items/RemoteSearch/Series', + optionalBody: true, + ) + Future>> + _itemsRemoteSearchSeriesPost( + {@Body() required SeriesInfoRemoteSearchQuery? body}); + + ///Get trailer remote search. + Future>> + itemsRemoteSearchTrailerPost( + {required TrailerInfoRemoteSearchQuery? body}) { + generatedMapping.putIfAbsent( + RemoteSearchResult, () => RemoteSearchResult.fromJsonFactory); + + return _itemsRemoteSearchTrailerPost(body: body); + } + + ///Get trailer remote search. + @Post( + path: '/Items/RemoteSearch/Trailer', + optionalBody: true, + ) + Future>> + _itemsRemoteSearchTrailerPost( + {@Body() required TrailerInfoRemoteSearchQuery? body}); + + ///Refreshes metadata for an item. + ///@param itemId Item id. + ///@param metadataRefreshMode (Optional) Specifies the metadata refresh mode. + ///@param imageRefreshMode (Optional) Specifies the image refresh mode. + ///@param replaceAllMetadata (Optional) Determines if metadata should be replaced. Only applicable if mode is FullRefresh. + ///@param replaceAllImages (Optional) Determines if images should be replaced. Only applicable if mode is FullRefresh. + Future itemsItemIdRefreshPost({ + required String? itemId, + enums.ItemsItemIdRefreshPostMetadataRefreshMode? metadataRefreshMode, + enums.ItemsItemIdRefreshPostImageRefreshMode? imageRefreshMode, + bool? replaceAllMetadata, + bool? replaceAllImages, + }) { + return _itemsItemIdRefreshPost( + itemId: itemId, + metadataRefreshMode: metadataRefreshMode?.value?.toString(), + imageRefreshMode: imageRefreshMode?.value?.toString(), + replaceAllMetadata: replaceAllMetadata, + replaceAllImages: replaceAllImages); + } + + ///Refreshes metadata for an item. + ///@param itemId Item id. + ///@param metadataRefreshMode (Optional) Specifies the metadata refresh mode. + ///@param imageRefreshMode (Optional) Specifies the image refresh mode. + ///@param replaceAllMetadata (Optional) Determines if metadata should be replaced. Only applicable if mode is FullRefresh. + ///@param replaceAllImages (Optional) Determines if images should be replaced. Only applicable if mode is FullRefresh. + @Post( + path: '/Items/{itemId}/Refresh', + optionalBody: true, + ) + Future _itemsItemIdRefreshPost({ + @Path('itemId') required String? itemId, + @Query('metadataRefreshMode') String? metadataRefreshMode, + @Query('imageRefreshMode') String? imageRefreshMode, + @Query('replaceAllMetadata') bool? replaceAllMetadata, + @Query('replaceAllImages') bool? replaceAllImages, + }); + + ///Gets items based on a query. + ///@param userId The user id supplied as query parameter; this is required when not using an API key. + ///@param maxOfficialRating Optional filter by maximum official rating (PG, PG-13, TV-MA, etc). + ///@param hasThemeSong Optional filter by items with theme songs. + ///@param hasThemeVideo Optional filter by items with theme videos. + ///@param hasSubtitles Optional filter by items with subtitles. + ///@param hasSpecialFeature Optional filter by items with special features. + ///@param hasTrailer Optional filter by items with trailers. + ///@param adjacentTo Optional. Return items that are siblings of a supplied item. + ///@param parentIndexNumber Optional filter by parent index number. + ///@param hasParentalRating Optional filter by items that have or do not have a parental rating. + ///@param isHd Optional filter by items that are HD or not. + ///@param is4K Optional filter by items that are 4K or not. + ///@param locationTypes Optional. If specified, results will be filtered based on LocationType. This allows multiple, comma delimited. + ///@param excludeLocationTypes Optional. If specified, results will be filtered based on the LocationType. This allows multiple, comma delimited. + ///@param isMissing Optional filter by items that are missing episodes or not. + ///@param isUnaired Optional filter by items that are unaired episodes or not. + ///@param minCommunityRating Optional filter by minimum community rating. + ///@param minCriticRating Optional filter by minimum critic rating. + ///@param minPremiereDate Optional. The minimum premiere date. Format = ISO. + ///@param minDateLastSaved Optional. The minimum last saved date. Format = ISO. + ///@param minDateLastSavedForUser Optional. The minimum last saved date for the current user. Format = ISO. + ///@param maxPremiereDate Optional. The maximum premiere date. Format = ISO. + ///@param hasOverview Optional filter by items that have an overview or not. + ///@param hasImdbId Optional filter by items that have an IMDb id or not. + ///@param hasTmdbId Optional filter by items that have a TMDb id or not. + ///@param hasTvdbId Optional filter by items that have a TVDb id or not. + ///@param isMovie Optional filter for live tv movies. + ///@param isSeries Optional filter for live tv series. + ///@param isNews Optional filter for live tv news. + ///@param isKids Optional filter for live tv kids. + ///@param isSports Optional filter for live tv sports. + ///@param excludeItemIds Optional. If specified, results will be filtered by excluding item ids. This allows multiple, comma delimited. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param recursive When searching within folders, this determines whether or not the search will be recursive. true/false. + ///@param searchTerm Optional. Filter based on a search term. + ///@param sortOrder Sort Order - Ascending, Descending. + ///@param parentId Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param fields Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines. + ///@param excludeItemTypes Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited. + ///@param includeItemTypes Optional. If specified, results will be filtered based on the item type. This allows multiple, comma delimited. + ///@param filters Optional. Specify additional filters to apply. This allows multiple, comma delimited. Options: IsFolder, IsNotFolder, IsUnplayed, IsPlayed, IsFavorite, IsResumable, Likes, Dislikes. + ///@param isFavorite Optional filter by items that are marked as favorite, or not. + ///@param mediaTypes Optional filter by MediaType. Allows multiple, comma delimited. + ///@param imageTypes Optional. If specified, results will be filtered based on those containing image types. This allows multiple, comma delimited. + ///@param sortBy Optional. Specify one or more sort orders, comma delimited. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime. + ///@param isPlayed Optional filter by items that are played, or not. + ///@param genres Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimited. + ///@param officialRatings Optional. If specified, results will be filtered based on OfficialRating. This allows multiple, pipe delimited. + ///@param tags Optional. If specified, results will be filtered based on tag. This allows multiple, pipe delimited. + ///@param years Optional. If specified, results will be filtered based on production year. This allows multiple, comma delimited. + ///@param enableUserData Optional, include user data. + ///@param imageTypeLimit Optional, the max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param person Optional. If specified, results will be filtered to include only those containing the specified person. + ///@param personIds Optional. If specified, results will be filtered to include only those containing the specified person id. + ///@param personTypes Optional. If specified, along with Person, results will be filtered to include only those containing the specified person and PersonType. Allows multiple, comma-delimited. + ///@param studios Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimited. + ///@param artists Optional. If specified, results will be filtered based on artists. This allows multiple, pipe delimited. + ///@param excludeArtistIds Optional. If specified, results will be filtered based on artist id. This allows multiple, pipe delimited. + ///@param artistIds Optional. If specified, results will be filtered to include only those containing the specified artist id. + ///@param albumArtistIds Optional. If specified, results will be filtered to include only those containing the specified album artist id. + ///@param contributingArtistIds Optional. If specified, results will be filtered to include only those containing the specified contributing artist id. + ///@param albums Optional. If specified, results will be filtered based on album. This allows multiple, pipe delimited. + ///@param albumIds Optional. If specified, results will be filtered based on album id. This allows multiple, pipe delimited. + ///@param ids Optional. If specific items are needed, specify a list of item id's to retrieve. This allows multiple, comma delimited. + ///@param videoTypes Optional filter by VideoType (videofile, dvd, bluray, iso). Allows multiple, comma delimited. + ///@param minOfficialRating Optional filter by minimum official rating (PG, PG-13, TV-MA, etc). + ///@param isLocked Optional filter by items that are locked. + ///@param isPlaceHolder Optional filter by items that are placeholders. + ///@param hasOfficialRating Optional filter by items that have official ratings. + ///@param collapseBoxSetItems Whether or not to hide items behind their boxsets. + ///@param minWidth Optional. Filter by the minimum width of the item. + ///@param minHeight Optional. Filter by the minimum height of the item. + ///@param maxWidth Optional. Filter by the maximum width of the item. + ///@param maxHeight Optional. Filter by the maximum height of the item. + ///@param is3D Optional filter by items that are 3D, or not. + ///@param seriesStatus Optional filter by Series Status. Allows multiple, comma delimited. + ///@param nameStartsWithOrGreater Optional filter by items whose name is sorted equally or greater than a given input string. + ///@param nameStartsWith Optional filter by items whose name is sorted equally than a given input string. + ///@param nameLessThan Optional filter by items whose name is equally or lesser than a given input string. + ///@param studioIds Optional. If specified, results will be filtered based on studio id. This allows multiple, pipe delimited. + ///@param genreIds Optional. If specified, results will be filtered based on genre id. This allows multiple, pipe delimited. + ///@param enableTotalRecordCount Optional. Enable the total record count. + ///@param enableImages Optional, include image information in output. + Future> itemsGet({ + String? userId, + String? maxOfficialRating, + bool? hasThemeSong, + bool? hasThemeVideo, + bool? hasSubtitles, + bool? hasSpecialFeature, + bool? hasTrailer, + String? adjacentTo, + int? parentIndexNumber, + bool? hasParentalRating, + bool? isHd, + bool? is4K, + List? locationTypes, + List? excludeLocationTypes, + bool? isMissing, + bool? isUnaired, + num? minCommunityRating, + num? minCriticRating, + DateTime? minPremiereDate, + DateTime? minDateLastSaved, + DateTime? minDateLastSavedForUser, + DateTime? maxPremiereDate, + bool? hasOverview, + bool? hasImdbId, + bool? hasTmdbId, + bool? hasTvdbId, + bool? isMovie, + bool? isSeries, + bool? isNews, + bool? isKids, + bool? isSports, + List? excludeItemIds, + int? startIndex, + int? limit, + bool? recursive, + String? searchTerm, + List? sortOrder, + String? parentId, + List? fields, + List? excludeItemTypes, + List? includeItemTypes, + List? filters, + bool? isFavorite, + List? mediaTypes, + List? imageTypes, + List? sortBy, + bool? isPlayed, + List? genres, + List? officialRatings, + List? tags, + List? years, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + String? person, + List? personIds, + List? personTypes, + List? studios, + List? artists, + List? excludeArtistIds, + List? artistIds, + List? albumArtistIds, + List? contributingArtistIds, + List? albums, + List? albumIds, + List? ids, + List? videoTypes, + String? minOfficialRating, + bool? isLocked, + bool? isPlaceHolder, + bool? hasOfficialRating, + bool? collapseBoxSetItems, + int? minWidth, + int? minHeight, + int? maxWidth, + int? maxHeight, + bool? is3D, + List? seriesStatus, + String? nameStartsWithOrGreater, + String? nameStartsWith, + String? nameLessThan, + List? studioIds, + List? genreIds, + bool? enableTotalRecordCount, + bool? enableImages, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _itemsGet( + userId: userId, + maxOfficialRating: maxOfficialRating, + hasThemeSong: hasThemeSong, + hasThemeVideo: hasThemeVideo, + hasSubtitles: hasSubtitles, + hasSpecialFeature: hasSpecialFeature, + hasTrailer: hasTrailer, + adjacentTo: adjacentTo, + parentIndexNumber: parentIndexNumber, + hasParentalRating: hasParentalRating, + isHd: isHd, + is4K: is4K, + locationTypes: locationTypeListToJson(locationTypes), + excludeLocationTypes: locationTypeListToJson(excludeLocationTypes), + isMissing: isMissing, + isUnaired: isUnaired, + minCommunityRating: minCommunityRating, + minCriticRating: minCriticRating, + minPremiereDate: minPremiereDate, + minDateLastSaved: minDateLastSaved, + minDateLastSavedForUser: minDateLastSavedForUser, + maxPremiereDate: maxPremiereDate, + hasOverview: hasOverview, + hasImdbId: hasImdbId, + hasTmdbId: hasTmdbId, + hasTvdbId: hasTvdbId, + isMovie: isMovie, + isSeries: isSeries, + isNews: isNews, + isKids: isKids, + isSports: isSports, + excludeItemIds: excludeItemIds, + startIndex: startIndex, + limit: limit, + recursive: recursive, + searchTerm: searchTerm, + sortOrder: sortOrderListToJson(sortOrder), + parentId: parentId, + fields: itemFieldsListToJson(fields), + excludeItemTypes: baseItemKindListToJson(excludeItemTypes), + includeItemTypes: baseItemKindListToJson(includeItemTypes), + filters: itemFilterListToJson(filters), + isFavorite: isFavorite, + mediaTypes: mediaTypeListToJson(mediaTypes), + imageTypes: imageTypeListToJson(imageTypes), + sortBy: itemSortByListToJson(sortBy), + isPlayed: isPlayed, + genres: genres, + officialRatings: officialRatings, + tags: tags, + years: years, + enableUserData: enableUserData, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes), + person: person, + personIds: personIds, + personTypes: personTypes, + studios: studios, + artists: artists, + excludeArtistIds: excludeArtistIds, + artistIds: artistIds, + albumArtistIds: albumArtistIds, + contributingArtistIds: contributingArtistIds, + albums: albums, + albumIds: albumIds, + ids: ids, + videoTypes: videoTypeListToJson(videoTypes), + minOfficialRating: minOfficialRating, + isLocked: isLocked, + isPlaceHolder: isPlaceHolder, + hasOfficialRating: hasOfficialRating, + collapseBoxSetItems: collapseBoxSetItems, + minWidth: minWidth, + minHeight: minHeight, + maxWidth: maxWidth, + maxHeight: maxHeight, + is3D: is3D, + seriesStatus: seriesStatusListToJson(seriesStatus), + nameStartsWithOrGreater: nameStartsWithOrGreater, + nameStartsWith: nameStartsWith, + nameLessThan: nameLessThan, + studioIds: studioIds, + genreIds: genreIds, + enableTotalRecordCount: enableTotalRecordCount, + enableImages: enableImages); + } + + ///Gets items based on a query. + ///@param userId The user id supplied as query parameter; this is required when not using an API key. + ///@param maxOfficialRating Optional filter by maximum official rating (PG, PG-13, TV-MA, etc). + ///@param hasThemeSong Optional filter by items with theme songs. + ///@param hasThemeVideo Optional filter by items with theme videos. + ///@param hasSubtitles Optional filter by items with subtitles. + ///@param hasSpecialFeature Optional filter by items with special features. + ///@param hasTrailer Optional filter by items with trailers. + ///@param adjacentTo Optional. Return items that are siblings of a supplied item. + ///@param parentIndexNumber Optional filter by parent index number. + ///@param hasParentalRating Optional filter by items that have or do not have a parental rating. + ///@param isHd Optional filter by items that are HD or not. + ///@param is4K Optional filter by items that are 4K or not. + ///@param locationTypes Optional. If specified, results will be filtered based on LocationType. This allows multiple, comma delimited. + ///@param excludeLocationTypes Optional. If specified, results will be filtered based on the LocationType. This allows multiple, comma delimited. + ///@param isMissing Optional filter by items that are missing episodes or not. + ///@param isUnaired Optional filter by items that are unaired episodes or not. + ///@param minCommunityRating Optional filter by minimum community rating. + ///@param minCriticRating Optional filter by minimum critic rating. + ///@param minPremiereDate Optional. The minimum premiere date. Format = ISO. + ///@param minDateLastSaved Optional. The minimum last saved date. Format = ISO. + ///@param minDateLastSavedForUser Optional. The minimum last saved date for the current user. Format = ISO. + ///@param maxPremiereDate Optional. The maximum premiere date. Format = ISO. + ///@param hasOverview Optional filter by items that have an overview or not. + ///@param hasImdbId Optional filter by items that have an IMDb id or not. + ///@param hasTmdbId Optional filter by items that have a TMDb id or not. + ///@param hasTvdbId Optional filter by items that have a TVDb id or not. + ///@param isMovie Optional filter for live tv movies. + ///@param isSeries Optional filter for live tv series. + ///@param isNews Optional filter for live tv news. + ///@param isKids Optional filter for live tv kids. + ///@param isSports Optional filter for live tv sports. + ///@param excludeItemIds Optional. If specified, results will be filtered by excluding item ids. This allows multiple, comma delimited. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param recursive When searching within folders, this determines whether or not the search will be recursive. true/false. + ///@param searchTerm Optional. Filter based on a search term. + ///@param sortOrder Sort Order - Ascending, Descending. + ///@param parentId Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param fields Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines. + ///@param excludeItemTypes Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited. + ///@param includeItemTypes Optional. If specified, results will be filtered based on the item type. This allows multiple, comma delimited. + ///@param filters Optional. Specify additional filters to apply. This allows multiple, comma delimited. Options: IsFolder, IsNotFolder, IsUnplayed, IsPlayed, IsFavorite, IsResumable, Likes, Dislikes. + ///@param isFavorite Optional filter by items that are marked as favorite, or not. + ///@param mediaTypes Optional filter by MediaType. Allows multiple, comma delimited. + ///@param imageTypes Optional. If specified, results will be filtered based on those containing image types. This allows multiple, comma delimited. + ///@param sortBy Optional. Specify one or more sort orders, comma delimited. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime. + ///@param isPlayed Optional filter by items that are played, or not. + ///@param genres Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimited. + ///@param officialRatings Optional. If specified, results will be filtered based on OfficialRating. This allows multiple, pipe delimited. + ///@param tags Optional. If specified, results will be filtered based on tag. This allows multiple, pipe delimited. + ///@param years Optional. If specified, results will be filtered based on production year. This allows multiple, comma delimited. + ///@param enableUserData Optional, include user data. + ///@param imageTypeLimit Optional, the max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param person Optional. If specified, results will be filtered to include only those containing the specified person. + ///@param personIds Optional. If specified, results will be filtered to include only those containing the specified person id. + ///@param personTypes Optional. If specified, along with Person, results will be filtered to include only those containing the specified person and PersonType. Allows multiple, comma-delimited. + ///@param studios Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimited. + ///@param artists Optional. If specified, results will be filtered based on artists. This allows multiple, pipe delimited. + ///@param excludeArtistIds Optional. If specified, results will be filtered based on artist id. This allows multiple, pipe delimited. + ///@param artistIds Optional. If specified, results will be filtered to include only those containing the specified artist id. + ///@param albumArtistIds Optional. If specified, results will be filtered to include only those containing the specified album artist id. + ///@param contributingArtistIds Optional. If specified, results will be filtered to include only those containing the specified contributing artist id. + ///@param albums Optional. If specified, results will be filtered based on album. This allows multiple, pipe delimited. + ///@param albumIds Optional. If specified, results will be filtered based on album id. This allows multiple, pipe delimited. + ///@param ids Optional. If specific items are needed, specify a list of item id's to retrieve. This allows multiple, comma delimited. + ///@param videoTypes Optional filter by VideoType (videofile, dvd, bluray, iso). Allows multiple, comma delimited. + ///@param minOfficialRating Optional filter by minimum official rating (PG, PG-13, TV-MA, etc). + ///@param isLocked Optional filter by items that are locked. + ///@param isPlaceHolder Optional filter by items that are placeholders. + ///@param hasOfficialRating Optional filter by items that have official ratings. + ///@param collapseBoxSetItems Whether or not to hide items behind their boxsets. + ///@param minWidth Optional. Filter by the minimum width of the item. + ///@param minHeight Optional. Filter by the minimum height of the item. + ///@param maxWidth Optional. Filter by the maximum width of the item. + ///@param maxHeight Optional. Filter by the maximum height of the item. + ///@param is3D Optional filter by items that are 3D, or not. + ///@param seriesStatus Optional filter by Series Status. Allows multiple, comma delimited. + ///@param nameStartsWithOrGreater Optional filter by items whose name is sorted equally or greater than a given input string. + ///@param nameStartsWith Optional filter by items whose name is sorted equally than a given input string. + ///@param nameLessThan Optional filter by items whose name is equally or lesser than a given input string. + ///@param studioIds Optional. If specified, results will be filtered based on studio id. This allows multiple, pipe delimited. + ///@param genreIds Optional. If specified, results will be filtered based on genre id. This allows multiple, pipe delimited. + ///@param enableTotalRecordCount Optional. Enable the total record count. + ///@param enableImages Optional, include image information in output. + @Get(path: '/Items') + Future> _itemsGet({ + @Query('userId') String? userId, + @Query('maxOfficialRating') String? maxOfficialRating, + @Query('hasThemeSong') bool? hasThemeSong, + @Query('hasThemeVideo') bool? hasThemeVideo, + @Query('hasSubtitles') bool? hasSubtitles, + @Query('hasSpecialFeature') bool? hasSpecialFeature, + @Query('hasTrailer') bool? hasTrailer, + @Query('adjacentTo') String? adjacentTo, + @Query('parentIndexNumber') int? parentIndexNumber, + @Query('hasParentalRating') bool? hasParentalRating, + @Query('isHd') bool? isHd, + @Query('is4K') bool? is4K, + @Query('locationTypes') List? locationTypes, + @Query('excludeLocationTypes') List? excludeLocationTypes, + @Query('isMissing') bool? isMissing, + @Query('isUnaired') bool? isUnaired, + @Query('minCommunityRating') num? minCommunityRating, + @Query('minCriticRating') num? minCriticRating, + @Query('minPremiereDate') DateTime? minPremiereDate, + @Query('minDateLastSaved') DateTime? minDateLastSaved, + @Query('minDateLastSavedForUser') DateTime? minDateLastSavedForUser, + @Query('maxPremiereDate') DateTime? maxPremiereDate, + @Query('hasOverview') bool? hasOverview, + @Query('hasImdbId') bool? hasImdbId, + @Query('hasTmdbId') bool? hasTmdbId, + @Query('hasTvdbId') bool? hasTvdbId, + @Query('isMovie') bool? isMovie, + @Query('isSeries') bool? isSeries, + @Query('isNews') bool? isNews, + @Query('isKids') bool? isKids, + @Query('isSports') bool? isSports, + @Query('excludeItemIds') List? excludeItemIds, + @Query('startIndex') int? startIndex, + @Query('limit') int? limit, + @Query('recursive') bool? recursive, + @Query('searchTerm') String? searchTerm, + @Query('sortOrder') List? sortOrder, + @Query('parentId') String? parentId, + @Query('fields') List? fields, + @Query('excludeItemTypes') List? excludeItemTypes, + @Query('includeItemTypes') List? includeItemTypes, + @Query('filters') List? filters, + @Query('isFavorite') bool? isFavorite, + @Query('mediaTypes') List? mediaTypes, + @Query('imageTypes') List? imageTypes, + @Query('sortBy') List? sortBy, + @Query('isPlayed') bool? isPlayed, + @Query('genres') List? genres, + @Query('officialRatings') List? officialRatings, + @Query('tags') List? tags, + @Query('years') List? years, + @Query('enableUserData') bool? enableUserData, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + @Query('person') String? person, + @Query('personIds') List? personIds, + @Query('personTypes') List? personTypes, + @Query('studios') List? studios, + @Query('artists') List? artists, + @Query('excludeArtistIds') List? excludeArtistIds, + @Query('artistIds') List? artistIds, + @Query('albumArtistIds') List? albumArtistIds, + @Query('contributingArtistIds') List? contributingArtistIds, + @Query('albums') List? albums, + @Query('albumIds') List? albumIds, + @Query('ids') List? ids, + @Query('videoTypes') List? videoTypes, + @Query('minOfficialRating') String? minOfficialRating, + @Query('isLocked') bool? isLocked, + @Query('isPlaceHolder') bool? isPlaceHolder, + @Query('hasOfficialRating') bool? hasOfficialRating, + @Query('collapseBoxSetItems') bool? collapseBoxSetItems, + @Query('minWidth') int? minWidth, + @Query('minHeight') int? minHeight, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('is3D') bool? is3D, + @Query('seriesStatus') List? seriesStatus, + @Query('nameStartsWithOrGreater') String? nameStartsWithOrGreater, + @Query('nameStartsWith') String? nameStartsWith, + @Query('nameLessThan') String? nameLessThan, + @Query('studioIds') List? studioIds, + @Query('genreIds') List? genreIds, + @Query('enableTotalRecordCount') bool? enableTotalRecordCount, + @Query('enableImages') bool? enableImages, + }); + + ///Deletes items from the library and filesystem. + ///@param ids The item ids. + Future itemsDelete({List? ids}) { + return _itemsDelete(ids: ids); + } + + ///Deletes items from the library and filesystem. + ///@param ids The item ids. + @Delete(path: '/Items') + Future _itemsDelete({@Query('ids') List? ids}); + + ///Get Item User Data. + ///@param userId The user id. + ///@param itemId The item id. + Future> userItemsItemIdUserDataGet({ + String? userId, + required String? itemId, + }) { + generatedMapping.putIfAbsent( + UserItemDataDto, () => UserItemDataDto.fromJsonFactory); + + return _userItemsItemIdUserDataGet(userId: userId, itemId: itemId); + } + + ///Get Item User Data. + ///@param userId The user id. + ///@param itemId The item id. + @Get(path: '/UserItems/{itemId}/UserData') + Future> _userItemsItemIdUserDataGet({ + @Query('userId') String? userId, + @Path('itemId') required String? itemId, + }); + + ///Update Item User Data. + ///@param userId The user id. + ///@param itemId The item id. + Future> userItemsItemIdUserDataPost({ + String? userId, + required String? itemId, + required UpdateUserItemDataDto? body, + }) { + generatedMapping.putIfAbsent( + UserItemDataDto, () => UserItemDataDto.fromJsonFactory); + + return _userItemsItemIdUserDataPost( + userId: userId, itemId: itemId, body: body); + } + + ///Update Item User Data. + ///@param userId The user id. + ///@param itemId The item id. + @Post( + path: '/UserItems/{itemId}/UserData', + optionalBody: true, + ) + Future> _userItemsItemIdUserDataPost({ + @Query('userId') String? userId, + @Path('itemId') required String? itemId, + @Body() required UpdateUserItemDataDto? body, + }); + + ///Gets items based on a query. + ///@param userId The user id. + ///@param startIndex The start index. + ///@param limit The item limit. + ///@param searchTerm The search term. + ///@param parentId Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param fields Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines. + ///@param mediaTypes Optional. Filter by MediaType. Allows multiple, comma delimited. + ///@param enableUserData Optional. Include user data. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param excludeItemTypes Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited. + ///@param includeItemTypes Optional. If specified, results will be filtered based on the item type. This allows multiple, comma delimited. + ///@param enableTotalRecordCount Optional. Enable the total record count. + ///@param enableImages Optional. Include image information in output. + ///@param excludeActiveSessions Optional. Whether to exclude the currently active sessions. + Future> userItemsResumeGet({ + String? userId, + int? startIndex, + int? limit, + String? searchTerm, + String? parentId, + List? fields, + List? mediaTypes, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + List? excludeItemTypes, + List? includeItemTypes, + bool? enableTotalRecordCount, + bool? enableImages, + bool? excludeActiveSessions, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _userItemsResumeGet( + userId: userId, + startIndex: startIndex, + limit: limit, + searchTerm: searchTerm, + parentId: parentId, + fields: itemFieldsListToJson(fields), + mediaTypes: mediaTypeListToJson(mediaTypes), + enableUserData: enableUserData, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes), + excludeItemTypes: baseItemKindListToJson(excludeItemTypes), + includeItemTypes: baseItemKindListToJson(includeItemTypes), + enableTotalRecordCount: enableTotalRecordCount, + enableImages: enableImages, + excludeActiveSessions: excludeActiveSessions); + } + + ///Gets items based on a query. + ///@param userId The user id. + ///@param startIndex The start index. + ///@param limit The item limit. + ///@param searchTerm The search term. + ///@param parentId Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param fields Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines. + ///@param mediaTypes Optional. Filter by MediaType. Allows multiple, comma delimited. + ///@param enableUserData Optional. Include user data. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param excludeItemTypes Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited. + ///@param includeItemTypes Optional. If specified, results will be filtered based on the item type. This allows multiple, comma delimited. + ///@param enableTotalRecordCount Optional. Enable the total record count. + ///@param enableImages Optional. Include image information in output. + ///@param excludeActiveSessions Optional. Whether to exclude the currently active sessions. + @Get(path: '/UserItems/Resume') + Future> _userItemsResumeGet({ + @Query('userId') String? userId, + @Query('startIndex') int? startIndex, + @Query('limit') int? limit, + @Query('searchTerm') String? searchTerm, + @Query('parentId') String? parentId, + @Query('fields') List? fields, + @Query('mediaTypes') List? mediaTypes, + @Query('enableUserData') bool? enableUserData, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + @Query('excludeItemTypes') List? excludeItemTypes, + @Query('includeItemTypes') List? includeItemTypes, + @Query('enableTotalRecordCount') bool? enableTotalRecordCount, + @Query('enableImages') bool? enableImages, + @Query('excludeActiveSessions') bool? excludeActiveSessions, + }); + + ///Updates an item. + ///@param itemId The item id. + Future itemsItemIdPost({ + required String? itemId, + required BaseItemDto? body, + }) { + return _itemsItemIdPost(itemId: itemId, body: body); + } + + ///Updates an item. + ///@param itemId The item id. + @Post( + path: '/Items/{itemId}', + optionalBody: true, + ) + Future _itemsItemIdPost({ + @Path('itemId') required String? itemId, + @Body() required BaseItemDto? body, + }); + + ///Deletes an item from the library and filesystem. + ///@param itemId The item id. + Future itemsItemIdDelete({required String? itemId}) { + return _itemsItemIdDelete(itemId: itemId); + } + + ///Deletes an item from the library and filesystem. + ///@param itemId The item id. + @Delete(path: '/Items/{itemId}') + Future _itemsItemIdDelete( + {@Path('itemId') required String? itemId}); + + ///Gets an item from a user's library. + ///@param userId User id. + ///@param itemId Item id. + Future> itemsItemIdGet({ + String? userId, + required String? itemId, + }) { + generatedMapping.putIfAbsent( + BaseItemDto, () => BaseItemDto.fromJsonFactory); + + return _itemsItemIdGet(userId: userId, itemId: itemId); + } + + ///Gets an item from a user's library. + ///@param userId User id. + ///@param itemId Item id. + @Get(path: '/Items/{itemId}') + Future> _itemsItemIdGet({ + @Query('userId') String? userId, + @Path('itemId') required String? itemId, + }); + + ///Updates an item's content type. + ///@param itemId The item id. + ///@param contentType The content type of the item. + Future itemsItemIdContentTypePost({ + required String? itemId, + String? contentType, + }) { + return _itemsItemIdContentTypePost( + itemId: itemId, contentType: contentType); + } + + ///Updates an item's content type. + ///@param itemId The item id. + ///@param contentType The content type of the item. + @Post( + path: '/Items/{itemId}/ContentType', + optionalBody: true, + ) + Future _itemsItemIdContentTypePost({ + @Path('itemId') required String? itemId, + @Query('contentType') String? contentType, + }); + + ///Gets metadata editor info for an item. + ///@param itemId The item id. + Future> itemsItemIdMetadataEditorGet( + {required String? itemId}) { + generatedMapping.putIfAbsent( + MetadataEditorInfo, () => MetadataEditorInfo.fromJsonFactory); + + return _itemsItemIdMetadataEditorGet(itemId: itemId); + } + + ///Gets metadata editor info for an item. + ///@param itemId The item id. + @Get(path: '/Items/{itemId}/MetadataEditor') + Future> _itemsItemIdMetadataEditorGet( + {@Path('itemId') required String? itemId}); + + ///Gets similar items. + ///@param itemId The item id. + ///@param excludeArtistIds Exclude artist ids. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls. + Future> albumsItemIdSimilarGet({ + required String? itemId, + List? excludeArtistIds, + String? userId, + int? limit, + List? fields, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _albumsItemIdSimilarGet( + itemId: itemId, + excludeArtistIds: excludeArtistIds, + userId: userId, + limit: limit, + fields: itemFieldsListToJson(fields)); + } + + ///Gets similar items. + ///@param itemId The item id. + ///@param excludeArtistIds Exclude artist ids. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls. + @Get(path: '/Albums/{itemId}/Similar') + Future> _albumsItemIdSimilarGet({ + @Path('itemId') required String? itemId, + @Query('excludeArtistIds') List? excludeArtistIds, + @Query('userId') String? userId, + @Query('limit') int? limit, + @Query('fields') List? fields, + }); + + ///Gets similar items. + ///@param itemId The item id. + ///@param excludeArtistIds Exclude artist ids. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls. + Future> artistsItemIdSimilarGet({ + required String? itemId, + List? excludeArtistIds, + String? userId, + int? limit, + List? fields, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _artistsItemIdSimilarGet( + itemId: itemId, + excludeArtistIds: excludeArtistIds, + userId: userId, + limit: limit, + fields: itemFieldsListToJson(fields)); + } + + ///Gets similar items. + ///@param itemId The item id. + ///@param excludeArtistIds Exclude artist ids. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls. + @Get(path: '/Artists/{itemId}/Similar') + Future> _artistsItemIdSimilarGet({ + @Path('itemId') required String? itemId, + @Query('excludeArtistIds') List? excludeArtistIds, + @Query('userId') String? userId, + @Query('limit') int? limit, + @Query('fields') List? fields, + }); + + ///Gets all parents of an item. + ///@param itemId The item id. + ///@param userId Optional. Filter by user id, and attach user data. + Future>> itemsItemIdAncestorsGet({ + required String? itemId, + String? userId, + }) { + generatedMapping.putIfAbsent( + BaseItemDto, () => BaseItemDto.fromJsonFactory); + + return _itemsItemIdAncestorsGet(itemId: itemId, userId: userId); + } + + ///Gets all parents of an item. + ///@param itemId The item id. + ///@param userId Optional. Filter by user id, and attach user data. + @Get(path: '/Items/{itemId}/Ancestors') + Future>> _itemsItemIdAncestorsGet({ + @Path('itemId') required String? itemId, + @Query('userId') String? userId, + }); + + ///Gets critic review for an item. + ///@param itemId + @deprecated + Future> itemsItemIdCriticReviewsGet( + {required String? itemId}) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _itemsItemIdCriticReviewsGet(itemId: itemId); + } + + ///Gets critic review for an item. + ///@param itemId + @deprecated + @Get(path: '/Items/{itemId}/CriticReviews') + Future> _itemsItemIdCriticReviewsGet( + {@Path('itemId') required String? itemId}); + + ///Downloads item media. + ///@param itemId The item id. + Future> itemsItemIdDownloadGet( + {required String? itemId}) { + return _itemsItemIdDownloadGet(itemId: itemId); + } + + ///Downloads item media. + ///@param itemId The item id. + @Get(path: '/Items/{itemId}/Download') + Future> _itemsItemIdDownloadGet( + {@Path('itemId') required String? itemId}); + + ///Get the original file of an item. + ///@param itemId The item id. + Future> itemsItemIdFileGet( + {required String? itemId}) { + return _itemsItemIdFileGet(itemId: itemId); + } + + ///Get the original file of an item. + ///@param itemId The item id. + @Get(path: '/Items/{itemId}/File') + Future> _itemsItemIdFileGet( + {@Path('itemId') required String? itemId}); + + ///Gets similar items. + ///@param itemId The item id. + ///@param excludeArtistIds Exclude artist ids. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls. + Future> itemsItemIdSimilarGet({ + required String? itemId, + List? excludeArtistIds, + String? userId, + int? limit, + List? fields, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _itemsItemIdSimilarGet( + itemId: itemId, + excludeArtistIds: excludeArtistIds, + userId: userId, + limit: limit, + fields: itemFieldsListToJson(fields)); + } + + ///Gets similar items. + ///@param itemId The item id. + ///@param excludeArtistIds Exclude artist ids. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls. + @Get(path: '/Items/{itemId}/Similar') + Future> _itemsItemIdSimilarGet({ + @Path('itemId') required String? itemId, + @Query('excludeArtistIds') List? excludeArtistIds, + @Query('userId') String? userId, + @Query('limit') int? limit, + @Query('fields') List? fields, + }); + + ///Get theme songs and videos for an item. + ///@param itemId The item id. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param inheritFromParent Optional. Determines whether or not parent items should be searched for theme media. + Future> itemsItemIdThemeMediaGet({ + required String? itemId, + String? userId, + bool? inheritFromParent, + }) { + generatedMapping.putIfAbsent( + AllThemeMediaResult, () => AllThemeMediaResult.fromJsonFactory); + + return _itemsItemIdThemeMediaGet( + itemId: itemId, userId: userId, inheritFromParent: inheritFromParent); + } + + ///Get theme songs and videos for an item. + ///@param itemId The item id. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param inheritFromParent Optional. Determines whether or not parent items should be searched for theme media. + @Get(path: '/Items/{itemId}/ThemeMedia') + Future> _itemsItemIdThemeMediaGet({ + @Path('itemId') required String? itemId, + @Query('userId') String? userId, + @Query('inheritFromParent') bool? inheritFromParent, + }); + + ///Get theme songs for an item. + ///@param itemId The item id. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param inheritFromParent Optional. Determines whether or not parent items should be searched for theme media. + Future> itemsItemIdThemeSongsGet({ + required String? itemId, + String? userId, + bool? inheritFromParent, + }) { + generatedMapping.putIfAbsent( + ThemeMediaResult, () => ThemeMediaResult.fromJsonFactory); + + return _itemsItemIdThemeSongsGet( + itemId: itemId, userId: userId, inheritFromParent: inheritFromParent); + } + + ///Get theme songs for an item. + ///@param itemId The item id. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param inheritFromParent Optional. Determines whether or not parent items should be searched for theme media. + @Get(path: '/Items/{itemId}/ThemeSongs') + Future> _itemsItemIdThemeSongsGet({ + @Path('itemId') required String? itemId, + @Query('userId') String? userId, + @Query('inheritFromParent') bool? inheritFromParent, + }); + + ///Get theme videos for an item. + ///@param itemId The item id. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param inheritFromParent Optional. Determines whether or not parent items should be searched for theme media. + Future> itemsItemIdThemeVideosGet({ + required String? itemId, + String? userId, + bool? inheritFromParent, + }) { + generatedMapping.putIfAbsent( + ThemeMediaResult, () => ThemeMediaResult.fromJsonFactory); + + return _itemsItemIdThemeVideosGet( + itemId: itemId, userId: userId, inheritFromParent: inheritFromParent); + } + + ///Get theme videos for an item. + ///@param itemId The item id. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param inheritFromParent Optional. Determines whether or not parent items should be searched for theme media. + @Get(path: '/Items/{itemId}/ThemeVideos') + Future> _itemsItemIdThemeVideosGet({ + @Path('itemId') required String? itemId, + @Query('userId') String? userId, + @Query('inheritFromParent') bool? inheritFromParent, + }); + + ///Get item counts. + ///@param userId Optional. Get counts from a specific user's library. + ///@param isFavorite Optional. Get counts of favorite items. + Future> itemsCountsGet({ + String? userId, + bool? isFavorite, + }) { + generatedMapping.putIfAbsent(ItemCounts, () => ItemCounts.fromJsonFactory); + + return _itemsCountsGet(userId: userId, isFavorite: isFavorite); + } + + ///Get item counts. + ///@param userId Optional. Get counts from a specific user's library. + ///@param isFavorite Optional. Get counts of favorite items. + @Get(path: '/Items/Counts') + Future> _itemsCountsGet({ + @Query('userId') String? userId, + @Query('isFavorite') bool? isFavorite, + }); + + ///Gets the library options info. + ///@param libraryContentType Library content type. + ///@param isNewLibrary Whether this is a new library. + Future> + librariesAvailableOptionsGet({ + enums.LibrariesAvailableOptionsGetLibraryContentType? libraryContentType, + bool? isNewLibrary, + }) { + generatedMapping.putIfAbsent( + LibraryOptionsResultDto, () => LibraryOptionsResultDto.fromJsonFactory); + + return _librariesAvailableOptionsGet( + libraryContentType: libraryContentType?.value?.toString(), + isNewLibrary: isNewLibrary); + } + + ///Gets the library options info. + ///@param libraryContentType Library content type. + ///@param isNewLibrary Whether this is a new library. + @Get(path: '/Libraries/AvailableOptions') + Future> + _librariesAvailableOptionsGet({ + @Query('libraryContentType') String? libraryContentType, + @Query('isNewLibrary') bool? isNewLibrary, + }); + + ///Reports that new movies have been added by an external source. + Future libraryMediaUpdatedPost( + {required MediaUpdateInfoDto? body}) { + return _libraryMediaUpdatedPost(body: body); + } + + ///Reports that new movies have been added by an external source. + @Post( + path: '/Library/Media/Updated', + optionalBody: true, + ) + Future _libraryMediaUpdatedPost( + {@Body() required MediaUpdateInfoDto? body}); + + ///Gets all user media folders. + ///@param isHidden Optional. Filter by folders that are marked hidden, or not. + Future> libraryMediaFoldersGet( + {bool? isHidden}) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _libraryMediaFoldersGet(isHidden: isHidden); + } + + ///Gets all user media folders. + ///@param isHidden Optional. Filter by folders that are marked hidden, or not. + @Get(path: '/Library/MediaFolders') + Future> _libraryMediaFoldersGet( + {@Query('isHidden') bool? isHidden}); + + ///Reports that new movies have been added by an external source. + ///@param tmdbId The tmdbId. + ///@param imdbId The imdbId. + Future libraryMoviesAddedPost({ + String? tmdbId, + String? imdbId, + }) { + return _libraryMoviesAddedPost(tmdbId: tmdbId, imdbId: imdbId); + } + + ///Reports that new movies have been added by an external source. + ///@param tmdbId The tmdbId. + ///@param imdbId The imdbId. + @Post( + path: '/Library/Movies/Added', + optionalBody: true, + ) + Future _libraryMoviesAddedPost({ + @Query('tmdbId') String? tmdbId, + @Query('imdbId') String? imdbId, + }); + + ///Reports that new movies have been added by an external source. + ///@param tmdbId The tmdbId. + ///@param imdbId The imdbId. + Future libraryMoviesUpdatedPost({ + String? tmdbId, + String? imdbId, + }) { + return _libraryMoviesUpdatedPost(tmdbId: tmdbId, imdbId: imdbId); + } + + ///Reports that new movies have been added by an external source. + ///@param tmdbId The tmdbId. + ///@param imdbId The imdbId. + @Post( + path: '/Library/Movies/Updated', + optionalBody: true, + ) + Future _libraryMoviesUpdatedPost({ + @Query('tmdbId') String? tmdbId, + @Query('imdbId') String? imdbId, + }); + + ///Gets a list of physical paths from virtual folders. + Future>> libraryPhysicalPathsGet() { + return _libraryPhysicalPathsGet(); + } + + ///Gets a list of physical paths from virtual folders. + @Get(path: '/Library/PhysicalPaths') + Future>> _libraryPhysicalPathsGet(); + + ///Starts a library scan. + Future libraryRefreshPost() { + return _libraryRefreshPost(); + } + + ///Starts a library scan. + @Post( + path: '/Library/Refresh', + optionalBody: true, + ) + Future _libraryRefreshPost(); + + ///Reports that new episodes of a series have been added by an external source. + ///@param tvdbId The tvdbId. + Future librarySeriesAddedPost({String? tvdbId}) { + return _librarySeriesAddedPost(tvdbId: tvdbId); + } + + ///Reports that new episodes of a series have been added by an external source. + ///@param tvdbId The tvdbId. + @Post( + path: '/Library/Series/Added', + optionalBody: true, + ) + Future _librarySeriesAddedPost( + {@Query('tvdbId') String? tvdbId}); + + ///Reports that new episodes of a series have been added by an external source. + ///@param tvdbId The tvdbId. + Future librarySeriesUpdatedPost({String? tvdbId}) { + return _librarySeriesUpdatedPost(tvdbId: tvdbId); + } + + ///Reports that new episodes of a series have been added by an external source. + ///@param tvdbId The tvdbId. + @Post( + path: '/Library/Series/Updated', + optionalBody: true, + ) + Future _librarySeriesUpdatedPost( + {@Query('tvdbId') String? tvdbId}); + + ///Gets similar items. + ///@param itemId The item id. + ///@param excludeArtistIds Exclude artist ids. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls. + Future> moviesItemIdSimilarGet({ + required String? itemId, + List? excludeArtistIds, + String? userId, + int? limit, + List? fields, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _moviesItemIdSimilarGet( + itemId: itemId, + excludeArtistIds: excludeArtistIds, + userId: userId, + limit: limit, + fields: itemFieldsListToJson(fields)); + } + + ///Gets similar items. + ///@param itemId The item id. + ///@param excludeArtistIds Exclude artist ids. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls. + @Get(path: '/Movies/{itemId}/Similar') + Future> _moviesItemIdSimilarGet({ + @Path('itemId') required String? itemId, + @Query('excludeArtistIds') List? excludeArtistIds, + @Query('userId') String? userId, + @Query('limit') int? limit, + @Query('fields') List? fields, + }); + + ///Gets similar items. + ///@param itemId The item id. + ///@param excludeArtistIds Exclude artist ids. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls. + Future> showsItemIdSimilarGet({ + required String? itemId, + List? excludeArtistIds, + String? userId, + int? limit, + List? fields, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _showsItemIdSimilarGet( + itemId: itemId, + excludeArtistIds: excludeArtistIds, + userId: userId, + limit: limit, + fields: itemFieldsListToJson(fields)); + } + + ///Gets similar items. + ///@param itemId The item id. + ///@param excludeArtistIds Exclude artist ids. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls. + @Get(path: '/Shows/{itemId}/Similar') + Future> _showsItemIdSimilarGet({ + @Path('itemId') required String? itemId, + @Query('excludeArtistIds') List? excludeArtistIds, + @Query('userId') String? userId, + @Query('limit') int? limit, + @Query('fields') List? fields, + }); + + ///Gets similar items. + ///@param itemId The item id. + ///@param excludeArtistIds Exclude artist ids. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls. + Future> trailersItemIdSimilarGet({ + required String? itemId, + List? excludeArtistIds, + String? userId, + int? limit, + List? fields, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _trailersItemIdSimilarGet( + itemId: itemId, + excludeArtistIds: excludeArtistIds, + userId: userId, + limit: limit, + fields: itemFieldsListToJson(fields)); + } + + ///Gets similar items. + ///@param itemId The item id. + ///@param excludeArtistIds Exclude artist ids. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls. + @Get(path: '/Trailers/{itemId}/Similar') + Future> _trailersItemIdSimilarGet({ + @Path('itemId') required String? itemId, + @Query('excludeArtistIds') List? excludeArtistIds, + @Query('userId') String? userId, + @Query('limit') int? limit, + @Query('fields') List? fields, + }); + + ///Gets all virtual folders. + Future>> libraryVirtualFoldersGet() { + generatedMapping.putIfAbsent( + VirtualFolderInfo, () => VirtualFolderInfo.fromJsonFactory); + + return _libraryVirtualFoldersGet(); + } + + ///Gets all virtual folders. + @Get(path: '/Library/VirtualFolders') + Future>> _libraryVirtualFoldersGet(); + + ///Adds a virtual folder. + ///@param name The name of the virtual folder. + ///@param collectionType The type of the collection. + ///@param paths The paths of the virtual folder. + ///@param refreshLibrary Whether to refresh the library. + Future libraryVirtualFoldersPost({ + String? name, + enums.LibraryVirtualFoldersPostCollectionType? collectionType, + List? paths, + bool? refreshLibrary, + required AddVirtualFolderDto? body, + }) { + return _libraryVirtualFoldersPost( + name: name, + collectionType: collectionType?.value?.toString(), + paths: paths, + refreshLibrary: refreshLibrary, + body: body); + } + + ///Adds a virtual folder. + ///@param name The name of the virtual folder. + ///@param collectionType The type of the collection. + ///@param paths The paths of the virtual folder. + ///@param refreshLibrary Whether to refresh the library. + @Post( + path: '/Library/VirtualFolders', + optionalBody: true, + ) + Future _libraryVirtualFoldersPost({ + @Query('name') String? name, + @Query('collectionType') String? collectionType, + @Query('paths') List? paths, + @Query('refreshLibrary') bool? refreshLibrary, + @Body() required AddVirtualFolderDto? body, + }); + + ///Removes a virtual folder. + ///@param name The name of the folder. + ///@param refreshLibrary Whether to refresh the library. + Future libraryVirtualFoldersDelete({ + String? name, + bool? refreshLibrary, + }) { + return _libraryVirtualFoldersDelete( + name: name, refreshLibrary: refreshLibrary); + } + + ///Removes a virtual folder. + ///@param name The name of the folder. + ///@param refreshLibrary Whether to refresh the library. + @Delete(path: '/Library/VirtualFolders') + Future _libraryVirtualFoldersDelete({ + @Query('name') String? name, + @Query('refreshLibrary') bool? refreshLibrary, + }); + + ///Update library options. + Future libraryVirtualFoldersLibraryOptionsPost( + {required UpdateLibraryOptionsDto? body}) { + return _libraryVirtualFoldersLibraryOptionsPost(body: body); + } + + ///Update library options. + @Post( + path: '/Library/VirtualFolders/LibraryOptions', + optionalBody: true, + ) + Future _libraryVirtualFoldersLibraryOptionsPost( + {@Body() required UpdateLibraryOptionsDto? body}); + + ///Renames a virtual folder. + ///@param name The name of the virtual folder. + ///@param newName The new name. + ///@param refreshLibrary Whether to refresh the library. + Future libraryVirtualFoldersNamePost({ + String? name, + String? newName, + bool? refreshLibrary, + }) { + return _libraryVirtualFoldersNamePost( + name: name, newName: newName, refreshLibrary: refreshLibrary); + } + + ///Renames a virtual folder. + ///@param name The name of the virtual folder. + ///@param newName The new name. + ///@param refreshLibrary Whether to refresh the library. + @Post( + path: '/Library/VirtualFolders/Name', + optionalBody: true, + ) + Future _libraryVirtualFoldersNamePost({ + @Query('name') String? name, + @Query('newName') String? newName, + @Query('refreshLibrary') bool? refreshLibrary, + }); + + ///Add a media path to a library. + ///@param refreshLibrary Whether to refresh the library. + Future libraryVirtualFoldersPathsPost({ + bool? refreshLibrary, + required MediaPathDto? body, + }) { + return _libraryVirtualFoldersPathsPost( + refreshLibrary: refreshLibrary, body: body); + } + + ///Add a media path to a library. + ///@param refreshLibrary Whether to refresh the library. + @Post( + path: '/Library/VirtualFolders/Paths', + optionalBody: true, + ) + Future _libraryVirtualFoldersPathsPost({ + @Query('refreshLibrary') bool? refreshLibrary, + @Body() required MediaPathDto? body, + }); + + ///Remove a media path. + ///@param name The name of the library. + ///@param path The path to remove. + ///@param refreshLibrary Whether to refresh the library. + Future libraryVirtualFoldersPathsDelete({ + String? name, + String? path, + bool? refreshLibrary, + }) { + return _libraryVirtualFoldersPathsDelete( + name: name, path: path, refreshLibrary: refreshLibrary); + } + + ///Remove a media path. + ///@param name The name of the library. + ///@param path The path to remove. + ///@param refreshLibrary Whether to refresh the library. + @Delete(path: '/Library/VirtualFolders/Paths') + Future _libraryVirtualFoldersPathsDelete({ + @Query('name') String? name, + @Query('path') String? path, + @Query('refreshLibrary') bool? refreshLibrary, + }); + + ///Updates a media path. + Future libraryVirtualFoldersPathsUpdatePost( + {required UpdateMediaPathRequestDto? body}) { + return _libraryVirtualFoldersPathsUpdatePost(body: body); + } + + ///Updates a media path. + @Post( + path: '/Library/VirtualFolders/Paths/Update', + optionalBody: true, + ) + Future _libraryVirtualFoldersPathsUpdatePost( + {@Body() required UpdateMediaPathRequestDto? body}); + + ///Get channel mapping options. + ///@param providerId Provider id. + Future> + liveTvChannelMappingOptionsGet({String? providerId}) { + generatedMapping.putIfAbsent(ChannelMappingOptionsDto, + () => ChannelMappingOptionsDto.fromJsonFactory); + + return _liveTvChannelMappingOptionsGet(providerId: providerId); + } + + ///Get channel mapping options. + ///@param providerId Provider id. + @Get(path: '/LiveTv/ChannelMappingOptions') + Future> + _liveTvChannelMappingOptionsGet( + {@Query('providerId') String? providerId}); + + ///Set channel mappings. + Future> liveTvChannelMappingsPost( + {required SetChannelMappingDto? body}) { + generatedMapping.putIfAbsent( + TunerChannelMapping, () => TunerChannelMapping.fromJsonFactory); + + return _liveTvChannelMappingsPost(body: body); + } + + ///Set channel mappings. + @Post( + path: '/LiveTv/ChannelMappings', + optionalBody: true, + ) + Future> _liveTvChannelMappingsPost( + {@Body() required SetChannelMappingDto? body}); + + ///Gets available live tv channels. + ///@param type Optional. Filter by channel type. + ///@param userId Optional. Filter by user and attach user data. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param isMovie Optional. Filter for movies. + ///@param isSeries Optional. Filter for series. + ///@param isNews Optional. Filter for news. + ///@param isKids Optional. Filter for kids. + ///@param isSports Optional. Filter for sports. + ///@param limit Optional. The maximum number of records to return. + ///@param isFavorite Optional. Filter by channels that are favorites, or not. + ///@param isLiked Optional. Filter by channels that are liked, or not. + ///@param isDisliked Optional. Filter by channels that are disliked, or not. + ///@param enableImages Optional. Include image information in output. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes "Optional. The image types to include in the output. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableUserData Optional. Include user data. + ///@param sortBy Optional. Key to sort by. + ///@param sortOrder Optional. Sort order. + ///@param enableFavoriteSorting Optional. Incorporate favorite and like status into channel sorting. + ///@param addCurrentProgram Optional. Adds current program info to each channel. + Future> liveTvChannelsGet({ + enums.LiveTvChannelsGetType? type, + String? userId, + int? startIndex, + bool? isMovie, + bool? isSeries, + bool? isNews, + bool? isKids, + bool? isSports, + int? limit, + bool? isFavorite, + bool? isLiked, + bool? isDisliked, + bool? enableImages, + int? imageTypeLimit, + List? enableImageTypes, + List? fields, + bool? enableUserData, + List? sortBy, + enums.LiveTvChannelsGetSortOrder? sortOrder, + bool? enableFavoriteSorting, + bool? addCurrentProgram, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _liveTvChannelsGet( + type: type?.value?.toString(), + userId: userId, + startIndex: startIndex, + isMovie: isMovie, + isSeries: isSeries, + isNews: isNews, + isKids: isKids, + isSports: isSports, + limit: limit, + isFavorite: isFavorite, + isLiked: isLiked, + isDisliked: isDisliked, + enableImages: enableImages, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes), + fields: itemFieldsListToJson(fields), + enableUserData: enableUserData, + sortBy: itemSortByListToJson(sortBy), + sortOrder: sortOrder?.value?.toString(), + enableFavoriteSorting: enableFavoriteSorting, + addCurrentProgram: addCurrentProgram); + } + + ///Gets available live tv channels. + ///@param type Optional. Filter by channel type. + ///@param userId Optional. Filter by user and attach user data. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param isMovie Optional. Filter for movies. + ///@param isSeries Optional. Filter for series. + ///@param isNews Optional. Filter for news. + ///@param isKids Optional. Filter for kids. + ///@param isSports Optional. Filter for sports. + ///@param limit Optional. The maximum number of records to return. + ///@param isFavorite Optional. Filter by channels that are favorites, or not. + ///@param isLiked Optional. Filter by channels that are liked, or not. + ///@param isDisliked Optional. Filter by channels that are disliked, or not. + ///@param enableImages Optional. Include image information in output. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes "Optional. The image types to include in the output. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableUserData Optional. Include user data. + ///@param sortBy Optional. Key to sort by. + ///@param sortOrder Optional. Sort order. + ///@param enableFavoriteSorting Optional. Incorporate favorite and like status into channel sorting. + ///@param addCurrentProgram Optional. Adds current program info to each channel. + @Get(path: '/LiveTv/Channels') + Future> _liveTvChannelsGet({ + @Query('type') String? type, + @Query('userId') String? userId, + @Query('startIndex') int? startIndex, + @Query('isMovie') bool? isMovie, + @Query('isSeries') bool? isSeries, + @Query('isNews') bool? isNews, + @Query('isKids') bool? isKids, + @Query('isSports') bool? isSports, + @Query('limit') int? limit, + @Query('isFavorite') bool? isFavorite, + @Query('isLiked') bool? isLiked, + @Query('isDisliked') bool? isDisliked, + @Query('enableImages') bool? enableImages, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + @Query('fields') List? fields, + @Query('enableUserData') bool? enableUserData, + @Query('sortBy') List? sortBy, + @Query('sortOrder') String? sortOrder, + @Query('enableFavoriteSorting') bool? enableFavoriteSorting, + @Query('addCurrentProgram') bool? addCurrentProgram, + }); + + ///Gets a live tv channel. + ///@param channelId Channel id. + ///@param userId Optional. Attach user data. + Future> liveTvChannelsChannelIdGet({ + required String? channelId, + String? userId, + }) { + generatedMapping.putIfAbsent( + BaseItemDto, () => BaseItemDto.fromJsonFactory); + + return _liveTvChannelsChannelIdGet(channelId: channelId, userId: userId); + } + + ///Gets a live tv channel. + ///@param channelId Channel id. + ///@param userId Optional. Attach user data. + @Get(path: '/LiveTv/Channels/{channelId}') + Future> _liveTvChannelsChannelIdGet({ + @Path('channelId') required String? channelId, + @Query('userId') String? userId, + }); + + ///Get guid info. + Future> liveTvGuideInfoGet() { + generatedMapping.putIfAbsent(GuideInfo, () => GuideInfo.fromJsonFactory); + + return _liveTvGuideInfoGet(); + } + + ///Get guid info. + @Get(path: '/LiveTv/GuideInfo') + Future> _liveTvGuideInfoGet(); + + ///Gets available live tv services. + Future> liveTvInfoGet() { + generatedMapping.putIfAbsent(LiveTvInfo, () => LiveTvInfo.fromJsonFactory); + + return _liveTvInfoGet(); + } + + ///Gets available live tv services. + @Get(path: '/LiveTv/Info') + Future> _liveTvInfoGet(); + + ///Adds a listings provider. + ///@param pw Password. + ///@param validateListings Validate listings. + ///@param validateLogin Validate login. + Future> liveTvListingProvidersPost({ + String? pw, + bool? validateListings, + bool? validateLogin, + required ListingsProviderInfo? body, + }) { + generatedMapping.putIfAbsent( + ListingsProviderInfo, () => ListingsProviderInfo.fromJsonFactory); + + return _liveTvListingProvidersPost( + pw: pw, + validateListings: validateListings, + validateLogin: validateLogin, + body: body); + } + + ///Adds a listings provider. + ///@param pw Password. + ///@param validateListings Validate listings. + ///@param validateLogin Validate login. + @Post( + path: '/LiveTv/ListingProviders', + optionalBody: true, + ) + Future> _liveTvListingProvidersPost({ + @Query('pw') String? pw, + @Query('validateListings') bool? validateListings, + @Query('validateLogin') bool? validateLogin, + @Body() required ListingsProviderInfo? body, + }); + + ///Delete listing provider. + ///@param id Listing provider id. + Future liveTvListingProvidersDelete({String? id}) { + return _liveTvListingProvidersDelete(id: id); + } + + ///Delete listing provider. + ///@param id Listing provider id. + @Delete(path: '/LiveTv/ListingProviders') + Future _liveTvListingProvidersDelete( + {@Query('id') String? id}); + + ///Gets default listings provider info. + Future> + liveTvListingProvidersDefaultGet() { + generatedMapping.putIfAbsent( + ListingsProviderInfo, () => ListingsProviderInfo.fromJsonFactory); + + return _liveTvListingProvidersDefaultGet(); + } + + ///Gets default listings provider info. + @Get(path: '/LiveTv/ListingProviders/Default') + Future> + _liveTvListingProvidersDefaultGet(); + + ///Gets available lineups. + ///@param id Provider id. + ///@param type Provider type. + ///@param location Location. + ///@param country Country. + Future>> liveTvListingProvidersLineupsGet({ + String? id, + String? type, + String? location, + String? country, + }) { + generatedMapping.putIfAbsent(NameIdPair, () => NameIdPair.fromJsonFactory); + + return _liveTvListingProvidersLineupsGet( + id: id, type: type, location: location, country: country); + } + + ///Gets available lineups. + ///@param id Provider id. + ///@param type Provider type. + ///@param location Location. + ///@param country Country. + @Get(path: '/LiveTv/ListingProviders/Lineups') + Future>> _liveTvListingProvidersLineupsGet({ + @Query('id') String? id, + @Query('type') String? type, + @Query('location') String? location, + @Query('country') String? country, + }); + + ///Gets available countries. + Future> + liveTvListingProvidersSchedulesDirectCountriesGet() { + return _liveTvListingProvidersSchedulesDirectCountriesGet(); + } + + ///Gets available countries. + @Get(path: '/LiveTv/ListingProviders/SchedulesDirect/Countries') + Future> + _liveTvListingProvidersSchedulesDirectCountriesGet(); + + ///Gets a live tv recording stream. + ///@param recordingId Recording id. + Future> liveTvLiveRecordingsRecordingIdStreamGet( + {required String? recordingId}) { + return _liveTvLiveRecordingsRecordingIdStreamGet(recordingId: recordingId); + } + + ///Gets a live tv recording stream. + ///@param recordingId Recording id. + @Get(path: '/LiveTv/LiveRecordings/{recordingId}/stream') + Future> _liveTvLiveRecordingsRecordingIdStreamGet( + {@Path('recordingId') required String? recordingId}); + + ///Gets a live tv channel stream. + ///@param streamId Stream id. + ///@param container Container type. + Future> + liveTvLiveStreamFilesStreamIdStreamContainerGet({ + required String? streamId, + required String? container, + }) { + return _liveTvLiveStreamFilesStreamIdStreamContainerGet( + streamId: streamId, container: container); + } + + ///Gets a live tv channel stream. + ///@param streamId Stream id. + ///@param container Container type. + @Get(path: '/LiveTv/LiveStreamFiles/{streamId}/stream.{container}') + Future> + _liveTvLiveStreamFilesStreamIdStreamContainerGet({ + @Path('streamId') required String? streamId, + @Path('container') required String? container, + }); + + ///Gets available live tv epgs. + ///@param channelIds The channels to return guide information for. + ///@param userId Optional. Filter by user id. + ///@param minStartDate Optional. The minimum premiere start date. + ///@param hasAired Optional. Filter by programs that have completed airing, or not. + ///@param isAiring Optional. Filter by programs that are currently airing, or not. + ///@param maxStartDate Optional. The maximum premiere start date. + ///@param minEndDate Optional. The minimum premiere end date. + ///@param maxEndDate Optional. The maximum premiere end date. + ///@param isMovie Optional. Filter for movies. + ///@param isSeries Optional. Filter for series. + ///@param isNews Optional. Filter for news. + ///@param isKids Optional. Filter for kids. + ///@param isSports Optional. Filter for sports. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param sortBy Optional. Specify one or more sort orders, comma delimited. Options: Name, StartDate. + ///@param sortOrder Sort Order - Ascending,Descending. + ///@param genres The genres to return guide information for. + ///@param genreIds The genre ids to return guide information for. + ///@param enableImages Optional. Include image information in output. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param enableUserData Optional. Include user data. + ///@param seriesTimerId Optional. Filter by series timer id. + ///@param librarySeriesId Optional. Filter by library series id. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableTotalRecordCount Retrieve total record count. + Future> liveTvProgramsGet({ + List? channelIds, + String? userId, + DateTime? minStartDate, + bool? hasAired, + bool? isAiring, + DateTime? maxStartDate, + DateTime? minEndDate, + DateTime? maxEndDate, + bool? isMovie, + bool? isSeries, + bool? isNews, + bool? isKids, + bool? isSports, + int? startIndex, + int? limit, + List? sortBy, + List? sortOrder, + List? genres, + List? genreIds, + bool? enableImages, + int? imageTypeLimit, + List? enableImageTypes, + bool? enableUserData, + String? seriesTimerId, + String? librarySeriesId, + List? fields, + bool? enableTotalRecordCount, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _liveTvProgramsGet( + channelIds: channelIds, + userId: userId, + minStartDate: minStartDate, + hasAired: hasAired, + isAiring: isAiring, + maxStartDate: maxStartDate, + minEndDate: minEndDate, + maxEndDate: maxEndDate, + isMovie: isMovie, + isSeries: isSeries, + isNews: isNews, + isKids: isKids, + isSports: isSports, + startIndex: startIndex, + limit: limit, + sortBy: itemSortByListToJson(sortBy), + sortOrder: sortOrderListToJson(sortOrder), + genres: genres, + genreIds: genreIds, + enableImages: enableImages, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes), + enableUserData: enableUserData, + seriesTimerId: seriesTimerId, + librarySeriesId: librarySeriesId, + fields: itemFieldsListToJson(fields), + enableTotalRecordCount: enableTotalRecordCount); + } + + ///Gets available live tv epgs. + ///@param channelIds The channels to return guide information for. + ///@param userId Optional. Filter by user id. + ///@param minStartDate Optional. The minimum premiere start date. + ///@param hasAired Optional. Filter by programs that have completed airing, or not. + ///@param isAiring Optional. Filter by programs that are currently airing, or not. + ///@param maxStartDate Optional. The maximum premiere start date. + ///@param minEndDate Optional. The minimum premiere end date. + ///@param maxEndDate Optional. The maximum premiere end date. + ///@param isMovie Optional. Filter for movies. + ///@param isSeries Optional. Filter for series. + ///@param isNews Optional. Filter for news. + ///@param isKids Optional. Filter for kids. + ///@param isSports Optional. Filter for sports. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param sortBy Optional. Specify one or more sort orders, comma delimited. Options: Name, StartDate. + ///@param sortOrder Sort Order - Ascending,Descending. + ///@param genres The genres to return guide information for. + ///@param genreIds The genre ids to return guide information for. + ///@param enableImages Optional. Include image information in output. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param enableUserData Optional. Include user data. + ///@param seriesTimerId Optional. Filter by series timer id. + ///@param librarySeriesId Optional. Filter by library series id. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableTotalRecordCount Retrieve total record count. + @Get(path: '/LiveTv/Programs') + Future> _liveTvProgramsGet({ + @Query('channelIds') List? channelIds, + @Query('userId') String? userId, + @Query('minStartDate') DateTime? minStartDate, + @Query('hasAired') bool? hasAired, + @Query('isAiring') bool? isAiring, + @Query('maxStartDate') DateTime? maxStartDate, + @Query('minEndDate') DateTime? minEndDate, + @Query('maxEndDate') DateTime? maxEndDate, + @Query('isMovie') bool? isMovie, + @Query('isSeries') bool? isSeries, + @Query('isNews') bool? isNews, + @Query('isKids') bool? isKids, + @Query('isSports') bool? isSports, + @Query('startIndex') int? startIndex, + @Query('limit') int? limit, + @Query('sortBy') List? sortBy, + @Query('sortOrder') List? sortOrder, + @Query('genres') List? genres, + @Query('genreIds') List? genreIds, + @Query('enableImages') bool? enableImages, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + @Query('enableUserData') bool? enableUserData, + @Query('seriesTimerId') String? seriesTimerId, + @Query('librarySeriesId') String? librarySeriesId, + @Query('fields') List? fields, + @Query('enableTotalRecordCount') bool? enableTotalRecordCount, + }); + + ///Gets available live tv epgs. + Future> liveTvProgramsPost( + {required GetProgramsDto? body}) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _liveTvProgramsPost(body: body); + } + + ///Gets available live tv epgs. + @Post( + path: '/LiveTv/Programs', + optionalBody: true, + ) + Future> _liveTvProgramsPost( + {@Body() required GetProgramsDto? body}); + + ///Gets a live tv program. + ///@param programId Program id. + ///@param userId Optional. Attach user data. + Future> liveTvProgramsProgramIdGet({ + required String? programId, + String? userId, + }) { + generatedMapping.putIfAbsent( + BaseItemDto, () => BaseItemDto.fromJsonFactory); + + return _liveTvProgramsProgramIdGet(programId: programId, userId: userId); + } + + ///Gets a live tv program. + ///@param programId Program id. + ///@param userId Optional. Attach user data. + @Get(path: '/LiveTv/Programs/{programId}') + Future> _liveTvProgramsProgramIdGet({ + @Path('programId') required String? programId, + @Query('userId') String? userId, + }); + + ///Gets recommended live tv epgs. + ///@param userId Optional. filter by user id. + ///@param limit Optional. The maximum number of records to return. + ///@param isAiring Optional. Filter by programs that are currently airing, or not. + ///@param hasAired Optional. Filter by programs that have completed airing, or not. + ///@param isSeries Optional. Filter for series. + ///@param isMovie Optional. Filter for movies. + ///@param isNews Optional. Filter for news. + ///@param isKids Optional. Filter for kids. + ///@param isSports Optional. Filter for sports. + ///@param enableImages Optional. Include image information in output. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param genreIds The genres to return guide information for. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableUserData Optional. include user data. + ///@param enableTotalRecordCount Retrieve total record count. + Future> + liveTvProgramsRecommendedGet({ + String? userId, + int? limit, + bool? isAiring, + bool? hasAired, + bool? isSeries, + bool? isMovie, + bool? isNews, + bool? isKids, + bool? isSports, + bool? enableImages, + int? imageTypeLimit, + List? enableImageTypes, + List? genreIds, + List? fields, + bool? enableUserData, + bool? enableTotalRecordCount, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _liveTvProgramsRecommendedGet( + userId: userId, + limit: limit, + isAiring: isAiring, + hasAired: hasAired, + isSeries: isSeries, + isMovie: isMovie, + isNews: isNews, + isKids: isKids, + isSports: isSports, + enableImages: enableImages, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes), + genreIds: genreIds, + fields: itemFieldsListToJson(fields), + enableUserData: enableUserData, + enableTotalRecordCount: enableTotalRecordCount); + } + + ///Gets recommended live tv epgs. + ///@param userId Optional. filter by user id. + ///@param limit Optional. The maximum number of records to return. + ///@param isAiring Optional. Filter by programs that are currently airing, or not. + ///@param hasAired Optional. Filter by programs that have completed airing, or not. + ///@param isSeries Optional. Filter for series. + ///@param isMovie Optional. Filter for movies. + ///@param isNews Optional. Filter for news. + ///@param isKids Optional. Filter for kids. + ///@param isSports Optional. Filter for sports. + ///@param enableImages Optional. Include image information in output. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param genreIds The genres to return guide information for. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableUserData Optional. include user data. + ///@param enableTotalRecordCount Retrieve total record count. + @Get(path: '/LiveTv/Programs/Recommended') + Future> + _liveTvProgramsRecommendedGet({ + @Query('userId') String? userId, + @Query('limit') int? limit, + @Query('isAiring') bool? isAiring, + @Query('hasAired') bool? hasAired, + @Query('isSeries') bool? isSeries, + @Query('isMovie') bool? isMovie, + @Query('isNews') bool? isNews, + @Query('isKids') bool? isKids, + @Query('isSports') bool? isSports, + @Query('enableImages') bool? enableImages, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + @Query('genreIds') List? genreIds, + @Query('fields') List? fields, + @Query('enableUserData') bool? enableUserData, + @Query('enableTotalRecordCount') bool? enableTotalRecordCount, + }); + + ///Gets live tv recordings. + ///@param channelId Optional. Filter by channel id. + ///@param userId Optional. Filter by user and attach user data. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param status Optional. Filter by recording status. + ///@param isInProgress Optional. Filter by recordings that are in progress, or not. + ///@param seriesTimerId Optional. Filter by recordings belonging to a series timer. + ///@param enableImages Optional. Include image information in output. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableUserData Optional. Include user data. + ///@param isMovie Optional. Filter for movies. + ///@param isSeries Optional. Filter for series. + ///@param isKids Optional. Filter for kids. + ///@param isSports Optional. Filter for sports. + ///@param isNews Optional. Filter for news. + ///@param isLibraryItem Optional. Filter for is library item. + ///@param enableTotalRecordCount Optional. Return total record count. + Future> liveTvRecordingsGet({ + String? channelId, + String? userId, + int? startIndex, + int? limit, + enums.LiveTvRecordingsGetStatus? status, + bool? isInProgress, + String? seriesTimerId, + bool? enableImages, + int? imageTypeLimit, + List? enableImageTypes, + List? fields, + bool? enableUserData, + bool? isMovie, + bool? isSeries, + bool? isKids, + bool? isSports, + bool? isNews, + bool? isLibraryItem, + bool? enableTotalRecordCount, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _liveTvRecordingsGet( + channelId: channelId, + userId: userId, + startIndex: startIndex, + limit: limit, + status: status?.value?.toString(), + isInProgress: isInProgress, + seriesTimerId: seriesTimerId, + enableImages: enableImages, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes), + fields: itemFieldsListToJson(fields), + enableUserData: enableUserData, + isMovie: isMovie, + isSeries: isSeries, + isKids: isKids, + isSports: isSports, + isNews: isNews, + isLibraryItem: isLibraryItem, + enableTotalRecordCount: enableTotalRecordCount); + } + + ///Gets live tv recordings. + ///@param channelId Optional. Filter by channel id. + ///@param userId Optional. Filter by user and attach user data. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param status Optional. Filter by recording status. + ///@param isInProgress Optional. Filter by recordings that are in progress, or not. + ///@param seriesTimerId Optional. Filter by recordings belonging to a series timer. + ///@param enableImages Optional. Include image information in output. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableUserData Optional. Include user data. + ///@param isMovie Optional. Filter for movies. + ///@param isSeries Optional. Filter for series. + ///@param isKids Optional. Filter for kids. + ///@param isSports Optional. Filter for sports. + ///@param isNews Optional. Filter for news. + ///@param isLibraryItem Optional. Filter for is library item. + ///@param enableTotalRecordCount Optional. Return total record count. + @Get(path: '/LiveTv/Recordings') + Future> _liveTvRecordingsGet({ + @Query('channelId') String? channelId, + @Query('userId') String? userId, + @Query('startIndex') int? startIndex, + @Query('limit') int? limit, + @Query('status') String? status, + @Query('isInProgress') bool? isInProgress, + @Query('seriesTimerId') String? seriesTimerId, + @Query('enableImages') bool? enableImages, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + @Query('fields') List? fields, + @Query('enableUserData') bool? enableUserData, + @Query('isMovie') bool? isMovie, + @Query('isSeries') bool? isSeries, + @Query('isKids') bool? isKids, + @Query('isSports') bool? isSports, + @Query('isNews') bool? isNews, + @Query('isLibraryItem') bool? isLibraryItem, + @Query('enableTotalRecordCount') bool? enableTotalRecordCount, + }); + + ///Gets a live tv recording. + ///@param recordingId Recording id. + ///@param userId Optional. Attach user data. + Future> liveTvRecordingsRecordingIdGet({ + required String? recordingId, + String? userId, + }) { + generatedMapping.putIfAbsent( + BaseItemDto, () => BaseItemDto.fromJsonFactory); + + return _liveTvRecordingsRecordingIdGet( + recordingId: recordingId, userId: userId); + } + + ///Gets a live tv recording. + ///@param recordingId Recording id. + ///@param userId Optional. Attach user data. + @Get(path: '/LiveTv/Recordings/{recordingId}') + Future> _liveTvRecordingsRecordingIdGet({ + @Path('recordingId') required String? recordingId, + @Query('userId') String? userId, + }); + + ///Deletes a live tv recording. + ///@param recordingId Recording id. + Future liveTvRecordingsRecordingIdDelete( + {required String? recordingId}) { + return _liveTvRecordingsRecordingIdDelete(recordingId: recordingId); + } + + ///Deletes a live tv recording. + ///@param recordingId Recording id. + @Delete(path: '/LiveTv/Recordings/{recordingId}') + Future _liveTvRecordingsRecordingIdDelete( + {@Path('recordingId') required String? recordingId}); + + ///Gets recording folders. + ///@param userId Optional. Filter by user and attach user data. + Future> liveTvRecordingsFoldersGet( + {String? userId}) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _liveTvRecordingsFoldersGet(userId: userId); + } + + ///Gets recording folders. + ///@param userId Optional. Filter by user and attach user data. + @Get(path: '/LiveTv/Recordings/Folders') + Future> _liveTvRecordingsFoldersGet( + {@Query('userId') String? userId}); + + ///Gets live tv recording groups. + ///@param userId Optional. Filter by user and attach user data. + @deprecated + Future> liveTvRecordingsGroupsGet( + {String? userId}) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _liveTvRecordingsGroupsGet(userId: userId); + } + + ///Gets live tv recording groups. + ///@param userId Optional. Filter by user and attach user data. + @deprecated + @Get(path: '/LiveTv/Recordings/Groups') + Future> _liveTvRecordingsGroupsGet( + {@Query('userId') String? userId}); + + ///Get recording group. + ///@param groupId Group id. + @deprecated + Future liveTvRecordingsGroupsGroupIdGet( + {required String? groupId}) { + return _liveTvRecordingsGroupsGroupIdGet(groupId: groupId); + } + + ///Get recording group. + ///@param groupId Group id. + @deprecated + @Get(path: '/LiveTv/Recordings/Groups/{groupId}') + Future _liveTvRecordingsGroupsGroupIdGet( + {@Path('groupId') required String? groupId}); + + ///Gets live tv recording series. + ///@param channelId Optional. Filter by channel id. + ///@param userId Optional. Filter by user and attach user data. + ///@param groupId Optional. Filter by recording group. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param status Optional. Filter by recording status. + ///@param isInProgress Optional. Filter by recordings that are in progress, or not. + ///@param seriesTimerId Optional. Filter by recordings belonging to a series timer. + ///@param enableImages Optional. Include image information in output. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableUserData Optional. Include user data. + ///@param enableTotalRecordCount Optional. Return total record count. + @deprecated + Future> liveTvRecordingsSeriesGet({ + String? channelId, + String? userId, + String? groupId, + int? startIndex, + int? limit, + enums.LiveTvRecordingsSeriesGetStatus? status, + bool? isInProgress, + String? seriesTimerId, + bool? enableImages, + int? imageTypeLimit, + List? enableImageTypes, + List? fields, + bool? enableUserData, + bool? enableTotalRecordCount, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _liveTvRecordingsSeriesGet( + channelId: channelId, + userId: userId, + groupId: groupId, + startIndex: startIndex, + limit: limit, + status: status?.value?.toString(), + isInProgress: isInProgress, + seriesTimerId: seriesTimerId, + enableImages: enableImages, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes), + fields: itemFieldsListToJson(fields), + enableUserData: enableUserData, + enableTotalRecordCount: enableTotalRecordCount); + } + + ///Gets live tv recording series. + ///@param channelId Optional. Filter by channel id. + ///@param userId Optional. Filter by user and attach user data. + ///@param groupId Optional. Filter by recording group. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param status Optional. Filter by recording status. + ///@param isInProgress Optional. Filter by recordings that are in progress, or not. + ///@param seriesTimerId Optional. Filter by recordings belonging to a series timer. + ///@param enableImages Optional. Include image information in output. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableUserData Optional. Include user data. + ///@param enableTotalRecordCount Optional. Return total record count. + @deprecated + @Get(path: '/LiveTv/Recordings/Series') + Future> _liveTvRecordingsSeriesGet({ + @Query('channelId') String? channelId, + @Query('userId') String? userId, + @Query('groupId') String? groupId, + @Query('startIndex') int? startIndex, + @Query('limit') int? limit, + @Query('status') String? status, + @Query('isInProgress') bool? isInProgress, + @Query('seriesTimerId') String? seriesTimerId, + @Query('enableImages') bool? enableImages, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + @Query('fields') List? fields, + @Query('enableUserData') bool? enableUserData, + @Query('enableTotalRecordCount') bool? enableTotalRecordCount, + }); + + ///Gets live tv series timers. + ///@param sortBy Optional. Sort by SortName or Priority. + ///@param sortOrder Optional. Sort in Ascending or Descending order. + Future> + liveTvSeriesTimersGet({ + String? sortBy, + enums.LiveTvSeriesTimersGetSortOrder? sortOrder, + }) { + generatedMapping.putIfAbsent(SeriesTimerInfoDtoQueryResult, + () => SeriesTimerInfoDtoQueryResult.fromJsonFactory); + + return _liveTvSeriesTimersGet( + sortBy: sortBy, sortOrder: sortOrder?.value?.toString()); + } + + ///Gets live tv series timers. + ///@param sortBy Optional. Sort by SortName or Priority. + ///@param sortOrder Optional. Sort in Ascending or Descending order. + @Get(path: '/LiveTv/SeriesTimers') + Future> + _liveTvSeriesTimersGet({ + @Query('sortBy') String? sortBy, + @Query('sortOrder') String? sortOrder, + }); + + ///Creates a live tv series timer. + Future liveTvSeriesTimersPost( + {required SeriesTimerInfoDto? body}) { + return _liveTvSeriesTimersPost(body: body); + } + + ///Creates a live tv series timer. + @Post( + path: '/LiveTv/SeriesTimers', + optionalBody: true, + ) + Future _liveTvSeriesTimersPost( + {@Body() required SeriesTimerInfoDto? body}); + + ///Gets a live tv series timer. + ///@param timerId Timer id. + Future> liveTvSeriesTimersTimerIdGet( + {required String? timerId}) { + generatedMapping.putIfAbsent( + SeriesTimerInfoDto, () => SeriesTimerInfoDto.fromJsonFactory); + + return _liveTvSeriesTimersTimerIdGet(timerId: timerId); + } + + ///Gets a live tv series timer. + ///@param timerId Timer id. + @Get(path: '/LiveTv/SeriesTimers/{timerId}') + Future> _liveTvSeriesTimersTimerIdGet( + {@Path('timerId') required String? timerId}); + + ///Cancels a live tv series timer. + ///@param timerId Timer id. + Future liveTvSeriesTimersTimerIdDelete( + {required String? timerId}) { + return _liveTvSeriesTimersTimerIdDelete(timerId: timerId); + } + + ///Cancels a live tv series timer. + ///@param timerId Timer id. + @Delete(path: '/LiveTv/SeriesTimers/{timerId}') + Future _liveTvSeriesTimersTimerIdDelete( + {@Path('timerId') required String? timerId}); + + ///Updates a live tv series timer. + ///@param timerId Timer id. + Future liveTvSeriesTimersTimerIdPost({ + required String? timerId, + required SeriesTimerInfoDto? body, + }) { + return _liveTvSeriesTimersTimerIdPost(timerId: timerId, body: body); + } + + ///Updates a live tv series timer. + ///@param timerId Timer id. + @Post( + path: '/LiveTv/SeriesTimers/{timerId}', + optionalBody: true, + ) + Future _liveTvSeriesTimersTimerIdPost({ + @Path('timerId') required String? timerId, + @Body() required SeriesTimerInfoDto? body, + }); + + ///Gets the live tv timers. + ///@param channelId Optional. Filter by channel id. + ///@param seriesTimerId Optional. Filter by timers belonging to a series timer. + ///@param isActive Optional. Filter by timers that are active. + ///@param isScheduled Optional. Filter by timers that are scheduled. + Future> liveTvTimersGet({ + String? channelId, + String? seriesTimerId, + bool? isActive, + bool? isScheduled, + }) { + generatedMapping.putIfAbsent( + TimerInfoDtoQueryResult, () => TimerInfoDtoQueryResult.fromJsonFactory); + + return _liveTvTimersGet( + channelId: channelId, + seriesTimerId: seriesTimerId, + isActive: isActive, + isScheduled: isScheduled); + } + + ///Gets the live tv timers. + ///@param channelId Optional. Filter by channel id. + ///@param seriesTimerId Optional. Filter by timers belonging to a series timer. + ///@param isActive Optional. Filter by timers that are active. + ///@param isScheduled Optional. Filter by timers that are scheduled. + @Get(path: '/LiveTv/Timers') + Future> _liveTvTimersGet({ + @Query('channelId') String? channelId, + @Query('seriesTimerId') String? seriesTimerId, + @Query('isActive') bool? isActive, + @Query('isScheduled') bool? isScheduled, + }); + + ///Creates a live tv timer. + Future liveTvTimersPost({required TimerInfoDto? body}) { + return _liveTvTimersPost(body: body); + } + + ///Creates a live tv timer. + @Post( + path: '/LiveTv/Timers', + optionalBody: true, + ) + Future _liveTvTimersPost( + {@Body() required TimerInfoDto? body}); + + ///Gets a timer. + ///@param timerId Timer id. + Future> liveTvTimersTimerIdGet( + {required String? timerId}) { + generatedMapping.putIfAbsent( + TimerInfoDto, () => TimerInfoDto.fromJsonFactory); + + return _liveTvTimersTimerIdGet(timerId: timerId); + } + + ///Gets a timer. + ///@param timerId Timer id. + @Get(path: '/LiveTv/Timers/{timerId}') + Future> _liveTvTimersTimerIdGet( + {@Path('timerId') required String? timerId}); + + ///Cancels a live tv timer. + ///@param timerId Timer id. + Future liveTvTimersTimerIdDelete( + {required String? timerId}) { + return _liveTvTimersTimerIdDelete(timerId: timerId); + } + + ///Cancels a live tv timer. + ///@param timerId Timer id. + @Delete(path: '/LiveTv/Timers/{timerId}') + Future _liveTvTimersTimerIdDelete( + {@Path('timerId') required String? timerId}); + + ///Updates a live tv timer. + ///@param timerId Timer id. + Future liveTvTimersTimerIdPost({ + required String? timerId, + required TimerInfoDto? body, + }) { + return _liveTvTimersTimerIdPost(timerId: timerId, body: body); + } + + ///Updates a live tv timer. + ///@param timerId Timer id. + @Post( + path: '/LiveTv/Timers/{timerId}', + optionalBody: true, + ) + Future _liveTvTimersTimerIdPost({ + @Path('timerId') required String? timerId, + @Body() required TimerInfoDto? body, + }); + + ///Gets the default values for a new timer. + ///@param programId Optional. To attach default values based on a program. + Future> liveTvTimersDefaultsGet( + {String? programId}) { + generatedMapping.putIfAbsent( + SeriesTimerInfoDto, () => SeriesTimerInfoDto.fromJsonFactory); + + return _liveTvTimersDefaultsGet(programId: programId); + } + + ///Gets the default values for a new timer. + ///@param programId Optional. To attach default values based on a program. + @Get(path: '/LiveTv/Timers/Defaults') + Future> _liveTvTimersDefaultsGet( + {@Query('programId') String? programId}); + + ///Adds a tuner host. + Future> liveTvTunerHostsPost( + {required TunerHostInfo? body}) { + generatedMapping.putIfAbsent( + TunerHostInfo, () => TunerHostInfo.fromJsonFactory); + + return _liveTvTunerHostsPost(body: body); + } + + ///Adds a tuner host. + @Post( + path: '/LiveTv/TunerHosts', + optionalBody: true, + ) + Future> _liveTvTunerHostsPost( + {@Body() required TunerHostInfo? body}); + + ///Deletes a tuner host. + ///@param id Tuner host id. + Future liveTvTunerHostsDelete({String? id}) { + return _liveTvTunerHostsDelete(id: id); + } + + ///Deletes a tuner host. + ///@param id Tuner host id. + @Delete(path: '/LiveTv/TunerHosts') + Future _liveTvTunerHostsDelete({@Query('id') String? id}); + + ///Get tuner host types. + Future>> liveTvTunerHostsTypesGet() { + generatedMapping.putIfAbsent(NameIdPair, () => NameIdPair.fromJsonFactory); + + return _liveTvTunerHostsTypesGet(); + } + + ///Get tuner host types. + @Get(path: '/LiveTv/TunerHosts/Types') + Future>> _liveTvTunerHostsTypesGet(); + + ///Resets a tv tuner. + ///@param tunerId Tuner id. + Future liveTvTunersTunerIdResetPost( + {required String? tunerId}) { + return _liveTvTunersTunerIdResetPost(tunerId: tunerId); + } + + ///Resets a tv tuner. + ///@param tunerId Tuner id. + @Post( + path: '/LiveTv/Tuners/{tunerId}/Reset', + optionalBody: true, + ) + Future _liveTvTunersTunerIdResetPost( + {@Path('tunerId') required String? tunerId}); + + ///Discover tuners. + ///@param newDevicesOnly Only discover new tuners. + Future>> liveTvTunersDiscoverGet( + {bool? newDevicesOnly}) { + generatedMapping.putIfAbsent( + TunerHostInfo, () => TunerHostInfo.fromJsonFactory); + + return _liveTvTunersDiscoverGet(newDevicesOnly: newDevicesOnly); + } + + ///Discover tuners. + ///@param newDevicesOnly Only discover new tuners. + @Get(path: '/LiveTv/Tuners/Discover') + Future>> _liveTvTunersDiscoverGet( + {@Query('newDevicesOnly') bool? newDevicesOnly}); + + ///Discover tuners. + ///@param newDevicesOnly Only discover new tuners. + Future>> liveTvTunersDiscvoverGet( + {bool? newDevicesOnly}) { + generatedMapping.putIfAbsent( + TunerHostInfo, () => TunerHostInfo.fromJsonFactory); + + return _liveTvTunersDiscvoverGet(newDevicesOnly: newDevicesOnly); + } + + ///Discover tuners. + ///@param newDevicesOnly Only discover new tuners. + @Get(path: '/LiveTv/Tuners/Discvover') + Future>> _liveTvTunersDiscvoverGet( + {@Query('newDevicesOnly') bool? newDevicesOnly}); + + ///Gets known countries. + Future>> localizationCountriesGet() { + generatedMapping.putIfAbsent( + CountryInfo, () => CountryInfo.fromJsonFactory); + + return _localizationCountriesGet(); + } + + ///Gets known countries. + @Get(path: '/Localization/Countries') + Future>> _localizationCountriesGet(); + + ///Gets known cultures. + Future>> localizationCulturesGet() { + generatedMapping.putIfAbsent(CultureDto, () => CultureDto.fromJsonFactory); + + return _localizationCulturesGet(); + } + + ///Gets known cultures. + @Get(path: '/Localization/Cultures') + Future>> _localizationCulturesGet(); + + ///Gets localization options. + Future>> localizationOptionsGet() { + generatedMapping.putIfAbsent( + LocalizationOption, () => LocalizationOption.fromJsonFactory); + + return _localizationOptionsGet(); + } + + ///Gets localization options. + @Get(path: '/Localization/Options') + Future>> _localizationOptionsGet(); + + ///Gets known parental ratings. + Future>> + localizationParentalRatingsGet() { + generatedMapping.putIfAbsent( + ParentalRating, () => ParentalRating.fromJsonFactory); + + return _localizationParentalRatingsGet(); + } + + ///Gets known parental ratings. + @Get(path: '/Localization/ParentalRatings') + Future>> + _localizationParentalRatingsGet(); + + ///Gets an item's lyrics. + ///@param itemId Item id. + Future> audioItemIdLyricsGet( + {required String? itemId}) { + generatedMapping.putIfAbsent(LyricDto, () => LyricDto.fromJsonFactory); + + return _audioItemIdLyricsGet(itemId: itemId); + } + + ///Gets an item's lyrics. + ///@param itemId Item id. + @Get(path: '/Audio/{itemId}/Lyrics') + Future> _audioItemIdLyricsGet( + {@Path('itemId') required String? itemId}); + + ///Upload an external lyric file. + ///@param itemId The item the lyric belongs to. + ///@param fileName Name of the file being uploaded. + Future> audioItemIdLyricsPost({ + required String? itemId, + required String? fileName, + required Object? body, + }) { + generatedMapping.putIfAbsent(LyricDto, () => LyricDto.fromJsonFactory); + + return _audioItemIdLyricsPost( + itemId: itemId, fileName: fileName, body: body); + } + + ///Upload an external lyric file. + ///@param itemId The item the lyric belongs to. + ///@param fileName Name of the file being uploaded. + @Post( + path: '/Audio/{itemId}/Lyrics', + optionalBody: true, + ) + Future> _audioItemIdLyricsPost({ + @Path('itemId') required String? itemId, + @Query('fileName') required String? fileName, + @Body() required Object? body, + }); + + ///Deletes an external lyric file. + ///@param itemId The item id. + Future audioItemIdLyricsDelete({required String? itemId}) { + return _audioItemIdLyricsDelete(itemId: itemId); + } + + ///Deletes an external lyric file. + ///@param itemId The item id. + @Delete(path: '/Audio/{itemId}/Lyrics') + Future _audioItemIdLyricsDelete( + {@Path('itemId') required String? itemId}); + + ///Search remote lyrics. + ///@param itemId The item id. + Future>> + audioItemIdRemoteSearchLyricsGet({required String? itemId}) { + generatedMapping.putIfAbsent( + RemoteLyricInfoDto, () => RemoteLyricInfoDto.fromJsonFactory); + + return _audioItemIdRemoteSearchLyricsGet(itemId: itemId); + } + + ///Search remote lyrics. + ///@param itemId The item id. + @Get(path: '/Audio/{itemId}/RemoteSearch/Lyrics') + Future>> + _audioItemIdRemoteSearchLyricsGet( + {@Path('itemId') required String? itemId}); + + ///Downloads a remote lyric. + ///@param itemId The item id. + ///@param lyricId The lyric id. + Future> audioItemIdRemoteSearchLyricsLyricIdPost({ + required String? itemId, + required String? lyricId, + }) { + generatedMapping.putIfAbsent(LyricDto, () => LyricDto.fromJsonFactory); + + return _audioItemIdRemoteSearchLyricsLyricIdPost( + itemId: itemId, lyricId: lyricId); + } + + ///Downloads a remote lyric. + ///@param itemId The item id. + ///@param lyricId The lyric id. + @Post( + path: '/Audio/{itemId}/RemoteSearch/Lyrics/{lyricId}', + optionalBody: true, + ) + Future> _audioItemIdRemoteSearchLyricsLyricIdPost({ + @Path('itemId') required String? itemId, + @Path('lyricId') required String? lyricId, + }); + + ///Gets the remote lyrics. + ///@param lyricId The remote provider item id. + Future> providersLyricsLyricIdGet( + {required String? lyricId}) { + generatedMapping.putIfAbsent(LyricDto, () => LyricDto.fromJsonFactory); + + return _providersLyricsLyricIdGet(lyricId: lyricId); + } + + ///Gets the remote lyrics. + ///@param lyricId The remote provider item id. + @Get(path: '/Providers/Lyrics/{lyricId}') + Future> _providersLyricsLyricIdGet( + {@Path('lyricId') required String? lyricId}); + + ///Gets live playback media info for an item. + ///@param itemId The item id. + ///@param userId The user id. + Future> itemsItemIdPlaybackInfoGet({ + required String? itemId, + String? userId, + }) { + generatedMapping.putIfAbsent( + PlaybackInfoResponse, () => PlaybackInfoResponse.fromJsonFactory); + + return _itemsItemIdPlaybackInfoGet(itemId: itemId, userId: userId); + } + + ///Gets live playback media info for an item. + ///@param itemId The item id. + ///@param userId The user id. + @Get(path: '/Items/{itemId}/PlaybackInfo') + Future> _itemsItemIdPlaybackInfoGet({ + @Path('itemId') required String? itemId, + @Query('userId') String? userId, + }); + + ///Gets live playback media info for an item. + ///@param itemId The item id. + ///@param userId The user id. + ///@param maxStreamingBitrate The maximum streaming bitrate. + ///@param startTimeTicks The start time in ticks. + ///@param audioStreamIndex The audio stream index. + ///@param subtitleStreamIndex The subtitle stream index. + ///@param maxAudioChannels The maximum number of audio channels. + ///@param mediaSourceId The media source id. + ///@param liveStreamId The livestream id. + ///@param autoOpenLiveStream Whether to auto open the livestream. + ///@param enableDirectPlay Whether to enable direct play. Default: true. + ///@param enableDirectStream Whether to enable direct stream. Default: true. + ///@param enableTranscoding Whether to enable transcoding. Default: true. + ///@param allowVideoStreamCopy Whether to allow to copy the video stream. Default: true. + ///@param allowAudioStreamCopy Whether to allow to copy the audio stream. Default: true. + Future> itemsItemIdPlaybackInfoPost({ + required String? itemId, + String? userId, + int? maxStreamingBitrate, + int? startTimeTicks, + int? audioStreamIndex, + int? subtitleStreamIndex, + int? maxAudioChannels, + String? mediaSourceId, + String? liveStreamId, + bool? autoOpenLiveStream, + bool? enableDirectPlay, + bool? enableDirectStream, + bool? enableTranscoding, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + required PlaybackInfoDto? body, + }) { + generatedMapping.putIfAbsent( + PlaybackInfoResponse, () => PlaybackInfoResponse.fromJsonFactory); + + return _itemsItemIdPlaybackInfoPost( + itemId: itemId, + userId: userId, + maxStreamingBitrate: maxStreamingBitrate, + startTimeTicks: startTimeTicks, + audioStreamIndex: audioStreamIndex, + subtitleStreamIndex: subtitleStreamIndex, + maxAudioChannels: maxAudioChannels, + mediaSourceId: mediaSourceId, + liveStreamId: liveStreamId, + autoOpenLiveStream: autoOpenLiveStream, + enableDirectPlay: enableDirectPlay, + enableDirectStream: enableDirectStream, + enableTranscoding: enableTranscoding, + allowVideoStreamCopy: allowVideoStreamCopy, + allowAudioStreamCopy: allowAudioStreamCopy, + body: body); + } + + ///Gets live playback media info for an item. + ///@param itemId The item id. + ///@param userId The user id. + ///@param maxStreamingBitrate The maximum streaming bitrate. + ///@param startTimeTicks The start time in ticks. + ///@param audioStreamIndex The audio stream index. + ///@param subtitleStreamIndex The subtitle stream index. + ///@param maxAudioChannels The maximum number of audio channels. + ///@param mediaSourceId The media source id. + ///@param liveStreamId The livestream id. + ///@param autoOpenLiveStream Whether to auto open the livestream. + ///@param enableDirectPlay Whether to enable direct play. Default: true. + ///@param enableDirectStream Whether to enable direct stream. Default: true. + ///@param enableTranscoding Whether to enable transcoding. Default: true. + ///@param allowVideoStreamCopy Whether to allow to copy the video stream. Default: true. + ///@param allowAudioStreamCopy Whether to allow to copy the audio stream. Default: true. + @Post( + path: '/Items/{itemId}/PlaybackInfo', + optionalBody: true, + ) + Future> _itemsItemIdPlaybackInfoPost({ + @Path('itemId') required String? itemId, + @Query('userId') String? userId, + @Query('maxStreamingBitrate') int? maxStreamingBitrate, + @Query('startTimeTicks') int? startTimeTicks, + @Query('audioStreamIndex') int? audioStreamIndex, + @Query('subtitleStreamIndex') int? subtitleStreamIndex, + @Query('maxAudioChannels') int? maxAudioChannels, + @Query('mediaSourceId') String? mediaSourceId, + @Query('liveStreamId') String? liveStreamId, + @Query('autoOpenLiveStream') bool? autoOpenLiveStream, + @Query('enableDirectPlay') bool? enableDirectPlay, + @Query('enableDirectStream') bool? enableDirectStream, + @Query('enableTranscoding') bool? enableTranscoding, + @Query('allowVideoStreamCopy') bool? allowVideoStreamCopy, + @Query('allowAudioStreamCopy') bool? allowAudioStreamCopy, + @Body() required PlaybackInfoDto? body, + }); + + ///Closes a media source. + ///@param liveStreamId The livestream id. + Future liveStreamsClosePost( + {required String? liveStreamId}) { + return _liveStreamsClosePost(liveStreamId: liveStreamId); + } + + ///Closes a media source. + ///@param liveStreamId The livestream id. + @Post( + path: '/LiveStreams/Close', + optionalBody: true, + ) + Future _liveStreamsClosePost( + {@Query('liveStreamId') required String? liveStreamId}); + + ///Opens a media source. + ///@param openToken The open token. + ///@param userId The user id. + ///@param playSessionId The play session id. + ///@param maxStreamingBitrate The maximum streaming bitrate. + ///@param startTimeTicks The start time in ticks. + ///@param audioStreamIndex The audio stream index. + ///@param subtitleStreamIndex The subtitle stream index. + ///@param maxAudioChannels The maximum number of audio channels. + ///@param itemId The item id. + ///@param enableDirectPlay Whether to enable direct play. Default: true. + ///@param enableDirectStream Whether to enable direct stream. Default: true. + Future> liveStreamsOpenPost({ + String? openToken, + String? userId, + String? playSessionId, + int? maxStreamingBitrate, + int? startTimeTicks, + int? audioStreamIndex, + int? subtitleStreamIndex, + int? maxAudioChannels, + String? itemId, + bool? enableDirectPlay, + bool? enableDirectStream, + required OpenLiveStreamDto? body, + }) { + generatedMapping.putIfAbsent( + LiveStreamResponse, () => LiveStreamResponse.fromJsonFactory); + + return _liveStreamsOpenPost( + openToken: openToken, + userId: userId, + playSessionId: playSessionId, + maxStreamingBitrate: maxStreamingBitrate, + startTimeTicks: startTimeTicks, + audioStreamIndex: audioStreamIndex, + subtitleStreamIndex: subtitleStreamIndex, + maxAudioChannels: maxAudioChannels, + itemId: itemId, + enableDirectPlay: enableDirectPlay, + enableDirectStream: enableDirectStream, + body: body); + } + + ///Opens a media source. + ///@param openToken The open token. + ///@param userId The user id. + ///@param playSessionId The play session id. + ///@param maxStreamingBitrate The maximum streaming bitrate. + ///@param startTimeTicks The start time in ticks. + ///@param audioStreamIndex The audio stream index. + ///@param subtitleStreamIndex The subtitle stream index. + ///@param maxAudioChannels The maximum number of audio channels. + ///@param itemId The item id. + ///@param enableDirectPlay Whether to enable direct play. Default: true. + ///@param enableDirectStream Whether to enable direct stream. Default: true. + @Post( + path: '/LiveStreams/Open', + optionalBody: true, + ) + Future> _liveStreamsOpenPost({ + @Query('openToken') String? openToken, + @Query('userId') String? userId, + @Query('playSessionId') String? playSessionId, + @Query('maxStreamingBitrate') int? maxStreamingBitrate, + @Query('startTimeTicks') int? startTimeTicks, + @Query('audioStreamIndex') int? audioStreamIndex, + @Query('subtitleStreamIndex') int? subtitleStreamIndex, + @Query('maxAudioChannels') int? maxAudioChannels, + @Query('itemId') String? itemId, + @Query('enableDirectPlay') bool? enableDirectPlay, + @Query('enableDirectStream') bool? enableDirectStream, + @Body() required OpenLiveStreamDto? body, + }); + + ///Tests the network with a request with the size of the bitrate. + ///@param size The bitrate. Defaults to 102400. + Future> playbackBitrateTestGet({int? size}) { + return _playbackBitrateTestGet(size: size); + } + + ///Tests the network with a request with the size of the bitrate. + ///@param size The bitrate. Defaults to 102400. + @Get(path: '/Playback/BitrateTest') + Future> _playbackBitrateTestGet( + {@Query('size') int? size}); + + ///Gets movie recommendations. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param parentId Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param fields Optional. The fields to return. + ///@param categoryLimit The max number of categories to return. + ///@param itemLimit The max number of items to return per category. + Future>> moviesRecommendationsGet({ + String? userId, + String? parentId, + List? fields, + int? categoryLimit, + int? itemLimit, + }) { + generatedMapping.putIfAbsent( + RecommendationDto, () => RecommendationDto.fromJsonFactory); + + return _moviesRecommendationsGet( + userId: userId, + parentId: parentId, + fields: itemFieldsListToJson(fields), + categoryLimit: categoryLimit, + itemLimit: itemLimit); + } + + ///Gets movie recommendations. + ///@param userId Optional. Filter by user id, and attach user data. + ///@param parentId Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param fields Optional. The fields to return. + ///@param categoryLimit The max number of categories to return. + ///@param itemLimit The max number of items to return per category. + @Get(path: '/Movies/Recommendations') + Future>> _moviesRecommendationsGet({ + @Query('userId') String? userId, + @Query('parentId') String? parentId, + @Query('fields') List? fields, + @Query('categoryLimit') int? categoryLimit, + @Query('itemLimit') int? itemLimit, + }); + + ///Gets all music genres from a given item, folder, or the entire library. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param searchTerm The search term. + ///@param parentId Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param excludeItemTypes Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited. + ///@param includeItemTypes Optional. If specified, results will be filtered in based on item type. This allows multiple, comma delimited. + ///@param isFavorite Optional filter by items that are marked as favorite, or not. + ///@param imageTypeLimit Optional, the max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param userId User id. + ///@param nameStartsWithOrGreater Optional filter by items whose name is sorted equally or greater than a given input string. + ///@param nameStartsWith Optional filter by items whose name is sorted equally than a given input string. + ///@param nameLessThan Optional filter by items whose name is equally or lesser than a given input string. + ///@param sortBy Optional. Specify one or more sort orders, comma delimited. + ///@param sortOrder Sort Order - Ascending,Descending. + ///@param enableImages Optional, include image information in output. + ///@param enableTotalRecordCount Optional. Include total record count. + @deprecated + Future> musicGenresGet({ + int? startIndex, + int? limit, + String? searchTerm, + String? parentId, + List? fields, + List? excludeItemTypes, + List? includeItemTypes, + bool? isFavorite, + int? imageTypeLimit, + List? enableImageTypes, + String? userId, + String? nameStartsWithOrGreater, + String? nameStartsWith, + String? nameLessThan, + List? sortBy, + List? sortOrder, + bool? enableImages, + bool? enableTotalRecordCount, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _musicGenresGet( + startIndex: startIndex, + limit: limit, + searchTerm: searchTerm, + parentId: parentId, + fields: itemFieldsListToJson(fields), + excludeItemTypes: baseItemKindListToJson(excludeItemTypes), + includeItemTypes: baseItemKindListToJson(includeItemTypes), + isFavorite: isFavorite, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes), + userId: userId, + nameStartsWithOrGreater: nameStartsWithOrGreater, + nameStartsWith: nameStartsWith, + nameLessThan: nameLessThan, + sortBy: itemSortByListToJson(sortBy), + sortOrder: sortOrderListToJson(sortOrder), + enableImages: enableImages, + enableTotalRecordCount: enableTotalRecordCount); + } + + ///Gets all music genres from a given item, folder, or the entire library. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param searchTerm The search term. + ///@param parentId Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param excludeItemTypes Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited. + ///@param includeItemTypes Optional. If specified, results will be filtered in based on item type. This allows multiple, comma delimited. + ///@param isFavorite Optional filter by items that are marked as favorite, or not. + ///@param imageTypeLimit Optional, the max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param userId User id. + ///@param nameStartsWithOrGreater Optional filter by items whose name is sorted equally or greater than a given input string. + ///@param nameStartsWith Optional filter by items whose name is sorted equally than a given input string. + ///@param nameLessThan Optional filter by items whose name is equally or lesser than a given input string. + ///@param sortBy Optional. Specify one or more sort orders, comma delimited. + ///@param sortOrder Sort Order - Ascending,Descending. + ///@param enableImages Optional, include image information in output. + ///@param enableTotalRecordCount Optional. Include total record count. + @deprecated + @Get(path: '/MusicGenres') + Future> _musicGenresGet({ + @Query('startIndex') int? startIndex, + @Query('limit') int? limit, + @Query('searchTerm') String? searchTerm, + @Query('parentId') String? parentId, + @Query('fields') List? fields, + @Query('excludeItemTypes') List? excludeItemTypes, + @Query('includeItemTypes') List? includeItemTypes, + @Query('isFavorite') bool? isFavorite, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + @Query('userId') String? userId, + @Query('nameStartsWithOrGreater') String? nameStartsWithOrGreater, + @Query('nameStartsWith') String? nameStartsWith, + @Query('nameLessThan') String? nameLessThan, + @Query('sortBy') List? sortBy, + @Query('sortOrder') List? sortOrder, + @Query('enableImages') bool? enableImages, + @Query('enableTotalRecordCount') bool? enableTotalRecordCount, + }); + + ///Gets a music genre, by name. + ///@param genreName The genre name. + ///@param userId Optional. Filter by user id, and attach user data. + Future> musicGenresGenreNameGet({ + required String? genreName, + String? userId, + }) { + generatedMapping.putIfAbsent( + BaseItemDto, () => BaseItemDto.fromJsonFactory); + + return _musicGenresGenreNameGet(genreName: genreName, userId: userId); + } + + ///Gets a music genre, by name. + ///@param genreName The genre name. + ///@param userId Optional. Filter by user id, and attach user data. + @Get(path: '/MusicGenres/{genreName}') + Future> _musicGenresGenreNameGet({ + @Path('genreName') required String? genreName, + @Query('userId') String? userId, + }); + + ///Gets available packages. + Future>> packagesGet() { + generatedMapping.putIfAbsent( + PackageInfo, () => PackageInfo.fromJsonFactory); + + return _packagesGet(); + } + + ///Gets available packages. + @Get(path: '/Packages') + Future>> _packagesGet(); + + ///Gets a package by name or assembly GUID. + ///@param name The name of the package. + ///@param assemblyGuid The GUID of the associated assembly. + Future> packagesNameGet({ + required String? name, + String? assemblyGuid, + }) { + generatedMapping.putIfAbsent( + PackageInfo, () => PackageInfo.fromJsonFactory); + + return _packagesNameGet(name: name, assemblyGuid: assemblyGuid); + } + + ///Gets a package by name or assembly GUID. + ///@param name The name of the package. + ///@param assemblyGuid The GUID of the associated assembly. + @Get(path: '/Packages/{name}') + Future> _packagesNameGet({ + @Path('name') required String? name, + @Query('assemblyGuid') String? assemblyGuid, + }); + + ///Installs a package. + ///@param name Package name. + ///@param assemblyGuid GUID of the associated assembly. + ///@param version Optional version. Defaults to latest version. + ///@param repositoryUrl Optional. Specify the repository to install from. + Future packagesInstalledNamePost({ + required String? name, + String? assemblyGuid, + String? version, + String? repositoryUrl, + }) { + return _packagesInstalledNamePost( + name: name, + assemblyGuid: assemblyGuid, + version: version, + repositoryUrl: repositoryUrl); + } + + ///Installs a package. + ///@param name Package name. + ///@param assemblyGuid GUID of the associated assembly. + ///@param version Optional version. Defaults to latest version. + ///@param repositoryUrl Optional. Specify the repository to install from. + @Post( + path: '/Packages/Installed/{name}', + optionalBody: true, + ) + Future _packagesInstalledNamePost({ + @Path('name') required String? name, + @Query('assemblyGuid') String? assemblyGuid, + @Query('version') String? version, + @Query('repositoryUrl') String? repositoryUrl, + }); + + ///Cancels a package installation. + ///@param packageId Installation Id. + Future packagesInstallingPackageIdDelete( + {required String? packageId}) { + return _packagesInstallingPackageIdDelete(packageId: packageId); + } + + ///Cancels a package installation. + ///@param packageId Installation Id. + @Delete(path: '/Packages/Installing/{packageId}') + Future _packagesInstallingPackageIdDelete( + {@Path('packageId') required String? packageId}); + + ///Gets all package repositories. + Future>> repositoriesGet() { + generatedMapping.putIfAbsent( + RepositoryInfo, () => RepositoryInfo.fromJsonFactory); + + return _repositoriesGet(); + } + + ///Gets all package repositories. + @Get(path: '/Repositories') + Future>> _repositoriesGet(); + + ///Sets the enabled and existing package repositories. + Future repositoriesPost( + {required List? body}) { + return _repositoriesPost(body: body); + } + + ///Sets the enabled and existing package repositories. + @Post( + path: '/Repositories', + optionalBody: true, + ) + Future _repositoriesPost( + {@Body() required List? body}); + + ///Gets all persons. + ///@param limit Optional. The maximum number of records to return. + ///@param searchTerm The search term. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param filters Optional. Specify additional filters to apply. + ///@param isFavorite Optional filter by items that are marked as favorite, or not. userId is required. + ///@param enableUserData Optional, include user data. + ///@param imageTypeLimit Optional, the max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param excludePersonTypes Optional. If specified results will be filtered to exclude those containing the specified PersonType. Allows multiple, comma-delimited. + ///@param personTypes Optional. If specified results will be filtered to include only those containing the specified PersonType. Allows multiple, comma-delimited. + ///@param appearsInItemId Optional. If specified, person results will be filtered on items related to said persons. + ///@param userId User id. + ///@param enableImages Optional, include image information in output. + Future> personsGet({ + int? limit, + String? searchTerm, + List? fields, + List? filters, + bool? isFavorite, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + List? excludePersonTypes, + List? personTypes, + String? appearsInItemId, + String? userId, + bool? enableImages, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _personsGet( + limit: limit, + searchTerm: searchTerm, + fields: itemFieldsListToJson(fields), + filters: itemFilterListToJson(filters), + isFavorite: isFavorite, + enableUserData: enableUserData, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes), + excludePersonTypes: excludePersonTypes, + personTypes: personTypes, + appearsInItemId: appearsInItemId, + userId: userId, + enableImages: enableImages); + } + + ///Gets all persons. + ///@param limit Optional. The maximum number of records to return. + ///@param searchTerm The search term. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param filters Optional. Specify additional filters to apply. + ///@param isFavorite Optional filter by items that are marked as favorite, or not. userId is required. + ///@param enableUserData Optional, include user data. + ///@param imageTypeLimit Optional, the max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param excludePersonTypes Optional. If specified results will be filtered to exclude those containing the specified PersonType. Allows multiple, comma-delimited. + ///@param personTypes Optional. If specified results will be filtered to include only those containing the specified PersonType. Allows multiple, comma-delimited. + ///@param appearsInItemId Optional. If specified, person results will be filtered on items related to said persons. + ///@param userId User id. + ///@param enableImages Optional, include image information in output. + @Get(path: '/Persons') + Future> _personsGet({ + @Query('limit') int? limit, + @Query('searchTerm') String? searchTerm, + @Query('fields') List? fields, + @Query('filters') List? filters, + @Query('isFavorite') bool? isFavorite, + @Query('enableUserData') bool? enableUserData, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + @Query('excludePersonTypes') List? excludePersonTypes, + @Query('personTypes') List? personTypes, + @Query('appearsInItemId') String? appearsInItemId, + @Query('userId') String? userId, + @Query('enableImages') bool? enableImages, + }); + + ///Get person by name. + ///@param name Person name. + ///@param userId Optional. Filter by user id, and attach user data. + Future> personsNameGet({ + required String? name, + String? userId, + }) { + generatedMapping.putIfAbsent( + BaseItemDto, () => BaseItemDto.fromJsonFactory); + + return _personsNameGet(name: name, userId: userId); + } + + ///Get person by name. + ///@param name Person name. + ///@param userId Optional. Filter by user id, and attach user data. + @Get(path: '/Persons/{name}') + Future> _personsNameGet({ + @Path('name') required String? name, + @Query('userId') String? userId, + }); + + /// + ///@param breakdownType + ///@param days + ///@param endDate + ///@param timezoneOffset + Future userUsageStatsBreakdownTypeBreakdownReportGet({ + required String? breakdownType, + int? days, + DateTime? endDate, + num? timezoneOffset, + }) { + return _userUsageStatsBreakdownTypeBreakdownReportGet( + breakdownType: breakdownType, + days: days, + endDate: endDate, + timezoneOffset: timezoneOffset); + } + + /// + ///@param breakdownType + ///@param days + ///@param endDate + ///@param timezoneOffset + @Get(path: '/user_usage_stats/{breakdownType}/BreakdownReport') + Future _userUsageStatsBreakdownTypeBreakdownReportGet({ + @Path('breakdownType') required String? breakdownType, + @Query('days') int? days, + @Query('endDate') DateTime? endDate, + @Query('timezoneOffset') num? timezoneOffset, + }); + + /// + ///@param userId + ///@param date + ///@param filter + ///@param timezoneOffset + Future userUsageStatsUserIdDateGetItemsGet({ + required String? userId, + required String? date, + String? filter, + num? timezoneOffset, + }) { + return _userUsageStatsUserIdDateGetItemsGet( + userId: userId, + date: date, + filter: filter, + timezoneOffset: timezoneOffset); + } + + /// + ///@param userId + ///@param date + ///@param filter + ///@param timezoneOffset + @Get(path: '/user_usage_stats/{userId}/{date}/GetItems') + Future _userUsageStatsUserIdDateGetItemsGet({ + @Path('userId') required String? userId, + @Path('date') required String? date, + @Query('filter') String? filter, + @Query('timezoneOffset') num? timezoneOffset, + }); + + /// + ///@param days + ///@param endDate + ///@param filter + Future userUsageStatsDurationHistogramReportGet({ + int? days, + DateTime? endDate, + String? filter, + }) { + return _userUsageStatsDurationHistogramReportGet( + days: days, endDate: endDate, filter: filter); + } + + /// + ///@param days + ///@param endDate + ///@param filter + @Get(path: '/user_usage_stats/DurationHistogramReport') + Future _userUsageStatsDurationHistogramReportGet({ + @Query('days') int? days, + @Query('endDate') DateTime? endDate, + @Query('filter') String? filter, + }); + + /// + ///@param days + ///@param endDate + ///@param timezoneOffset + Future userUsageStatsGetTvShowsReportGet({ + int? days, + DateTime? endDate, + num? timezoneOffset, + }) { + return _userUsageStatsGetTvShowsReportGet( + days: days, endDate: endDate, timezoneOffset: timezoneOffset); + } + + /// + ///@param days + ///@param endDate + ///@param timezoneOffset + @Get(path: '/user_usage_stats/GetTvShowsReport') + Future _userUsageStatsGetTvShowsReportGet({ + @Query('days') int? days, + @Query('endDate') DateTime? endDate, + @Query('timezoneOffset') num? timezoneOffset, + }); + + /// + ///@param days + ///@param endDate + ///@param filter + ///@param timezoneOffset + Future userUsageStatsHourlyReportGet({ + int? days, + DateTime? endDate, + String? filter, + num? timezoneOffset, + }) { + return _userUsageStatsHourlyReportGet( + days: days, + endDate: endDate, + filter: filter, + timezoneOffset: timezoneOffset); + } + + /// + ///@param days + ///@param endDate + ///@param filter + ///@param timezoneOffset + @Get(path: '/user_usage_stats/HourlyReport') + Future _userUsageStatsHourlyReportGet({ + @Query('days') int? days, + @Query('endDate') DateTime? endDate, + @Query('filter') String? filter, + @Query('timezoneOffset') num? timezoneOffset, + }); + + /// + ///@param backupFilePath + Future>> userUsageStatsLoadBackupGet( + {String? backupFilePath}) { + return _userUsageStatsLoadBackupGet(backupFilePath: backupFilePath); + } + + /// + ///@param backupFilePath + @Get(path: '/user_usage_stats/load_backup') + Future>> _userUsageStatsLoadBackupGet( + {@Query('backupFilePath') String? backupFilePath}); + + /// + ///@param days + ///@param endDate + ///@param timezoneOffset + Future userUsageStatsMoviesReportGet({ + int? days, + DateTime? endDate, + num? timezoneOffset, + }) { + return _userUsageStatsMoviesReportGet( + days: days, endDate: endDate, timezoneOffset: timezoneOffset); + } + + /// + ///@param days + ///@param endDate + ///@param timezoneOffset + @Get(path: '/user_usage_stats/MoviesReport') + Future _userUsageStatsMoviesReportGet({ + @Query('days') int? days, + @Query('endDate') DateTime? endDate, + @Query('timezoneOffset') num? timezoneOffset, + }); + + /// + ///@param days + ///@param endDate + ///@param filter + ///@param dataType + ///@param timezoneOffset + Future userUsageStatsPlayActivityGet({ + int? days, + DateTime? endDate, + String? filter, + String? dataType, + num? timezoneOffset, + }) { + return _userUsageStatsPlayActivityGet( + days: days, + endDate: endDate, + filter: filter, + dataType: dataType, + timezoneOffset: timezoneOffset); + } + + /// + ///@param days + ///@param endDate + ///@param filter + ///@param dataType + ///@param timezoneOffset + @Get(path: '/user_usage_stats/PlayActivity') + Future _userUsageStatsPlayActivityGet({ + @Query('days') int? days, + @Query('endDate') DateTime? endDate, + @Query('filter') String? filter, + @Query('dataType') String? dataType, + @Query('timezoneOffset') num? timezoneOffset, + }); + + /// + Future>> userUsageStatsSaveBackupGet() { + return _userUsageStatsSaveBackupGet(); + } + + /// + @Get(path: '/user_usage_stats/save_backup') + Future>> _userUsageStatsSaveBackupGet(); + + /// + Future> userUsageStatsSubmitCustomQueryPost( + {required CustomQueryData? body}) { + return _userUsageStatsSubmitCustomQueryPost(body: body); + } + + /// + @Post( + path: '/user_usage_stats/submit_custom_query', + optionalBody: true, + ) + Future> _userUsageStatsSubmitCustomQueryPost( + {@Body() required CustomQueryData? body}); + + /// + Future userUsageStatsTypeFilterListGet() { + return _userUsageStatsTypeFilterListGet(); + } + + /// + @Get(path: '/user_usage_stats/type_filter_list') + Future _userUsageStatsTypeFilterListGet(); + + /// + ///@param days + ///@param endDate + ///@param timezoneOffset + Future userUsageStatsUserActivityGet({ + int? days, + DateTime? endDate, + num? timezoneOffset, + }) { + return _userUsageStatsUserActivityGet( + days: days, endDate: endDate, timezoneOffset: timezoneOffset); + } + + /// + ///@param days + ///@param endDate + ///@param timezoneOffset + @Get(path: '/user_usage_stats/user_activity') + Future _userUsageStatsUserActivityGet({ + @Query('days') int? days, + @Query('endDate') DateTime? endDate, + @Query('timezoneOffset') num? timezoneOffset, + }); + + /// + Future userUsageStatsUserListGet() { + return _userUsageStatsUserListGet(); + } + + /// + @Get(path: '/user_usage_stats/user_list') + Future _userUsageStatsUserListGet(); + + /// + ///@param id + Future> userUsageStatsUserManageAddGet({String? id}) { + return _userUsageStatsUserManageAddGet(id: id); + } + + /// + ///@param id + @Get(path: '/user_usage_stats/user_manage/add') + Future> _userUsageStatsUserManageAddGet( + {@Query('id') String? id}); + + /// + Future> userUsageStatsUserManagePruneGet() { + return _userUsageStatsUserManagePruneGet(); + } + + /// + @Get(path: '/user_usage_stats/user_manage/prune') + Future> _userUsageStatsUserManagePruneGet(); + + /// + ///@param id + Future> userUsageStatsUserManageRemoveGet( + {String? id}) { + return _userUsageStatsUserManageRemoveGet(id: id); + } + + /// + ///@param id + @Get(path: '/user_usage_stats/user_manage/remove') + Future> _userUsageStatsUserManageRemoveGet( + {@Query('id') String? id}); + + ///Creates a new playlist. + ///@param name The playlist name. + ///@param ids The item ids. + ///@param userId The user id. + ///@param mediaType The media type. + Future> playlistsPost({ + String? name, + List? ids, + String? userId, + enums.PlaylistsPostMediaType? mediaType, + required CreatePlaylistDto? body, + }) { + generatedMapping.putIfAbsent( + PlaylistCreationResult, () => PlaylistCreationResult.fromJsonFactory); + + return _playlistsPost( + name: name, + ids: ids, + userId: userId, + mediaType: mediaType?.value?.toString(), + body: body); + } + + ///Creates a new playlist. + ///@param name The playlist name. + ///@param ids The item ids. + ///@param userId The user id. + ///@param mediaType The media type. + @Post( + path: '/Playlists', + optionalBody: true, + ) + Future> _playlistsPost({ + @Query('name') String? name, + @Query('ids') List? ids, + @Query('userId') String? userId, + @Query('mediaType') String? mediaType, + @Body() required CreatePlaylistDto? body, + }); + + ///Updates a playlist. + ///@param playlistId The playlist id. + Future playlistsPlaylistIdPost({ + required String? playlistId, + required UpdatePlaylistDto? body, + }) { + return _playlistsPlaylistIdPost(playlistId: playlistId, body: body); + } + + ///Updates a playlist. + ///@param playlistId The playlist id. + @Post( + path: '/Playlists/{playlistId}', + optionalBody: true, + ) + Future _playlistsPlaylistIdPost({ + @Path('playlistId') required String? playlistId, + @Body() required UpdatePlaylistDto? body, + }); + + ///Adds items to a playlist. + ///@param playlistId The playlist id. + ///@param ids Item id, comma delimited. + ///@param userId The userId. + Future playlistsPlaylistIdItemsPost({ + required String? playlistId, + List? ids, + String? userId, + }) { + return _playlistsPlaylistIdItemsPost( + playlistId: playlistId, ids: ids, userId: userId); + } + + ///Adds items to a playlist. + ///@param playlistId The playlist id. + ///@param ids Item id, comma delimited. + ///@param userId The userId. + @Post( + path: '/Playlists/{playlistId}/Items', + optionalBody: true, + ) + Future _playlistsPlaylistIdItemsPost({ + @Path('playlistId') required String? playlistId, + @Query('ids') List? ids, + @Query('userId') String? userId, + }); + + ///Removes items from a playlist. + ///@param playlistId The playlist id. + ///@param entryIds The item ids, comma delimited. + Future playlistsPlaylistIdItemsDelete({ + required String? playlistId, + List? entryIds, + }) { + return _playlistsPlaylistIdItemsDelete( + playlistId: playlistId, entryIds: entryIds); + } + + ///Removes items from a playlist. + ///@param playlistId The playlist id. + ///@param entryIds The item ids, comma delimited. + @Delete(path: '/Playlists/{playlistId}/Items') + Future _playlistsPlaylistIdItemsDelete({ + @Path('playlistId') required String? playlistId, + @Query('entryIds') List? entryIds, + }); + + ///Gets the original items of a playlist. + ///@param playlistId The playlist id. + ///@param userId User id. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableImages Optional. Include image information in output. + ///@param enableUserData Optional. Include user data. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + Future> playlistsPlaylistIdItemsGet({ + required String? playlistId, + String? userId, + int? startIndex, + int? limit, + List? fields, + bool? enableImages, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _playlistsPlaylistIdItemsGet( + playlistId: playlistId, + userId: userId, + startIndex: startIndex, + limit: limit, + fields: itemFieldsListToJson(fields), + enableImages: enableImages, + enableUserData: enableUserData, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes)); + } + + ///Gets the original items of a playlist. + ///@param playlistId The playlist id. + ///@param userId User id. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param enableImages Optional. Include image information in output. + ///@param enableUserData Optional. Include user data. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + @Get(path: '/Playlists/{playlistId}/Items') + Future> + _playlistsPlaylistIdItemsGet({ + @Path('playlistId') required String? playlistId, + @Query('userId') String? userId, + @Query('startIndex') int? startIndex, + @Query('limit') int? limit, + @Query('fields') List? fields, + @Query('enableImages') bool? enableImages, + @Query('enableUserData') bool? enableUserData, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + }); + + ///Moves a playlist item. + ///@param playlistId The playlist id. + ///@param itemId The item id. + ///@param newIndex The new index. + Future playlistsPlaylistIdItemsItemIdMoveNewIndexPost({ + required String? playlistId, + required String? itemId, + required int? newIndex, + }) { + return _playlistsPlaylistIdItemsItemIdMoveNewIndexPost( + playlistId: playlistId, itemId: itemId, newIndex: newIndex); + } + + ///Moves a playlist item. + ///@param playlistId The playlist id. + ///@param itemId The item id. + ///@param newIndex The new index. + @Post( + path: '/Playlists/{playlistId}/Items/{itemId}/Move/{newIndex}', + optionalBody: true, + ) + Future _playlistsPlaylistIdItemsItemIdMoveNewIndexPost({ + @Path('playlistId') required String? playlistId, + @Path('itemId') required String? itemId, + @Path('newIndex') required int? newIndex, + }); + + ///Get a playlist's users. + ///@param playlistId The playlist id. + Future>> + playlistsPlaylistIdUsersGet({required String? playlistId}) { + generatedMapping.putIfAbsent( + PlaylistUserPermissions, () => PlaylistUserPermissions.fromJsonFactory); + + return _playlistsPlaylistIdUsersGet(playlistId: playlistId); + } + + ///Get a playlist's users. + ///@param playlistId The playlist id. + @Get(path: '/Playlists/{playlistId}/Users') + Future>> + _playlistsPlaylistIdUsersGet( + {@Path('playlistId') required String? playlistId}); + + ///Get a playlist user. + ///@param playlistId The playlist id. + ///@param userId The user id. + Future> + playlistsPlaylistIdUsersUserIdGet({ + required String? playlistId, + required String? userId, + }) { + generatedMapping.putIfAbsent( + PlaylistUserPermissions, () => PlaylistUserPermissions.fromJsonFactory); + + return _playlistsPlaylistIdUsersUserIdGet( + playlistId: playlistId, userId: userId); + } + + ///Get a playlist user. + ///@param playlistId The playlist id. + ///@param userId The user id. + @Get(path: '/Playlists/{playlistId}/Users/{userId}') + Future> + _playlistsPlaylistIdUsersUserIdGet({ + @Path('playlistId') required String? playlistId, + @Path('userId') required String? userId, + }); + + ///Modify a user of a playlist's users. + ///@param playlistId The playlist id. + ///@param userId The user id. + Future playlistsPlaylistIdUsersUserIdPost({ + required String? playlistId, + required String? userId, + required UpdatePlaylistUserDto? body, + }) { + return _playlistsPlaylistIdUsersUserIdPost( + playlistId: playlistId, userId: userId, body: body); + } + + ///Modify a user of a playlist's users. + ///@param playlistId The playlist id. + ///@param userId The user id. + @Post( + path: '/Playlists/{playlistId}/Users/{userId}', + optionalBody: true, + ) + Future _playlistsPlaylistIdUsersUserIdPost({ + @Path('playlistId') required String? playlistId, + @Path('userId') required String? userId, + @Body() required UpdatePlaylistUserDto? body, + }); + + ///Remove a user from a playlist's users. + ///@param playlistId The playlist id. + ///@param userId The user id. + Future playlistsPlaylistIdUsersUserIdDelete({ + required String? playlistId, + required String? userId, + }) { + return _playlistsPlaylistIdUsersUserIdDelete( + playlistId: playlistId, userId: userId); + } + + ///Remove a user from a playlist's users. + ///@param playlistId The playlist id. + ///@param userId The user id. + @Delete(path: '/Playlists/{playlistId}/Users/{userId}') + Future _playlistsPlaylistIdUsersUserIdDelete({ + @Path('playlistId') required String? playlistId, + @Path('userId') required String? userId, + }); + + ///Reports that a session has begun playing an item. + ///@param itemId Item id. + ///@param mediaSourceId The id of the MediaSource. + ///@param audioStreamIndex The audio stream index. + ///@param subtitleStreamIndex The subtitle stream index. + ///@param playMethod The play method. + ///@param liveStreamId The live stream id. + ///@param playSessionId The play session id. + ///@param canSeek Indicates if the client can seek. + Future playingItemsItemIdPost({ + required String? itemId, + String? mediaSourceId, + int? audioStreamIndex, + int? subtitleStreamIndex, + enums.PlayingItemsItemIdPostPlayMethod? playMethod, + String? liveStreamId, + String? playSessionId, + bool? canSeek, + }) { + return _playingItemsItemIdPost( + itemId: itemId, + mediaSourceId: mediaSourceId, + audioStreamIndex: audioStreamIndex, + subtitleStreamIndex: subtitleStreamIndex, + playMethod: playMethod?.value?.toString(), + liveStreamId: liveStreamId, + playSessionId: playSessionId, + canSeek: canSeek); + } + + ///Reports that a session has begun playing an item. + ///@param itemId Item id. + ///@param mediaSourceId The id of the MediaSource. + ///@param audioStreamIndex The audio stream index. + ///@param subtitleStreamIndex The subtitle stream index. + ///@param playMethod The play method. + ///@param liveStreamId The live stream id. + ///@param playSessionId The play session id. + ///@param canSeek Indicates if the client can seek. + @Post( + path: '/PlayingItems/{itemId}', + optionalBody: true, + ) + Future _playingItemsItemIdPost({ + @Path('itemId') required String? itemId, + @Query('mediaSourceId') String? mediaSourceId, + @Query('audioStreamIndex') int? audioStreamIndex, + @Query('subtitleStreamIndex') int? subtitleStreamIndex, + @Query('playMethod') String? playMethod, + @Query('liveStreamId') String? liveStreamId, + @Query('playSessionId') String? playSessionId, + @Query('canSeek') bool? canSeek, + }); + + ///Reports that a session has stopped playing an item. + ///@param itemId Item id. + ///@param mediaSourceId The id of the MediaSource. + ///@param nextMediaType The next media type that will play. + ///@param positionTicks Optional. The position, in ticks, where playback stopped. 1 tick = 10000 ms. + ///@param liveStreamId The live stream id. + ///@param playSessionId The play session id. + Future playingItemsItemIdDelete({ + required String? itemId, + String? mediaSourceId, + String? nextMediaType, + int? positionTicks, + String? liveStreamId, + String? playSessionId, + }) { + return _playingItemsItemIdDelete( + itemId: itemId, + mediaSourceId: mediaSourceId, + nextMediaType: nextMediaType, + positionTicks: positionTicks, + liveStreamId: liveStreamId, + playSessionId: playSessionId); + } + + ///Reports that a session has stopped playing an item. + ///@param itemId Item id. + ///@param mediaSourceId The id of the MediaSource. + ///@param nextMediaType The next media type that will play. + ///@param positionTicks Optional. The position, in ticks, where playback stopped. 1 tick = 10000 ms. + ///@param liveStreamId The live stream id. + ///@param playSessionId The play session id. + @Delete(path: '/PlayingItems/{itemId}') + Future _playingItemsItemIdDelete({ + @Path('itemId') required String? itemId, + @Query('mediaSourceId') String? mediaSourceId, + @Query('nextMediaType') String? nextMediaType, + @Query('positionTicks') int? positionTicks, + @Query('liveStreamId') String? liveStreamId, + @Query('playSessionId') String? playSessionId, + }); + + ///Reports a session's playback progress. + ///@param itemId Item id. + ///@param mediaSourceId The id of the MediaSource. + ///@param positionTicks Optional. The current position, in ticks. 1 tick = 10000 ms. + ///@param audioStreamIndex The audio stream index. + ///@param subtitleStreamIndex The subtitle stream index. + ///@param volumeLevel Scale of 0-100. + ///@param playMethod The play method. + ///@param liveStreamId The live stream id. + ///@param playSessionId The play session id. + ///@param repeatMode The repeat mode. + ///@param isPaused Indicates if the player is paused. + ///@param isMuted Indicates if the player is muted. + Future playingItemsItemIdProgressPost({ + required String? itemId, + String? mediaSourceId, + int? positionTicks, + int? audioStreamIndex, + int? subtitleStreamIndex, + int? volumeLevel, + enums.PlayingItemsItemIdProgressPostPlayMethod? playMethod, + String? liveStreamId, + String? playSessionId, + enums.PlayingItemsItemIdProgressPostRepeatMode? repeatMode, + bool? isPaused, + bool? isMuted, + }) { + return _playingItemsItemIdProgressPost( + itemId: itemId, + mediaSourceId: mediaSourceId, + positionTicks: positionTicks, + audioStreamIndex: audioStreamIndex, + subtitleStreamIndex: subtitleStreamIndex, + volumeLevel: volumeLevel, + playMethod: playMethod?.value?.toString(), + liveStreamId: liveStreamId, + playSessionId: playSessionId, + repeatMode: repeatMode?.value?.toString(), + isPaused: isPaused, + isMuted: isMuted); + } + + ///Reports a session's playback progress. + ///@param itemId Item id. + ///@param mediaSourceId The id of the MediaSource. + ///@param positionTicks Optional. The current position, in ticks. 1 tick = 10000 ms. + ///@param audioStreamIndex The audio stream index. + ///@param subtitleStreamIndex The subtitle stream index. + ///@param volumeLevel Scale of 0-100. + ///@param playMethod The play method. + ///@param liveStreamId The live stream id. + ///@param playSessionId The play session id. + ///@param repeatMode The repeat mode. + ///@param isPaused Indicates if the player is paused. + ///@param isMuted Indicates if the player is muted. + @Post( + path: '/PlayingItems/{itemId}/Progress', + optionalBody: true, + ) + Future _playingItemsItemIdProgressPost({ + @Path('itemId') required String? itemId, + @Query('mediaSourceId') String? mediaSourceId, + @Query('positionTicks') int? positionTicks, + @Query('audioStreamIndex') int? audioStreamIndex, + @Query('subtitleStreamIndex') int? subtitleStreamIndex, + @Query('volumeLevel') int? volumeLevel, + @Query('playMethod') String? playMethod, + @Query('liveStreamId') String? liveStreamId, + @Query('playSessionId') String? playSessionId, + @Query('repeatMode') String? repeatMode, + @Query('isPaused') bool? isPaused, + @Query('isMuted') bool? isMuted, + }); + + ///Reports playback has started within a session. + Future sessionsPlayingPost( + {required PlaybackStartInfo? body}) { + return _sessionsPlayingPost(body: body); + } + + ///Reports playback has started within a session. + @Post( + path: '/Sessions/Playing', + optionalBody: true, + ) + Future _sessionsPlayingPost( + {@Body() required PlaybackStartInfo? body}); + + ///Pings a playback session. + ///@param playSessionId Playback session id. + Future sessionsPlayingPingPost( + {required String? playSessionId}) { + return _sessionsPlayingPingPost(playSessionId: playSessionId); + } + + ///Pings a playback session. + ///@param playSessionId Playback session id. + @Post( + path: '/Sessions/Playing/Ping', + optionalBody: true, + ) + Future _sessionsPlayingPingPost( + {@Query('playSessionId') required String? playSessionId}); + + ///Reports playback progress within a session. + Future sessionsPlayingProgressPost( + {required PlaybackProgressInfo? body}) { + return _sessionsPlayingProgressPost(body: body); + } + + ///Reports playback progress within a session. + @Post( + path: '/Sessions/Playing/Progress', + optionalBody: true, + ) + Future _sessionsPlayingProgressPost( + {@Body() required PlaybackProgressInfo? body}); + + ///Reports playback has stopped within a session. + Future sessionsPlayingStoppedPost( + {required PlaybackStopInfo? body}) { + return _sessionsPlayingStoppedPost(body: body); + } + + ///Reports playback has stopped within a session. + @Post( + path: '/Sessions/Playing/Stopped', + optionalBody: true, + ) + Future _sessionsPlayingStoppedPost( + {@Body() required PlaybackStopInfo? body}); + + ///Marks an item as played for user. + ///@param userId User id. + ///@param itemId Item id. + ///@param datePlayed Optional. The date the item was played. + Future> userPlayedItemsItemIdPost({ + String? userId, + required String? itemId, + DateTime? datePlayed, + }) { + generatedMapping.putIfAbsent( + UserItemDataDto, () => UserItemDataDto.fromJsonFactory); + + return _userPlayedItemsItemIdPost( + userId: userId, itemId: itemId, datePlayed: datePlayed); + } + + ///Marks an item as played for user. + ///@param userId User id. + ///@param itemId Item id. + ///@param datePlayed Optional. The date the item was played. + @Post( + path: '/UserPlayedItems/{itemId}', + optionalBody: true, + ) + Future> _userPlayedItemsItemIdPost({ + @Query('userId') String? userId, + @Path('itemId') required String? itemId, + @Query('datePlayed') DateTime? datePlayed, + }); + + ///Marks an item as unplayed for user. + ///@param userId User id. + ///@param itemId Item id. + Future> userPlayedItemsItemIdDelete({ + String? userId, + required String? itemId, + }) { + generatedMapping.putIfAbsent( + UserItemDataDto, () => UserItemDataDto.fromJsonFactory); + + return _userPlayedItemsItemIdDelete(userId: userId, itemId: itemId); + } + + ///Marks an item as unplayed for user. + ///@param userId User id. + ///@param itemId Item id. + @Delete(path: '/UserPlayedItems/{itemId}') + Future> _userPlayedItemsItemIdDelete({ + @Query('userId') String? userId, + @Path('itemId') required String? itemId, + }); + + ///Gets a list of currently installed plugins. + Future>> pluginsGet() { + generatedMapping.putIfAbsent(PluginInfo, () => PluginInfo.fromJsonFactory); + + return _pluginsGet(); + } + + ///Gets a list of currently installed plugins. + @Get(path: '/Plugins') + Future>> _pluginsGet(); + + ///Uninstalls a plugin. + ///@param pluginId Plugin id. + @deprecated + Future pluginsPluginIdDelete({required String? pluginId}) { + return _pluginsPluginIdDelete(pluginId: pluginId); + } + + ///Uninstalls a plugin. + ///@param pluginId Plugin id. + @deprecated + @Delete(path: '/Plugins/{pluginId}') + Future _pluginsPluginIdDelete( + {@Path('pluginId') required String? pluginId}); + + ///Uninstalls a plugin by version. + ///@param pluginId Plugin id. + ///@param version Plugin version. + Future pluginsPluginIdVersionDelete({ + required String? pluginId, + required String? version, + }) { + return _pluginsPluginIdVersionDelete(pluginId: pluginId, version: version); + } + + ///Uninstalls a plugin by version. + ///@param pluginId Plugin id. + ///@param version Plugin version. + @Delete(path: '/Plugins/{pluginId}/{version}') + Future _pluginsPluginIdVersionDelete({ + @Path('pluginId') required String? pluginId, + @Path('version') required String? version, + }); + + ///Disable a plugin. + ///@param pluginId Plugin id. + ///@param version Plugin version. + Future pluginsPluginIdVersionDisablePost({ + required String? pluginId, + required String? version, + }) { + return _pluginsPluginIdVersionDisablePost( + pluginId: pluginId, version: version); + } + + ///Disable a plugin. + ///@param pluginId Plugin id. + ///@param version Plugin version. + @Post( + path: '/Plugins/{pluginId}/{version}/Disable', + optionalBody: true, + ) + Future _pluginsPluginIdVersionDisablePost({ + @Path('pluginId') required String? pluginId, + @Path('version') required String? version, + }); + + ///Enables a disabled plugin. + ///@param pluginId Plugin id. + ///@param version Plugin version. + Future pluginsPluginIdVersionEnablePost({ + required String? pluginId, + required String? version, + }) { + return _pluginsPluginIdVersionEnablePost( + pluginId: pluginId, version: version); + } + + ///Enables a disabled plugin. + ///@param pluginId Plugin id. + ///@param version Plugin version. + @Post( + path: '/Plugins/{pluginId}/{version}/Enable', + optionalBody: true, + ) + Future _pluginsPluginIdVersionEnablePost({ + @Path('pluginId') required String? pluginId, + @Path('version') required String? version, + }); + + ///Gets a plugin's image. + ///@param pluginId Plugin id. + ///@param version Plugin version. + Future> pluginsPluginIdVersionImageGet({ + required String? pluginId, + required String? version, + }) { + return _pluginsPluginIdVersionImageGet( + pluginId: pluginId, version: version); + } + + ///Gets a plugin's image. + ///@param pluginId Plugin id. + ///@param version Plugin version. + @Get(path: '/Plugins/{pluginId}/{version}/Image') + Future> _pluginsPluginIdVersionImageGet({ + @Path('pluginId') required String? pluginId, + @Path('version') required String? version, + }); + + ///Gets plugin configuration. + ///@param pluginId Plugin id. + Future> + pluginsPluginIdConfigurationGet({required String? pluginId}) { + generatedMapping.putIfAbsent( + BasePluginConfiguration, () => BasePluginConfiguration.fromJsonFactory); + + return _pluginsPluginIdConfigurationGet(pluginId: pluginId); + } + + ///Gets plugin configuration. + ///@param pluginId Plugin id. + @Get(path: '/Plugins/{pluginId}/Configuration') + Future> + _pluginsPluginIdConfigurationGet( + {@Path('pluginId') required String? pluginId}); + + ///Updates plugin configuration. + ///@param pluginId Plugin id. + Future pluginsPluginIdConfigurationPost( + {required String? pluginId}) { + return _pluginsPluginIdConfigurationPost(pluginId: pluginId); + } + + ///Updates plugin configuration. + ///@param pluginId Plugin id. + @Post( + path: '/Plugins/{pluginId}/Configuration', + optionalBody: true, + ) + Future _pluginsPluginIdConfigurationPost( + {@Path('pluginId') required String? pluginId}); + + ///Gets a plugin's manifest. + ///@param pluginId Plugin id. + Future pluginsPluginIdManifestPost( + {required String? pluginId}) { + return _pluginsPluginIdManifestPost(pluginId: pluginId); + } + + ///Gets a plugin's manifest. + ///@param pluginId Plugin id. + @Post( + path: '/Plugins/{pluginId}/Manifest', + optionalBody: true, + ) + Future _pluginsPluginIdManifestPost( + {@Path('pluginId') required String? pluginId}); + + ///Authorizes a pending quick connect request. + ///@param code Quick connect code to authorize. + ///@param userId The user the authorize. Access to the requested user is required. + Future> quickConnectAuthorizePost({ + required String? code, + String? userId, + }) { + return _quickConnectAuthorizePost(code: code, userId: userId); + } + + ///Authorizes a pending quick connect request. + ///@param code Quick connect code to authorize. + ///@param userId The user the authorize. Access to the requested user is required. + @Post( + path: '/QuickConnect/Authorize', + optionalBody: true, + ) + Future> _quickConnectAuthorizePost({ + @Query('code') required String? code, + @Query('userId') String? userId, + }); + + ///Attempts to retrieve authentication information. + ///@param secret Secret previously returned from the Initiate endpoint. + Future> quickConnectConnectGet( + {required String? secret}) { + generatedMapping.putIfAbsent( + QuickConnectResult, () => QuickConnectResult.fromJsonFactory); + + return _quickConnectConnectGet(secret: secret); + } + + ///Attempts to retrieve authentication information. + ///@param secret Secret previously returned from the Initiate endpoint. + @Get(path: '/QuickConnect/Connect') + Future> _quickConnectConnectGet( + {@Query('secret') required String? secret}); + + ///Gets the current quick connect state. + Future> quickConnectEnabledGet() { + return _quickConnectEnabledGet(); + } + + ///Gets the current quick connect state. + @Get(path: '/QuickConnect/Enabled') + Future> _quickConnectEnabledGet(); + + ///Initiate a new quick connect request. + Future> quickConnectInitiatePost() { + generatedMapping.putIfAbsent( + QuickConnectResult, () => QuickConnectResult.fromJsonFactory); + + return _quickConnectInitiatePost(); + } + + ///Initiate a new quick connect request. + @Post( + path: '/QuickConnect/Initiate', + optionalBody: true, + ) + Future> _quickConnectInitiatePost(); + + ///Gets available remote images for an item. + ///@param itemId Item Id. + ///@param type The image type. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param providerName Optional. The image provider to use. + ///@param includeAllLanguages Optional. Include all languages. + Future> itemsItemIdRemoteImagesGet({ + required String? itemId, + enums.ItemsItemIdRemoteImagesGetType? type, + int? startIndex, + int? limit, + String? providerName, + bool? includeAllLanguages, + }) { + generatedMapping.putIfAbsent( + RemoteImageResult, () => RemoteImageResult.fromJsonFactory); + + return _itemsItemIdRemoteImagesGet( + itemId: itemId, + type: type?.value?.toString(), + startIndex: startIndex, + limit: limit, + providerName: providerName, + includeAllLanguages: includeAllLanguages); + } + + ///Gets available remote images for an item. + ///@param itemId Item Id. + ///@param type The image type. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param providerName Optional. The image provider to use. + ///@param includeAllLanguages Optional. Include all languages. + @Get(path: '/Items/{itemId}/RemoteImages') + Future> _itemsItemIdRemoteImagesGet({ + @Path('itemId') required String? itemId, + @Query('type') String? type, + @Query('startIndex') int? startIndex, + @Query('limit') int? limit, + @Query('providerName') String? providerName, + @Query('includeAllLanguages') bool? includeAllLanguages, + }); + + ///Downloads a remote image for an item. + ///@param itemId Item Id. + ///@param type The image type. + ///@param imageUrl The image url. + Future itemsItemIdRemoteImagesDownloadPost({ + required String? itemId, + required enums.ItemsItemIdRemoteImagesDownloadPostType? type, + String? imageUrl, + }) { + return _itemsItemIdRemoteImagesDownloadPost( + itemId: itemId, type: type?.value?.toString(), imageUrl: imageUrl); + } + + ///Downloads a remote image for an item. + ///@param itemId Item Id. + ///@param type The image type. + ///@param imageUrl The image url. + @Post( + path: '/Items/{itemId}/RemoteImages/Download', + optionalBody: true, + ) + Future _itemsItemIdRemoteImagesDownloadPost({ + @Path('itemId') required String? itemId, + @Query('type') required String? type, + @Query('imageUrl') String? imageUrl, + }); + + ///Gets available remote image providers for an item. + ///@param itemId Item Id. + Future>> + itemsItemIdRemoteImagesProvidersGet({required String? itemId}) { + generatedMapping.putIfAbsent( + ImageProviderInfo, () => ImageProviderInfo.fromJsonFactory); + + return _itemsItemIdRemoteImagesProvidersGet(itemId: itemId); + } + + ///Gets available remote image providers for an item. + ///@param itemId Item Id. + @Get(path: '/Items/{itemId}/RemoteImages/Providers') + Future>> + _itemsItemIdRemoteImagesProvidersGet( + {@Path('itemId') required String? itemId}); + + ///Get tasks. + ///@param isHidden Optional filter tasks that are hidden, or not. + ///@param isEnabled Optional filter tasks that are enabled, or not. + Future>> scheduledTasksGet({ + bool? isHidden, + bool? isEnabled, + }) { + generatedMapping.putIfAbsent(TaskInfo, () => TaskInfo.fromJsonFactory); + + return _scheduledTasksGet(isHidden: isHidden, isEnabled: isEnabled); + } + + ///Get tasks. + ///@param isHidden Optional filter tasks that are hidden, or not. + ///@param isEnabled Optional filter tasks that are enabled, or not. + @Get(path: '/ScheduledTasks') + Future>> _scheduledTasksGet({ + @Query('isHidden') bool? isHidden, + @Query('isEnabled') bool? isEnabled, + }); + + ///Get task by id. + ///@param taskId Task Id. + Future> scheduledTasksTaskIdGet( + {required String? taskId}) { + generatedMapping.putIfAbsent(TaskInfo, () => TaskInfo.fromJsonFactory); + + return _scheduledTasksTaskIdGet(taskId: taskId); + } + + ///Get task by id. + ///@param taskId Task Id. + @Get(path: '/ScheduledTasks/{taskId}') + Future> _scheduledTasksTaskIdGet( + {@Path('taskId') required String? taskId}); + + ///Update specified task triggers. + ///@param taskId Task Id. + Future scheduledTasksTaskIdTriggersPost({ + required String? taskId, + required List? body, + }) { + return _scheduledTasksTaskIdTriggersPost(taskId: taskId, body: body); + } + + ///Update specified task triggers. + ///@param taskId Task Id. + @Post( + path: '/ScheduledTasks/{taskId}/Triggers', + optionalBody: true, + ) + Future _scheduledTasksTaskIdTriggersPost({ + @Path('taskId') required String? taskId, + @Body() required List? body, + }); + + ///Start specified task. + ///@param taskId Task Id. + Future scheduledTasksRunningTaskIdPost( + {required String? taskId}) { + return _scheduledTasksRunningTaskIdPost(taskId: taskId); + } + + ///Start specified task. + ///@param taskId Task Id. + @Post( + path: '/ScheduledTasks/Running/{taskId}', + optionalBody: true, + ) + Future _scheduledTasksRunningTaskIdPost( + {@Path('taskId') required String? taskId}); + + ///Stop specified task. + ///@param taskId Task Id. + Future scheduledTasksRunningTaskIdDelete( + {required String? taskId}) { + return _scheduledTasksRunningTaskIdDelete(taskId: taskId); + } + + ///Stop specified task. + ///@param taskId Task Id. + @Delete(path: '/ScheduledTasks/Running/{taskId}') + Future _scheduledTasksRunningTaskIdDelete( + {@Path('taskId') required String? taskId}); + + ///Gets the search hint result. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param userId Optional. Supply a user id to search within a user's library or omit to search all. + ///@param searchTerm The search term to filter on. + ///@param includeItemTypes If specified, only results with the specified item types are returned. This allows multiple, comma delimited. + ///@param excludeItemTypes If specified, results with these item types are filtered out. This allows multiple, comma delimited. + ///@param mediaTypes If specified, only results with the specified media types are returned. This allows multiple, comma delimited. + ///@param parentId If specified, only children of the parent are returned. + ///@param isMovie Optional filter for movies. + ///@param isSeries Optional filter for series. + ///@param isNews Optional filter for news. + ///@param isKids Optional filter for kids. + ///@param isSports Optional filter for sports. + ///@param includePeople Optional filter whether to include people. + ///@param includeMedia Optional filter whether to include media. + ///@param includeGenres Optional filter whether to include genres. + ///@param includeStudios Optional filter whether to include studios. + ///@param includeArtists Optional filter whether to include artists. + Future> searchHintsGet({ + int? startIndex, + int? limit, + String? userId, + required String? searchTerm, + List? includeItemTypes, + List? excludeItemTypes, + List? mediaTypes, + String? parentId, + bool? isMovie, + bool? isSeries, + bool? isNews, + bool? isKids, + bool? isSports, + bool? includePeople, + bool? includeMedia, + bool? includeGenres, + bool? includeStudios, + bool? includeArtists, + }) { + generatedMapping.putIfAbsent( + SearchHintResult, () => SearchHintResult.fromJsonFactory); + + return _searchHintsGet( + startIndex: startIndex, + limit: limit, + userId: userId, + searchTerm: searchTerm, + includeItemTypes: baseItemKindListToJson(includeItemTypes), + excludeItemTypes: baseItemKindListToJson(excludeItemTypes), + mediaTypes: mediaTypeListToJson(mediaTypes), + parentId: parentId, + isMovie: isMovie, + isSeries: isSeries, + isNews: isNews, + isKids: isKids, + isSports: isSports, + includePeople: includePeople, + includeMedia: includeMedia, + includeGenres: includeGenres, + includeStudios: includeStudios, + includeArtists: includeArtists); + } + + ///Gets the search hint result. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param userId Optional. Supply a user id to search within a user's library or omit to search all. + ///@param searchTerm The search term to filter on. + ///@param includeItemTypes If specified, only results with the specified item types are returned. This allows multiple, comma delimited. + ///@param excludeItemTypes If specified, results with these item types are filtered out. This allows multiple, comma delimited. + ///@param mediaTypes If specified, only results with the specified media types are returned. This allows multiple, comma delimited. + ///@param parentId If specified, only children of the parent are returned. + ///@param isMovie Optional filter for movies. + ///@param isSeries Optional filter for series. + ///@param isNews Optional filter for news. + ///@param isKids Optional filter for kids. + ///@param isSports Optional filter for sports. + ///@param includePeople Optional filter whether to include people. + ///@param includeMedia Optional filter whether to include media. + ///@param includeGenres Optional filter whether to include genres. + ///@param includeStudios Optional filter whether to include studios. + ///@param includeArtists Optional filter whether to include artists. + @Get(path: '/Search/Hints') + Future> _searchHintsGet({ + @Query('startIndex') int? startIndex, + @Query('limit') int? limit, + @Query('userId') String? userId, + @Query('searchTerm') required String? searchTerm, + @Query('includeItemTypes') List? includeItemTypes, + @Query('excludeItemTypes') List? excludeItemTypes, + @Query('mediaTypes') List? mediaTypes, + @Query('parentId') String? parentId, + @Query('isMovie') bool? isMovie, + @Query('isSeries') bool? isSeries, + @Query('isNews') bool? isNews, + @Query('isKids') bool? isKids, + @Query('isSports') bool? isSports, + @Query('includePeople') bool? includePeople, + @Query('includeMedia') bool? includeMedia, + @Query('includeGenres') bool? includeGenres, + @Query('includeStudios') bool? includeStudios, + @Query('includeArtists') bool? includeArtists, + }); + + ///Get all password reset providers. + Future>> authPasswordResetProvidersGet() { + generatedMapping.putIfAbsent(NameIdPair, () => NameIdPair.fromJsonFactory); + + return _authPasswordResetProvidersGet(); + } + + ///Get all password reset providers. + @Get(path: '/Auth/PasswordResetProviders') + Future>> _authPasswordResetProvidersGet(); + + ///Get all auth providers. + Future>> authProvidersGet() { + generatedMapping.putIfAbsent(NameIdPair, () => NameIdPair.fromJsonFactory); + + return _authProvidersGet(); + } + + ///Get all auth providers. + @Get(path: '/Auth/Providers') + Future>> _authProvidersGet(); + + ///Gets a list of sessions. + ///@param controllableByUserId Filter by sessions that a given user is allowed to remote control. + ///@param deviceId Filter by device Id. + ///@param activeWithinSeconds Optional. Filter by sessions that were active in the last n seconds. + Future>> sessionsGet({ + String? controllableByUserId, + String? deviceId, + int? activeWithinSeconds, + }) { + generatedMapping.putIfAbsent( + SessionInfo, () => SessionInfo.fromJsonFactory); + + return _sessionsGet( + controllableByUserId: controllableByUserId, + deviceId: deviceId, + activeWithinSeconds: activeWithinSeconds); + } + + ///Gets a list of sessions. + ///@param controllableByUserId Filter by sessions that a given user is allowed to remote control. + ///@param deviceId Filter by device Id. + ///@param activeWithinSeconds Optional. Filter by sessions that were active in the last n seconds. + @Get(path: '/Sessions') + Future>> _sessionsGet({ + @Query('controllableByUserId') String? controllableByUserId, + @Query('deviceId') String? deviceId, + @Query('activeWithinSeconds') int? activeWithinSeconds, + }); + + ///Issues a full general command to a client. + ///@param sessionId The session id. + Future sessionsSessionIdCommandPost({ + required String? sessionId, + required GeneralCommand? body, + }) { + return _sessionsSessionIdCommandPost(sessionId: sessionId, body: body); + } + + ///Issues a full general command to a client. + ///@param sessionId The session id. + @Post( + path: '/Sessions/{sessionId}/Command', + optionalBody: true, + ) + Future _sessionsSessionIdCommandPost({ + @Path('sessionId') required String? sessionId, + @Body() required GeneralCommand? body, + }); + + ///Issues a general command to a client. + ///@param sessionId The session id. + ///@param command The command to send. + Future sessionsSessionIdCommandCommandPost({ + required String? sessionId, + required enums.SessionsSessionIdCommandCommandPostCommand? command, + }) { + return _sessionsSessionIdCommandCommandPost( + sessionId: sessionId, command: command?.value?.toString()); + } + + ///Issues a general command to a client. + ///@param sessionId The session id. + ///@param command The command to send. + @Post( + path: '/Sessions/{sessionId}/Command/{command}', + optionalBody: true, + ) + Future _sessionsSessionIdCommandCommandPost({ + @Path('sessionId') required String? sessionId, + @Path('command') required String? command, + }); + + ///Issues a command to a client to display a message to the user. + ///@param sessionId The session id. + Future sessionsSessionIdMessagePost({ + required String? sessionId, + required MessageCommand? body, + }) { + return _sessionsSessionIdMessagePost(sessionId: sessionId, body: body); + } + + ///Issues a command to a client to display a message to the user. + ///@param sessionId The session id. + @Post( + path: '/Sessions/{sessionId}/Message', + optionalBody: true, + ) + Future _sessionsSessionIdMessagePost({ + @Path('sessionId') required String? sessionId, + @Body() required MessageCommand? body, + }); + + ///Instructs a session to play an item. + ///@param sessionId The session id. + ///@param playCommand The type of play command to issue (PlayNow, PlayNext, PlayLast). Clients who have not yet implemented play next and play last may play now. + ///@param itemIds The ids of the items to play, comma delimited. + ///@param startPositionTicks The starting position of the first item. + ///@param mediaSourceId Optional. The media source id. + ///@param audioStreamIndex Optional. The index of the audio stream to play. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to play. + ///@param startIndex Optional. The start index. + Future sessionsSessionIdPlayingPost({ + required String? sessionId, + required enums.SessionsSessionIdPlayingPostPlayCommand? playCommand, + required List? itemIds, + int? startPositionTicks, + String? mediaSourceId, + int? audioStreamIndex, + int? subtitleStreamIndex, + int? startIndex, + }) { + return _sessionsSessionIdPlayingPost( + sessionId: sessionId, + playCommand: playCommand?.value?.toString(), + itemIds: itemIds, + startPositionTicks: startPositionTicks, + mediaSourceId: mediaSourceId, + audioStreamIndex: audioStreamIndex, + subtitleStreamIndex: subtitleStreamIndex, + startIndex: startIndex); + } + + ///Instructs a session to play an item. + ///@param sessionId The session id. + ///@param playCommand The type of play command to issue (PlayNow, PlayNext, PlayLast). Clients who have not yet implemented play next and play last may play now. + ///@param itemIds The ids of the items to play, comma delimited. + ///@param startPositionTicks The starting position of the first item. + ///@param mediaSourceId Optional. The media source id. + ///@param audioStreamIndex Optional. The index of the audio stream to play. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to play. + ///@param startIndex Optional. The start index. + @Post( + path: '/Sessions/{sessionId}/Playing', + optionalBody: true, + ) + Future _sessionsSessionIdPlayingPost({ + @Path('sessionId') required String? sessionId, + @Query('playCommand') required String? playCommand, + @Query('itemIds') required List? itemIds, + @Query('startPositionTicks') int? startPositionTicks, + @Query('mediaSourceId') String? mediaSourceId, + @Query('audioStreamIndex') int? audioStreamIndex, + @Query('subtitleStreamIndex') int? subtitleStreamIndex, + @Query('startIndex') int? startIndex, + }); + + ///Issues a playstate command to a client. + ///@param sessionId The session id. + ///@param command The MediaBrowser.Model.Session.PlaystateCommand. + ///@param seekPositionTicks The optional position ticks. + ///@param controllingUserId The optional controlling user id. + Future sessionsSessionIdPlayingCommandPost({ + required String? sessionId, + required enums.SessionsSessionIdPlayingCommandPostCommand? command, + int? seekPositionTicks, + String? controllingUserId, + }) { + return _sessionsSessionIdPlayingCommandPost( + sessionId: sessionId, + command: command?.value?.toString(), + seekPositionTicks: seekPositionTicks, + controllingUserId: controllingUserId); + } + + ///Issues a playstate command to a client. + ///@param sessionId The session id. + ///@param command The MediaBrowser.Model.Session.PlaystateCommand. + ///@param seekPositionTicks The optional position ticks. + ///@param controllingUserId The optional controlling user id. + @Post( + path: '/Sessions/{sessionId}/Playing/{command}', + optionalBody: true, + ) + Future _sessionsSessionIdPlayingCommandPost({ + @Path('sessionId') required String? sessionId, + @Path('command') required String? command, + @Query('seekPositionTicks') int? seekPositionTicks, + @Query('controllingUserId') String? controllingUserId, + }); + + ///Issues a system command to a client. + ///@param sessionId The session id. + ///@param command The command to send. + Future sessionsSessionIdSystemCommandPost({ + required String? sessionId, + required enums.SessionsSessionIdSystemCommandPostCommand? command, + }) { + return _sessionsSessionIdSystemCommandPost( + sessionId: sessionId, command: command?.value?.toString()); + } + + ///Issues a system command to a client. + ///@param sessionId The session id. + ///@param command The command to send. + @Post( + path: '/Sessions/{sessionId}/System/{command}', + optionalBody: true, + ) + Future _sessionsSessionIdSystemCommandPost({ + @Path('sessionId') required String? sessionId, + @Path('command') required String? command, + }); + + ///Adds an additional user to a session. + ///@param sessionId The session id. + ///@param userId The user id. + Future sessionsSessionIdUserUserIdPost({ + required String? sessionId, + required String? userId, + }) { + return _sessionsSessionIdUserUserIdPost( + sessionId: sessionId, userId: userId); + } + + ///Adds an additional user to a session. + ///@param sessionId The session id. + ///@param userId The user id. + @Post( + path: '/Sessions/{sessionId}/User/{userId}', + optionalBody: true, + ) + Future _sessionsSessionIdUserUserIdPost({ + @Path('sessionId') required String? sessionId, + @Path('userId') required String? userId, + }); + + ///Removes an additional user from a session. + ///@param sessionId The session id. + ///@param userId The user id. + Future sessionsSessionIdUserUserIdDelete({ + required String? sessionId, + required String? userId, + }) { + return _sessionsSessionIdUserUserIdDelete( + sessionId: sessionId, userId: userId); + } + + ///Removes an additional user from a session. + ///@param sessionId The session id. + ///@param userId The user id. + @Delete(path: '/Sessions/{sessionId}/User/{userId}') + Future _sessionsSessionIdUserUserIdDelete({ + @Path('sessionId') required String? sessionId, + @Path('userId') required String? userId, + }); + + ///Instructs a session to browse to an item or view. + ///@param sessionId The session Id. + ///@param itemType The type of item to browse to. + ///@param itemId The Id of the item. + ///@param itemName The name of the item. + Future sessionsSessionIdViewingPost({ + required String? sessionId, + required enums.SessionsSessionIdViewingPostItemType? itemType, + required String? itemId, + required String? itemName, + }) { + return _sessionsSessionIdViewingPost( + sessionId: sessionId, + itemType: itemType?.value?.toString(), + itemId: itemId, + itemName: itemName); + } + + ///Instructs a session to browse to an item or view. + ///@param sessionId The session Id. + ///@param itemType The type of item to browse to. + ///@param itemId The Id of the item. + ///@param itemName The name of the item. + @Post( + path: '/Sessions/{sessionId}/Viewing', + optionalBody: true, + ) + Future _sessionsSessionIdViewingPost({ + @Path('sessionId') required String? sessionId, + @Query('itemType') required String? itemType, + @Query('itemId') required String? itemId, + @Query('itemName') required String? itemName, + }); + + ///Updates capabilities for a device. + ///@param id The session id. + ///@param playableMediaTypes A list of playable media types, comma delimited. Audio, Video, Book, Photo. + ///@param supportedCommands A list of supported remote control commands, comma delimited. + ///@param supportsMediaControl Determines whether media can be played remotely.. + ///@param supportsPersistentIdentifier Determines whether the device supports a unique identifier. + Future sessionsCapabilitiesPost({ + String? id, + List? playableMediaTypes, + List? supportedCommands, + bool? supportsMediaControl, + bool? supportsPersistentIdentifier, + }) { + return _sessionsCapabilitiesPost( + id: id, + playableMediaTypes: mediaTypeListToJson(playableMediaTypes), + supportedCommands: generalCommandTypeListToJson(supportedCommands), + supportsMediaControl: supportsMediaControl, + supportsPersistentIdentifier: supportsPersistentIdentifier); + } + + ///Updates capabilities for a device. + ///@param id The session id. + ///@param playableMediaTypes A list of playable media types, comma delimited. Audio, Video, Book, Photo. + ///@param supportedCommands A list of supported remote control commands, comma delimited. + ///@param supportsMediaControl Determines whether media can be played remotely.. + ///@param supportsPersistentIdentifier Determines whether the device supports a unique identifier. + @Post( + path: '/Sessions/Capabilities', + optionalBody: true, + ) + Future _sessionsCapabilitiesPost({ + @Query('id') String? id, + @Query('playableMediaTypes') List? playableMediaTypes, + @Query('supportedCommands') List? supportedCommands, + @Query('supportsMediaControl') bool? supportsMediaControl, + @Query('supportsPersistentIdentifier') bool? supportsPersistentIdentifier, + }); + + ///Updates capabilities for a device. + ///@param id The session id. + Future sessionsCapabilitiesFullPost({ + String? id, + required ClientCapabilitiesDto? body, + }) { + return _sessionsCapabilitiesFullPost(id: id, body: body); + } + + ///Updates capabilities for a device. + ///@param id The session id. + @Post( + path: '/Sessions/Capabilities/Full', + optionalBody: true, + ) + Future _sessionsCapabilitiesFullPost({ + @Query('id') String? id, + @Body() required ClientCapabilitiesDto? body, + }); + + ///Reports that a session has ended. + Future sessionsLogoutPost() { + return _sessionsLogoutPost(); + } + + ///Reports that a session has ended. + @Post( + path: '/Sessions/Logout', + optionalBody: true, + ) + Future _sessionsLogoutPost(); + + ///Reports that a session is viewing an item. + ///@param sessionId The session id. + ///@param itemId The item id. + Future sessionsViewingPost({ + String? sessionId, + required String? itemId, + }) { + return _sessionsViewingPost(sessionId: sessionId, itemId: itemId); + } + + ///Reports that a session is viewing an item. + ///@param sessionId The session id. + ///@param itemId The item id. + @Post( + path: '/Sessions/Viewing', + optionalBody: true, + ) + Future _sessionsViewingPost({ + @Query('sessionId') String? sessionId, + @Query('itemId') required String? itemId, + }); + + /// + ///@param id + Future> episodeIdIntroSkipperSegmentsGet( + {required String? id}) { + return _episodeIdIntroSkipperSegmentsGet(id: id); + } + + /// + ///@param id + @Get(path: '/Episode/{id}/IntroSkipperSegments') + Future> _episodeIdIntroSkipperSegmentsGet( + {@Path('id') required String? id}); + + /// + ///@param id + ///@param mode + Future> episodeIdIntroTimestampsGet({ + required String? id, + enums.EpisodeIdIntroTimestampsGetMode? mode, + }) { + generatedMapping.putIfAbsent(Intro, () => Intro.fromJsonFactory); + + return _episodeIdIntroTimestampsGet(id: id, mode: mode?.value?.toString()); + } + + /// + ///@param id + ///@param mode + @Get(path: '/Episode/{id}/IntroTimestamps') + Future> _episodeIdIntroTimestampsGet({ + @Path('id') required String? id, + @Query('mode') String? mode, + }); + + /// + ///@param id + ///@param mode + Future> episodeIdIntroTimestampsV1Get({ + required String? id, + enums.EpisodeIdIntroTimestampsV1GetMode? mode, + }) { + generatedMapping.putIfAbsent(Intro, () => Intro.fromJsonFactory); + + return _episodeIdIntroTimestampsV1Get( + id: id, mode: mode?.value?.toString()); + } + + /// + ///@param id + ///@param mode + @Get(path: '/Episode/{id}/IntroTimestamps/v1') + Future> _episodeIdIntroTimestampsV1Get({ + @Path('id') required String? id, + @Query('mode') String? mode, + }); + + /// + ///@param mode + Future>> introsAllGet( + {enums.IntrosAllGetMode? mode}) { + generatedMapping.putIfAbsent( + IntroWithMetadata, () => IntroWithMetadata.fromJsonFactory); + + return _introsAllGet(mode: mode?.value?.toString()); + } + + /// + ///@param mode + @Get(path: '/Intros/All') + Future>> _introsAllGet( + {@Query('mode') String? mode}); + + /// + ///@param mode + ///@param eraseCache + Future introsEraseTimestampsPost({ + enums.IntrosEraseTimestampsPostMode? mode, + bool? eraseCache, + }) { + return _introsEraseTimestampsPost( + mode: mode?.value?.toString(), eraseCache: eraseCache); + } + + /// + ///@param mode + ///@param eraseCache + @Post( + path: '/Intros/EraseTimestamps', + optionalBody: true, + ) + Future _introsEraseTimestampsPost({ + @Query('mode') String? mode, + @Query('eraseCache') bool? eraseCache, + }); + + /// + Future> + introsUserInterfaceConfigurationGet() { + generatedMapping.putIfAbsent(UserInterfaceConfiguration, + () => UserInterfaceConfiguration.fromJsonFactory); + + return _introsUserInterfaceConfigurationGet(); + } + + /// + @Get(path: '/Intros/UserInterfaceConfiguration') + Future> + _introsUserInterfaceConfigurationGet(); + + ///Completes the startup wizard. + Future startupCompletePost() { + return _startupCompletePost(); + } + + ///Completes the startup wizard. + @Post( + path: '/Startup/Complete', + optionalBody: true, + ) + Future _startupCompletePost(); + + ///Gets the initial startup wizard configuration. + Future> startupConfigurationGet() { + generatedMapping.putIfAbsent( + StartupConfigurationDto, () => StartupConfigurationDto.fromJsonFactory); + + return _startupConfigurationGet(); + } + + ///Gets the initial startup wizard configuration. + @Get(path: '/Startup/Configuration') + Future> _startupConfigurationGet(); + + ///Sets the initial startup wizard configuration. + Future startupConfigurationPost( + {required StartupConfigurationDto? body}) { + return _startupConfigurationPost(body: body); + } + + ///Sets the initial startup wizard configuration. + @Post( + path: '/Startup/Configuration', + optionalBody: true, + ) + Future _startupConfigurationPost( + {@Body() required StartupConfigurationDto? body}); + + ///Gets the first user. + Future> startupFirstUserGet() { + generatedMapping.putIfAbsent( + StartupUserDto, () => StartupUserDto.fromJsonFactory); + + return _startupFirstUserGet(); + } + + ///Gets the first user. + @Get(path: '/Startup/FirstUser') + Future> _startupFirstUserGet(); + + ///Sets remote access and UPnP. + Future startupRemoteAccessPost( + {required StartupRemoteAccessDto? body}) { + return _startupRemoteAccessPost(body: body); + } + + ///Sets remote access and UPnP. + @Post( + path: '/Startup/RemoteAccess', + optionalBody: true, + ) + Future _startupRemoteAccessPost( + {@Body() required StartupRemoteAccessDto? body}); + + ///Gets the first user. + Future> startupUserGet() { + generatedMapping.putIfAbsent( + StartupUserDto, () => StartupUserDto.fromJsonFactory); + + return _startupUserGet(); + } + + ///Gets the first user. + @Get(path: '/Startup/User') + Future> _startupUserGet(); + + ///Sets the user name and password. + Future startupUserPost({required StartupUserDto? body}) { + return _startupUserPost(body: body); + } + + ///Sets the user name and password. + @Post( + path: '/Startup/User', + optionalBody: true, + ) + Future _startupUserPost( + {@Body() required StartupUserDto? body}); + + ///Gets all studios from a given item, folder, or the entire library. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param searchTerm Optional. Search term. + ///@param parentId Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param excludeItemTypes Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited. + ///@param includeItemTypes Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited. + ///@param isFavorite Optional filter by items that are marked as favorite, or not. + ///@param enableUserData Optional, include user data. + ///@param imageTypeLimit Optional, the max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param userId User id. + ///@param nameStartsWithOrGreater Optional filter by items whose name is sorted equally or greater than a given input string. + ///@param nameStartsWith Optional filter by items whose name is sorted equally than a given input string. + ///@param nameLessThan Optional filter by items whose name is equally or lesser than a given input string. + ///@param enableImages Optional, include image information in output. + ///@param enableTotalRecordCount Total record count. + Future> studiosGet({ + int? startIndex, + int? limit, + String? searchTerm, + String? parentId, + List? fields, + List? excludeItemTypes, + List? includeItemTypes, + bool? isFavorite, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + String? userId, + String? nameStartsWithOrGreater, + String? nameStartsWith, + String? nameLessThan, + bool? enableImages, + bool? enableTotalRecordCount, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _studiosGet( + startIndex: startIndex, + limit: limit, + searchTerm: searchTerm, + parentId: parentId, + fields: itemFieldsListToJson(fields), + excludeItemTypes: baseItemKindListToJson(excludeItemTypes), + includeItemTypes: baseItemKindListToJson(includeItemTypes), + isFavorite: isFavorite, + enableUserData: enableUserData, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes), + userId: userId, + nameStartsWithOrGreater: nameStartsWithOrGreater, + nameStartsWith: nameStartsWith, + nameLessThan: nameLessThan, + enableImages: enableImages, + enableTotalRecordCount: enableTotalRecordCount); + } + + ///Gets all studios from a given item, folder, or the entire library. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param searchTerm Optional. Search term. + ///@param parentId Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param excludeItemTypes Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited. + ///@param includeItemTypes Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited. + ///@param isFavorite Optional filter by items that are marked as favorite, or not. + ///@param enableUserData Optional, include user data. + ///@param imageTypeLimit Optional, the max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param userId User id. + ///@param nameStartsWithOrGreater Optional filter by items whose name is sorted equally or greater than a given input string. + ///@param nameStartsWith Optional filter by items whose name is sorted equally than a given input string. + ///@param nameLessThan Optional filter by items whose name is equally or lesser than a given input string. + ///@param enableImages Optional, include image information in output. + ///@param enableTotalRecordCount Total record count. + @Get(path: '/Studios') + Future> _studiosGet({ + @Query('startIndex') int? startIndex, + @Query('limit') int? limit, + @Query('searchTerm') String? searchTerm, + @Query('parentId') String? parentId, + @Query('fields') List? fields, + @Query('excludeItemTypes') List? excludeItemTypes, + @Query('includeItemTypes') List? includeItemTypes, + @Query('isFavorite') bool? isFavorite, + @Query('enableUserData') bool? enableUserData, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + @Query('userId') String? userId, + @Query('nameStartsWithOrGreater') String? nameStartsWithOrGreater, + @Query('nameStartsWith') String? nameStartsWith, + @Query('nameLessThan') String? nameLessThan, + @Query('enableImages') bool? enableImages, + @Query('enableTotalRecordCount') bool? enableTotalRecordCount, + }); + + ///Gets a studio by name. + ///@param name Studio name. + ///@param userId Optional. Filter by user id, and attach user data. + Future> studiosNameGet({ + required String? name, + String? userId, + }) { + generatedMapping.putIfAbsent( + BaseItemDto, () => BaseItemDto.fromJsonFactory); + + return _studiosNameGet(name: name, userId: userId); + } + + ///Gets a studio by name. + ///@param name Studio name. + ///@param userId Optional. Filter by user id, and attach user data. + @Get(path: '/Studios/{name}') + Future> _studiosNameGet({ + @Path('name') required String? name, + @Query('userId') String? userId, + }); + + ///Gets a list of available fallback font files. + Future>> fallbackFontFontsGet() { + generatedMapping.putIfAbsent(FontFile, () => FontFile.fromJsonFactory); + + return _fallbackFontFontsGet(); + } + + ///Gets a list of available fallback font files. + @Get(path: '/FallbackFont/Fonts') + Future>> _fallbackFontFontsGet(); + + ///Gets a fallback font file. + ///@param name The name of the fallback font file to get. + Future> fallbackFontFontsNameGet( + {required String? name}) { + return _fallbackFontFontsNameGet(name: name); + } + + ///Gets a fallback font file. + ///@param name The name of the fallback font file to get. + @Get(path: '/FallbackFont/Fonts/{name}') + Future> _fallbackFontFontsNameGet( + {@Path('name') required String? name}); + + ///Search remote subtitles. + ///@param itemId The item id. + ///@param language The language of the subtitles. + ///@param isPerfectMatch Optional. Only show subtitles which are a perfect match. + Future>> + itemsItemIdRemoteSearchSubtitlesLanguageGet({ + required String? itemId, + required String? language, + bool? isPerfectMatch, + }) { + generatedMapping.putIfAbsent( + RemoteSubtitleInfo, () => RemoteSubtitleInfo.fromJsonFactory); + + return _itemsItemIdRemoteSearchSubtitlesLanguageGet( + itemId: itemId, language: language, isPerfectMatch: isPerfectMatch); + } + + ///Search remote subtitles. + ///@param itemId The item id. + ///@param language The language of the subtitles. + ///@param isPerfectMatch Optional. Only show subtitles which are a perfect match. + @Get(path: '/Items/{itemId}/RemoteSearch/Subtitles/{language}') + Future>> + _itemsItemIdRemoteSearchSubtitlesLanguageGet({ + @Path('itemId') required String? itemId, + @Path('language') required String? language, + @Query('isPerfectMatch') bool? isPerfectMatch, + }); + + ///Downloads a remote subtitle. + ///@param itemId The item id. + ///@param subtitleId The subtitle id. + Future itemsItemIdRemoteSearchSubtitlesSubtitleIdPost({ + required String? itemId, + required String? subtitleId, + }) { + return _itemsItemIdRemoteSearchSubtitlesSubtitleIdPost( + itemId: itemId, subtitleId: subtitleId); + } + + ///Downloads a remote subtitle. + ///@param itemId The item id. + ///@param subtitleId The subtitle id. + @Post( + path: '/Items/{itemId}/RemoteSearch/Subtitles/{subtitleId}', + optionalBody: true, + ) + Future _itemsItemIdRemoteSearchSubtitlesSubtitleIdPost({ + @Path('itemId') required String? itemId, + @Path('subtitleId') required String? subtitleId, + }); + + ///Gets the remote subtitles. + ///@param subtitleId The item id. + Future> providersSubtitlesSubtitlesSubtitleIdGet( + {required String? subtitleId}) { + return _providersSubtitlesSubtitlesSubtitleIdGet(subtitleId: subtitleId); + } + + ///Gets the remote subtitles. + ///@param subtitleId The item id. + @Get(path: '/Providers/Subtitles/Subtitles/{subtitleId}') + Future> _providersSubtitlesSubtitlesSubtitleIdGet( + {@Path('subtitleId') required String? subtitleId}); + + ///Gets an HLS subtitle playlist. + ///@param itemId The item id. + ///@param index The subtitle stream index. + ///@param mediaSourceId The media source id. + ///@param segmentLength The subtitle segment length. + Future> + videosItemIdMediaSourceIdSubtitlesIndexSubtitlesM3u8Get({ + required String? itemId, + required int? index, + required String? mediaSourceId, + required int? segmentLength, + }) { + return _videosItemIdMediaSourceIdSubtitlesIndexSubtitlesM3u8Get( + itemId: itemId, + index: index, + mediaSourceId: mediaSourceId, + segmentLength: segmentLength); + } + + ///Gets an HLS subtitle playlist. + ///@param itemId The item id. + ///@param index The subtitle stream index. + ///@param mediaSourceId The media source id. + ///@param segmentLength The subtitle segment length. + @Get( + path: '/Videos/{itemId}/{mediaSourceId}/Subtitles/{index}/subtitles.m3u8') + Future> + _videosItemIdMediaSourceIdSubtitlesIndexSubtitlesM3u8Get({ + @Path('itemId') required String? itemId, + @Path('index') required int? index, + @Path('mediaSourceId') required String? mediaSourceId, + @Query('segmentLength') required int? segmentLength, + }); + + ///Upload an external subtitle file. + ///@param itemId The item the subtitle belongs to. + Future videosItemIdSubtitlesPost({ + required String? itemId, + required UploadSubtitleDto? body, + }) { + return _videosItemIdSubtitlesPost(itemId: itemId, body: body); + } + + ///Upload an external subtitle file. + ///@param itemId The item the subtitle belongs to. + @Post( + path: '/Videos/{itemId}/Subtitles', + optionalBody: true, + ) + Future _videosItemIdSubtitlesPost({ + @Path('itemId') required String? itemId, + @Body() required UploadSubtitleDto? body, + }); + + ///Deletes an external subtitle file. + ///@param itemId The item id. + ///@param index The index of the subtitle file. + Future videosItemIdSubtitlesIndexDelete({ + required String? itemId, + required int? index, + }) { + return _videosItemIdSubtitlesIndexDelete(itemId: itemId, index: index); + } + + ///Deletes an external subtitle file. + ///@param itemId The item id. + ///@param index The index of the subtitle file. + @Delete(path: '/Videos/{itemId}/Subtitles/{index}') + Future _videosItemIdSubtitlesIndexDelete({ + @Path('itemId') required String? itemId, + @Path('index') required int? index, + }); + + ///Gets subtitles in a specified format. + ///@param routeItemId The (route) item id. + ///@param routeMediaSourceId The (route) media source id. + ///@param routeIndex The (route) subtitle stream index. + ///@param routeStartPositionTicks The (route) start position of the subtitle in ticks. + ///@param routeFormat The (route) format of the returned subtitle. + ///@param itemId The item id. + ///@param mediaSourceId The media source id. + ///@param index The subtitle stream index. + ///@param startPositionTicks The start position of the subtitle in ticks. + ///@param format The format of the returned subtitle. + ///@param endPositionTicks Optional. The end position of the subtitle in ticks. + ///@param copyTimestamps Optional. Whether to copy the timestamps. + ///@param addVttTimeMap Optional. Whether to add a VTT time map. + Future> + videosRouteItemIdRouteMediaSourceIdSubtitlesRouteIndexRouteStartPositionTicksStreamRouteFormatGet({ + required String? routeItemId, + required String? routeMediaSourceId, + required int? routeIndex, + required int? routeStartPositionTicks, + required String? routeFormat, + String? itemId, + String? mediaSourceId, + int? index, + int? startPositionTicks, + String? format, + int? endPositionTicks, + bool? copyTimestamps, + bool? addVttTimeMap, + }) { + return _videosRouteItemIdRouteMediaSourceIdSubtitlesRouteIndexRouteStartPositionTicksStreamRouteFormatGet( + routeItemId: routeItemId, + routeMediaSourceId: routeMediaSourceId, + routeIndex: routeIndex, + routeStartPositionTicks: routeStartPositionTicks, + routeFormat: routeFormat, + itemId: itemId, + mediaSourceId: mediaSourceId, + index: index, + startPositionTicks: startPositionTicks, + format: format, + endPositionTicks: endPositionTicks, + copyTimestamps: copyTimestamps, + addVttTimeMap: addVttTimeMap); + } + + ///Gets subtitles in a specified format. + ///@param routeItemId The (route) item id. + ///@param routeMediaSourceId The (route) media source id. + ///@param routeIndex The (route) subtitle stream index. + ///@param routeStartPositionTicks The (route) start position of the subtitle in ticks. + ///@param routeFormat The (route) format of the returned subtitle. + ///@param itemId The item id. + ///@param mediaSourceId The media source id. + ///@param index The subtitle stream index. + ///@param startPositionTicks The start position of the subtitle in ticks. + ///@param format The format of the returned subtitle. + ///@param endPositionTicks Optional. The end position of the subtitle in ticks. + ///@param copyTimestamps Optional. Whether to copy the timestamps. + ///@param addVttTimeMap Optional. Whether to add a VTT time map. + @Get( + path: + '/Videos/{routeItemId}/{routeMediaSourceId}/Subtitles/{routeIndex}/{routeStartPositionTicks}/Stream.{routeFormat}') + Future> + _videosRouteItemIdRouteMediaSourceIdSubtitlesRouteIndexRouteStartPositionTicksStreamRouteFormatGet({ + @Path('routeItemId') required String? routeItemId, + @Path('routeMediaSourceId') required String? routeMediaSourceId, + @Path('routeIndex') required int? routeIndex, + @Path('routeStartPositionTicks') required int? routeStartPositionTicks, + @Path('routeFormat') required String? routeFormat, + @Query('itemId') String? itemId, + @Query('mediaSourceId') String? mediaSourceId, + @Query('index') int? index, + @Query('startPositionTicks') int? startPositionTicks, + @Query('format') String? format, + @Query('endPositionTicks') int? endPositionTicks, + @Query('copyTimestamps') bool? copyTimestamps, + @Query('addVttTimeMap') bool? addVttTimeMap, + }); + + ///Gets subtitles in a specified format. + ///@param routeItemId The (route) item id. + ///@param routeMediaSourceId The (route) media source id. + ///@param routeIndex The (route) subtitle stream index. + ///@param routeFormat The (route) format of the returned subtitle. + ///@param itemId The item id. + ///@param mediaSourceId The media source id. + ///@param index The subtitle stream index. + ///@param format The format of the returned subtitle. + ///@param endPositionTicks Optional. The end position of the subtitle in ticks. + ///@param copyTimestamps Optional. Whether to copy the timestamps. + ///@param addVttTimeMap Optional. Whether to add a VTT time map. + ///@param startPositionTicks The start position of the subtitle in ticks. + Future> + videosRouteItemIdRouteMediaSourceIdSubtitlesRouteIndexStreamRouteFormatGet({ + required String? routeItemId, + required String? routeMediaSourceId, + required int? routeIndex, + required String? routeFormat, + String? itemId, + String? mediaSourceId, + int? index, + String? format, + int? endPositionTicks, + bool? copyTimestamps, + bool? addVttTimeMap, + int? startPositionTicks, + }) { + return _videosRouteItemIdRouteMediaSourceIdSubtitlesRouteIndexStreamRouteFormatGet( + routeItemId: routeItemId, + routeMediaSourceId: routeMediaSourceId, + routeIndex: routeIndex, + routeFormat: routeFormat, + itemId: itemId, + mediaSourceId: mediaSourceId, + index: index, + format: format, + endPositionTicks: endPositionTicks, + copyTimestamps: copyTimestamps, + addVttTimeMap: addVttTimeMap, + startPositionTicks: startPositionTicks); + } + + ///Gets subtitles in a specified format. + ///@param routeItemId The (route) item id. + ///@param routeMediaSourceId The (route) media source id. + ///@param routeIndex The (route) subtitle stream index. + ///@param routeFormat The (route) format of the returned subtitle. + ///@param itemId The item id. + ///@param mediaSourceId The media source id. + ///@param index The subtitle stream index. + ///@param format The format of the returned subtitle. + ///@param endPositionTicks Optional. The end position of the subtitle in ticks. + ///@param copyTimestamps Optional. Whether to copy the timestamps. + ///@param addVttTimeMap Optional. Whether to add a VTT time map. + ///@param startPositionTicks The start position of the subtitle in ticks. + @Get( + path: + '/Videos/{routeItemId}/{routeMediaSourceId}/Subtitles/{routeIndex}/Stream.{routeFormat}') + Future> + _videosRouteItemIdRouteMediaSourceIdSubtitlesRouteIndexStreamRouteFormatGet({ + @Path('routeItemId') required String? routeItemId, + @Path('routeMediaSourceId') required String? routeMediaSourceId, + @Path('routeIndex') required int? routeIndex, + @Path('routeFormat') required String? routeFormat, + @Query('itemId') String? itemId, + @Query('mediaSourceId') String? mediaSourceId, + @Query('index') int? index, + @Query('format') String? format, + @Query('endPositionTicks') int? endPositionTicks, + @Query('copyTimestamps') bool? copyTimestamps, + @Query('addVttTimeMap') bool? addVttTimeMap, + @Query('startPositionTicks') int? startPositionTicks, + }); + + ///Gets suggestions. + ///@param userId The user id. + ///@param mediaType The media types. + ///@param type The type. + ///@param startIndex Optional. The start index. + ///@param limit Optional. The limit. + ///@param enableTotalRecordCount Whether to enable the total record count. + Future> itemsSuggestionsGet({ + String? userId, + List? mediaType, + List? type, + int? startIndex, + int? limit, + bool? enableTotalRecordCount, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _itemsSuggestionsGet( + userId: userId, + mediaType: mediaTypeListToJson(mediaType), + type: baseItemKindListToJson(type), + startIndex: startIndex, + limit: limit, + enableTotalRecordCount: enableTotalRecordCount); + } + + ///Gets suggestions. + ///@param userId The user id. + ///@param mediaType The media types. + ///@param type The type. + ///@param startIndex Optional. The start index. + ///@param limit Optional. The limit. + ///@param enableTotalRecordCount Whether to enable the total record count. + @Get(path: '/Items/Suggestions') + Future> _itemsSuggestionsGet({ + @Query('userId') String? userId, + @Query('mediaType') List? mediaType, + @Query('type') List? type, + @Query('startIndex') int? startIndex, + @Query('limit') int? limit, + @Query('enableTotalRecordCount') bool? enableTotalRecordCount, + }); + + ///Notify SyncPlay group that member is buffering. + Future syncPlayBufferingPost( + {required BufferRequestDto? body}) { + return _syncPlayBufferingPost(body: body); + } + + ///Notify SyncPlay group that member is buffering. + @Post( + path: '/SyncPlay/Buffering', + optionalBody: true, + ) + Future _syncPlayBufferingPost( + {@Body() required BufferRequestDto? body}); + + ///Join an existing SyncPlay group. + Future syncPlayJoinPost( + {required JoinGroupRequestDto? body}) { + return _syncPlayJoinPost(body: body); + } + + ///Join an existing SyncPlay group. + @Post( + path: '/SyncPlay/Join', + optionalBody: true, + ) + Future _syncPlayJoinPost( + {@Body() required JoinGroupRequestDto? body}); + + ///Leave the joined SyncPlay group. + Future syncPlayLeavePost() { + return _syncPlayLeavePost(); + } + + ///Leave the joined SyncPlay group. + @Post( + path: '/SyncPlay/Leave', + optionalBody: true, + ) + Future _syncPlayLeavePost(); + + ///Gets all SyncPlay groups. + Future>> syncPlayListGet() { + generatedMapping.putIfAbsent( + GroupInfoDto, () => GroupInfoDto.fromJsonFactory); + + return _syncPlayListGet(); + } + + ///Gets all SyncPlay groups. + @Get(path: '/SyncPlay/List') + Future>> _syncPlayListGet(); + + ///Request to move an item in the playlist in SyncPlay group. + Future syncPlayMovePlaylistItemPost( + {required MovePlaylistItemRequestDto? body}) { + return _syncPlayMovePlaylistItemPost(body: body); + } + + ///Request to move an item in the playlist in SyncPlay group. + @Post( + path: '/SyncPlay/MovePlaylistItem', + optionalBody: true, + ) + Future _syncPlayMovePlaylistItemPost( + {@Body() required MovePlaylistItemRequestDto? body}); + + ///Create a new SyncPlay group. + Future syncPlayNewPost( + {required NewGroupRequestDto? body}) { + return _syncPlayNewPost(body: body); + } + + ///Create a new SyncPlay group. + @Post( + path: '/SyncPlay/New', + optionalBody: true, + ) + Future _syncPlayNewPost( + {@Body() required NewGroupRequestDto? body}); + + ///Request next item in SyncPlay group. + Future syncPlayNextItemPost( + {required NextItemRequestDto? body}) { + return _syncPlayNextItemPost(body: body); + } + + ///Request next item in SyncPlay group. + @Post( + path: '/SyncPlay/NextItem', + optionalBody: true, + ) + Future _syncPlayNextItemPost( + {@Body() required NextItemRequestDto? body}); + + ///Request pause in SyncPlay group. + Future syncPlayPausePost() { + return _syncPlayPausePost(); + } + + ///Request pause in SyncPlay group. + @Post( + path: '/SyncPlay/Pause', + optionalBody: true, + ) + Future _syncPlayPausePost(); + + ///Update session ping. + Future syncPlayPingPost({required PingRequestDto? body}) { + return _syncPlayPingPost(body: body); + } + + ///Update session ping. + @Post( + path: '/SyncPlay/Ping', + optionalBody: true, + ) + Future _syncPlayPingPost( + {@Body() required PingRequestDto? body}); + + ///Request previous item in SyncPlay group. + Future syncPlayPreviousItemPost( + {required PreviousItemRequestDto? body}) { + return _syncPlayPreviousItemPost(body: body); + } + + ///Request previous item in SyncPlay group. + @Post( + path: '/SyncPlay/PreviousItem', + optionalBody: true, + ) + Future _syncPlayPreviousItemPost( + {@Body() required PreviousItemRequestDto? body}); + + ///Request to queue items to the playlist of a SyncPlay group. + Future syncPlayQueuePost({required QueueRequestDto? body}) { + return _syncPlayQueuePost(body: body); + } + + ///Request to queue items to the playlist of a SyncPlay group. + @Post( + path: '/SyncPlay/Queue', + optionalBody: true, + ) + Future _syncPlayQueuePost( + {@Body() required QueueRequestDto? body}); + + ///Notify SyncPlay group that member is ready for playback. + Future syncPlayReadyPost({required ReadyRequestDto? body}) { + return _syncPlayReadyPost(body: body); + } + + ///Notify SyncPlay group that member is ready for playback. + @Post( + path: '/SyncPlay/Ready', + optionalBody: true, + ) + Future _syncPlayReadyPost( + {@Body() required ReadyRequestDto? body}); + + ///Request to remove items from the playlist in SyncPlay group. + Future syncPlayRemoveFromPlaylistPost( + {required RemoveFromPlaylistRequestDto? body}) { + return _syncPlayRemoveFromPlaylistPost(body: body); + } + + ///Request to remove items from the playlist in SyncPlay group. + @Post( + path: '/SyncPlay/RemoveFromPlaylist', + optionalBody: true, + ) + Future _syncPlayRemoveFromPlaylistPost( + {@Body() required RemoveFromPlaylistRequestDto? body}); + + ///Request seek in SyncPlay group. + Future syncPlaySeekPost({required SeekRequestDto? body}) { + return _syncPlaySeekPost(body: body); + } + + ///Request seek in SyncPlay group. + @Post( + path: '/SyncPlay/Seek', + optionalBody: true, + ) + Future _syncPlaySeekPost( + {@Body() required SeekRequestDto? body}); + + ///Request SyncPlay group to ignore member during group-wait. + Future syncPlaySetIgnoreWaitPost( + {required IgnoreWaitRequestDto? body}) { + return _syncPlaySetIgnoreWaitPost(body: body); + } + + ///Request SyncPlay group to ignore member during group-wait. + @Post( + path: '/SyncPlay/SetIgnoreWait', + optionalBody: true, + ) + Future _syncPlaySetIgnoreWaitPost( + {@Body() required IgnoreWaitRequestDto? body}); + + ///Request to set new playlist in SyncPlay group. + Future syncPlaySetNewQueuePost( + {required PlayRequestDto? body}) { + return _syncPlaySetNewQueuePost(body: body); + } + + ///Request to set new playlist in SyncPlay group. + @Post( + path: '/SyncPlay/SetNewQueue', + optionalBody: true, + ) + Future _syncPlaySetNewQueuePost( + {@Body() required PlayRequestDto? body}); + + ///Request to change playlist item in SyncPlay group. + Future syncPlaySetPlaylistItemPost( + {required SetPlaylistItemRequestDto? body}) { + return _syncPlaySetPlaylistItemPost(body: body); + } + + ///Request to change playlist item in SyncPlay group. + @Post( + path: '/SyncPlay/SetPlaylistItem', + optionalBody: true, + ) + Future _syncPlaySetPlaylistItemPost( + {@Body() required SetPlaylistItemRequestDto? body}); + + ///Request to set repeat mode in SyncPlay group. + Future syncPlaySetRepeatModePost( + {required SetRepeatModeRequestDto? body}) { + return _syncPlaySetRepeatModePost(body: body); + } + + ///Request to set repeat mode in SyncPlay group. + @Post( + path: '/SyncPlay/SetRepeatMode', + optionalBody: true, + ) + Future _syncPlaySetRepeatModePost( + {@Body() required SetRepeatModeRequestDto? body}); + + ///Request to set shuffle mode in SyncPlay group. + Future syncPlaySetShuffleModePost( + {required SetShuffleModeRequestDto? body}) { + return _syncPlaySetShuffleModePost(body: body); + } + + ///Request to set shuffle mode in SyncPlay group. + @Post( + path: '/SyncPlay/SetShuffleMode', + optionalBody: true, + ) + Future _syncPlaySetShuffleModePost( + {@Body() required SetShuffleModeRequestDto? body}); + + ///Request stop in SyncPlay group. + Future syncPlayStopPost() { + return _syncPlayStopPost(); + } + + ///Request stop in SyncPlay group. + @Post( + path: '/SyncPlay/Stop', + optionalBody: true, + ) + Future _syncPlayStopPost(); + + ///Request unpause in SyncPlay group. + Future syncPlayUnpausePost() { + return _syncPlayUnpausePost(); + } + + ///Request unpause in SyncPlay group. + @Post( + path: '/SyncPlay/Unpause', + optionalBody: true, + ) + Future _syncPlayUnpausePost(); + + ///Gets information about the request endpoint. + Future> systemEndpointGet() { + generatedMapping.putIfAbsent( + EndPointInfo, () => EndPointInfo.fromJsonFactory); + + return _systemEndpointGet(); + } + + ///Gets information about the request endpoint. + @Get(path: '/System/Endpoint') + Future> _systemEndpointGet(); + + ///Gets information about the server. + Future> systemInfoGet() { + generatedMapping.putIfAbsent(SystemInfo, () => SystemInfo.fromJsonFactory); + + return _systemInfoGet(); + } + + ///Gets information about the server. + @Get(path: '/System/Info') + Future> _systemInfoGet(); + + ///Gets public information about the server. + Future> systemInfoPublicGet() { + generatedMapping.putIfAbsent( + PublicSystemInfo, () => PublicSystemInfo.fromJsonFactory); + + return _systemInfoPublicGet(); + } + + ///Gets public information about the server. + @Get(path: '/System/Info/Public') + Future> _systemInfoPublicGet(); + + ///Gets a list of available server log files. + Future>> systemLogsGet() { + generatedMapping.putIfAbsent(LogFile, () => LogFile.fromJsonFactory); + + return _systemLogsGet(); + } + + ///Gets a list of available server log files. + @Get(path: '/System/Logs') + Future>> _systemLogsGet(); + + ///Gets a log file. + ///@param name The name of the log file to get. + Future> systemLogsLogGet({required String? name}) { + return _systemLogsLogGet(name: name); + } + + ///Gets a log file. + ///@param name The name of the log file to get. + @Get(path: '/System/Logs/Log') + Future> _systemLogsLogGet( + {@Query('name') required String? name}); + + ///Pings the system. + Future> systemPingGet() { + return _systemPingGet(); + } + + ///Pings the system. + @Get(path: '/System/Ping') + Future> _systemPingGet(); + + ///Pings the system. + Future> systemPingPost() { + return _systemPingPost(); + } + + ///Pings the system. + @Post( + path: '/System/Ping', + optionalBody: true, + ) + Future> _systemPingPost(); + + ///Restarts the application. + Future systemRestartPost() { + return _systemRestartPost(); + } + + ///Restarts the application. + @Post( + path: '/System/Restart', + optionalBody: true, + ) + Future _systemRestartPost(); + + ///Shuts down the application. + Future systemShutdownPost() { + return _systemShutdownPost(); + } + + ///Shuts down the application. + @Post( + path: '/System/Shutdown', + optionalBody: true, + ) + Future _systemShutdownPost(); + + ///Gets wake on lan information. + @deprecated + Future>> systemWakeOnLanInfoGet() { + generatedMapping.putIfAbsent( + WakeOnLanInfo, () => WakeOnLanInfo.fromJsonFactory); + + return _systemWakeOnLanInfoGet(); + } + + ///Gets wake on lan information. + @deprecated + @Get(path: '/System/WakeOnLanInfo') + Future>> _systemWakeOnLanInfoGet(); + + ///Gets the current UTC time. + Future> getUtcTimeGet() { + generatedMapping.putIfAbsent( + UtcTimeResponse, () => UtcTimeResponse.fromJsonFactory); + + return _getUtcTimeGet(); + } + + ///Gets the current UTC time. + @Get(path: '/GetUtcTime') + Future> _getUtcTimeGet(); + + ///Gets the TMDb image configuration options. + Future> tmdbClientConfigurationGet() { + generatedMapping.putIfAbsent( + ConfigImageTypes, () => ConfigImageTypes.fromJsonFactory); + + return _tmdbClientConfigurationGet(); + } + + ///Gets the TMDb image configuration options. + @Get(path: '/Tmdb/ClientConfiguration') + Future> _tmdbClientConfigurationGet(); + + /// + Future tMDbBoxSetsRefreshPost() { + return _tMDbBoxSetsRefreshPost(); + } + + /// + @Post( + path: '/TMDbBoxSets/Refresh', + optionalBody: true, + ) + Future _tMDbBoxSetsRefreshPost(); + + ///Finds movies and trailers similar to a given trailer. + ///@param userId The user id supplied as query parameter; this is required when not using an API key. + ///@param maxOfficialRating Optional filter by maximum official rating (PG, PG-13, TV-MA, etc). + ///@param hasThemeSong Optional filter by items with theme songs. + ///@param hasThemeVideo Optional filter by items with theme videos. + ///@param hasSubtitles Optional filter by items with subtitles. + ///@param hasSpecialFeature Optional filter by items with special features. + ///@param hasTrailer Optional filter by items with trailers. + ///@param adjacentTo Optional. Return items that are siblings of a supplied item. + ///@param parentIndexNumber Optional filter by parent index number. + ///@param hasParentalRating Optional filter by items that have or do not have a parental rating. + ///@param isHd Optional filter by items that are HD or not. + ///@param is4K Optional filter by items that are 4K or not. + ///@param locationTypes Optional. If specified, results will be filtered based on LocationType. This allows multiple, comma delimited. + ///@param excludeLocationTypes Optional. If specified, results will be filtered based on the LocationType. This allows multiple, comma delimited. + ///@param isMissing Optional filter by items that are missing episodes or not. + ///@param isUnaired Optional filter by items that are unaired episodes or not. + ///@param minCommunityRating Optional filter by minimum community rating. + ///@param minCriticRating Optional filter by minimum critic rating. + ///@param minPremiereDate Optional. The minimum premiere date. Format = ISO. + ///@param minDateLastSaved Optional. The minimum last saved date. Format = ISO. + ///@param minDateLastSavedForUser Optional. The minimum last saved date for the current user. Format = ISO. + ///@param maxPremiereDate Optional. The maximum premiere date. Format = ISO. + ///@param hasOverview Optional filter by items that have an overview or not. + ///@param hasImdbId Optional filter by items that have an IMDb id or not. + ///@param hasTmdbId Optional filter by items that have a TMDb id or not. + ///@param hasTvdbId Optional filter by items that have a TVDb id or not. + ///@param isMovie Optional filter for live tv movies. + ///@param isSeries Optional filter for live tv series. + ///@param isNews Optional filter for live tv news. + ///@param isKids Optional filter for live tv kids. + ///@param isSports Optional filter for live tv sports. + ///@param excludeItemIds Optional. If specified, results will be filtered by excluding item ids. This allows multiple, comma delimited. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param recursive When searching within folders, this determines whether or not the search will be recursive. true/false. + ///@param searchTerm Optional. Filter based on a search term. + ///@param sortOrder Sort Order - Ascending, Descending. + ///@param parentId Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param fields Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines. + ///@param excludeItemTypes Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited. + ///@param filters Optional. Specify additional filters to apply. This allows multiple, comma delimited. Options: IsFolder, IsNotFolder, IsUnplayed, IsPlayed, IsFavorite, IsResumable, Likes, Dislikes. + ///@param isFavorite Optional filter by items that are marked as favorite, or not. + ///@param mediaTypes Optional filter by MediaType. Allows multiple, comma delimited. + ///@param imageTypes Optional. If specified, results will be filtered based on those containing image types. This allows multiple, comma delimited. + ///@param sortBy Optional. Specify one or more sort orders, comma delimited. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime. + ///@param isPlayed Optional filter by items that are played, or not. + ///@param genres Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimited. + ///@param officialRatings Optional. If specified, results will be filtered based on OfficialRating. This allows multiple, pipe delimited. + ///@param tags Optional. If specified, results will be filtered based on tag. This allows multiple, pipe delimited. + ///@param years Optional. If specified, results will be filtered based on production year. This allows multiple, comma delimited. + ///@param enableUserData Optional, include user data. + ///@param imageTypeLimit Optional, the max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param person Optional. If specified, results will be filtered to include only those containing the specified person. + ///@param personIds Optional. If specified, results will be filtered to include only those containing the specified person id. + ///@param personTypes Optional. If specified, along with Person, results will be filtered to include only those containing the specified person and PersonType. Allows multiple, comma-delimited. + ///@param studios Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimited. + ///@param artists Optional. If specified, results will be filtered based on artists. This allows multiple, pipe delimited. + ///@param excludeArtistIds Optional. If specified, results will be filtered based on artist id. This allows multiple, pipe delimited. + ///@param artistIds Optional. If specified, results will be filtered to include only those containing the specified artist id. + ///@param albumArtistIds Optional. If specified, results will be filtered to include only those containing the specified album artist id. + ///@param contributingArtistIds Optional. If specified, results will be filtered to include only those containing the specified contributing artist id. + ///@param albums Optional. If specified, results will be filtered based on album. This allows multiple, pipe delimited. + ///@param albumIds Optional. If specified, results will be filtered based on album id. This allows multiple, pipe delimited. + ///@param ids Optional. If specific items are needed, specify a list of item id's to retrieve. This allows multiple, comma delimited. + ///@param videoTypes Optional filter by VideoType (videofile, dvd, bluray, iso). Allows multiple, comma delimited. + ///@param minOfficialRating Optional filter by minimum official rating (PG, PG-13, TV-MA, etc). + ///@param isLocked Optional filter by items that are locked. + ///@param isPlaceHolder Optional filter by items that are placeholders. + ///@param hasOfficialRating Optional filter by items that have official ratings. + ///@param collapseBoxSetItems Whether or not to hide items behind their boxsets. + ///@param minWidth Optional. Filter by the minimum width of the item. + ///@param minHeight Optional. Filter by the minimum height of the item. + ///@param maxWidth Optional. Filter by the maximum width of the item. + ///@param maxHeight Optional. Filter by the maximum height of the item. + ///@param is3D Optional filter by items that are 3D, or not. + ///@param seriesStatus Optional filter by Series Status. Allows multiple, comma delimited. + ///@param nameStartsWithOrGreater Optional filter by items whose name is sorted equally or greater than a given input string. + ///@param nameStartsWith Optional filter by items whose name is sorted equally than a given input string. + ///@param nameLessThan Optional filter by items whose name is equally or lesser than a given input string. + ///@param studioIds Optional. If specified, results will be filtered based on studio id. This allows multiple, pipe delimited. + ///@param genreIds Optional. If specified, results will be filtered based on genre id. This allows multiple, pipe delimited. + ///@param enableTotalRecordCount Optional. Enable the total record count. + ///@param enableImages Optional, include image information in output. + Future> trailersGet({ + String? userId, + String? maxOfficialRating, + bool? hasThemeSong, + bool? hasThemeVideo, + bool? hasSubtitles, + bool? hasSpecialFeature, + bool? hasTrailer, + String? adjacentTo, + int? parentIndexNumber, + bool? hasParentalRating, + bool? isHd, + bool? is4K, + List? locationTypes, + List? excludeLocationTypes, + bool? isMissing, + bool? isUnaired, + num? minCommunityRating, + num? minCriticRating, + DateTime? minPremiereDate, + DateTime? minDateLastSaved, + DateTime? minDateLastSavedForUser, + DateTime? maxPremiereDate, + bool? hasOverview, + bool? hasImdbId, + bool? hasTmdbId, + bool? hasTvdbId, + bool? isMovie, + bool? isSeries, + bool? isNews, + bool? isKids, + bool? isSports, + List? excludeItemIds, + int? startIndex, + int? limit, + bool? recursive, + String? searchTerm, + List? sortOrder, + String? parentId, + List? fields, + List? excludeItemTypes, + List? filters, + bool? isFavorite, + List? mediaTypes, + List? imageTypes, + List? sortBy, + bool? isPlayed, + List? genres, + List? officialRatings, + List? tags, + List? years, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + String? person, + List? personIds, + List? personTypes, + List? studios, + List? artists, + List? excludeArtistIds, + List? artistIds, + List? albumArtistIds, + List? contributingArtistIds, + List? albums, + List? albumIds, + List? ids, + List? videoTypes, + String? minOfficialRating, + bool? isLocked, + bool? isPlaceHolder, + bool? hasOfficialRating, + bool? collapseBoxSetItems, + int? minWidth, + int? minHeight, + int? maxWidth, + int? maxHeight, + bool? is3D, + List? seriesStatus, + String? nameStartsWithOrGreater, + String? nameStartsWith, + String? nameLessThan, + List? studioIds, + List? genreIds, + bool? enableTotalRecordCount, + bool? enableImages, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _trailersGet( + userId: userId, + maxOfficialRating: maxOfficialRating, + hasThemeSong: hasThemeSong, + hasThemeVideo: hasThemeVideo, + hasSubtitles: hasSubtitles, + hasSpecialFeature: hasSpecialFeature, + hasTrailer: hasTrailer, + adjacentTo: adjacentTo, + parentIndexNumber: parentIndexNumber, + hasParentalRating: hasParentalRating, + isHd: isHd, + is4K: is4K, + locationTypes: locationTypeListToJson(locationTypes), + excludeLocationTypes: locationTypeListToJson(excludeLocationTypes), + isMissing: isMissing, + isUnaired: isUnaired, + minCommunityRating: minCommunityRating, + minCriticRating: minCriticRating, + minPremiereDate: minPremiereDate, + minDateLastSaved: minDateLastSaved, + minDateLastSavedForUser: minDateLastSavedForUser, + maxPremiereDate: maxPremiereDate, + hasOverview: hasOverview, + hasImdbId: hasImdbId, + hasTmdbId: hasTmdbId, + hasTvdbId: hasTvdbId, + isMovie: isMovie, + isSeries: isSeries, + isNews: isNews, + isKids: isKids, + isSports: isSports, + excludeItemIds: excludeItemIds, + startIndex: startIndex, + limit: limit, + recursive: recursive, + searchTerm: searchTerm, + sortOrder: sortOrderListToJson(sortOrder), + parentId: parentId, + fields: itemFieldsListToJson(fields), + excludeItemTypes: baseItemKindListToJson(excludeItemTypes), + filters: itemFilterListToJson(filters), + isFavorite: isFavorite, + mediaTypes: mediaTypeListToJson(mediaTypes), + imageTypes: imageTypeListToJson(imageTypes), + sortBy: itemSortByListToJson(sortBy), + isPlayed: isPlayed, + genres: genres, + officialRatings: officialRatings, + tags: tags, + years: years, + enableUserData: enableUserData, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes), + person: person, + personIds: personIds, + personTypes: personTypes, + studios: studios, + artists: artists, + excludeArtistIds: excludeArtistIds, + artistIds: artistIds, + albumArtistIds: albumArtistIds, + contributingArtistIds: contributingArtistIds, + albums: albums, + albumIds: albumIds, + ids: ids, + videoTypes: videoTypeListToJson(videoTypes), + minOfficialRating: minOfficialRating, + isLocked: isLocked, + isPlaceHolder: isPlaceHolder, + hasOfficialRating: hasOfficialRating, + collapseBoxSetItems: collapseBoxSetItems, + minWidth: minWidth, + minHeight: minHeight, + maxWidth: maxWidth, + maxHeight: maxHeight, + is3D: is3D, + seriesStatus: seriesStatusListToJson(seriesStatus), + nameStartsWithOrGreater: nameStartsWithOrGreater, + nameStartsWith: nameStartsWith, + nameLessThan: nameLessThan, + studioIds: studioIds, + genreIds: genreIds, + enableTotalRecordCount: enableTotalRecordCount, + enableImages: enableImages); + } + + ///Finds movies and trailers similar to a given trailer. + ///@param userId The user id supplied as query parameter; this is required when not using an API key. + ///@param maxOfficialRating Optional filter by maximum official rating (PG, PG-13, TV-MA, etc). + ///@param hasThemeSong Optional filter by items with theme songs. + ///@param hasThemeVideo Optional filter by items with theme videos. + ///@param hasSubtitles Optional filter by items with subtitles. + ///@param hasSpecialFeature Optional filter by items with special features. + ///@param hasTrailer Optional filter by items with trailers. + ///@param adjacentTo Optional. Return items that are siblings of a supplied item. + ///@param parentIndexNumber Optional filter by parent index number. + ///@param hasParentalRating Optional filter by items that have or do not have a parental rating. + ///@param isHd Optional filter by items that are HD or not. + ///@param is4K Optional filter by items that are 4K or not. + ///@param locationTypes Optional. If specified, results will be filtered based on LocationType. This allows multiple, comma delimited. + ///@param excludeLocationTypes Optional. If specified, results will be filtered based on the LocationType. This allows multiple, comma delimited. + ///@param isMissing Optional filter by items that are missing episodes or not. + ///@param isUnaired Optional filter by items that are unaired episodes or not. + ///@param minCommunityRating Optional filter by minimum community rating. + ///@param minCriticRating Optional filter by minimum critic rating. + ///@param minPremiereDate Optional. The minimum premiere date. Format = ISO. + ///@param minDateLastSaved Optional. The minimum last saved date. Format = ISO. + ///@param minDateLastSavedForUser Optional. The minimum last saved date for the current user. Format = ISO. + ///@param maxPremiereDate Optional. The maximum premiere date. Format = ISO. + ///@param hasOverview Optional filter by items that have an overview or not. + ///@param hasImdbId Optional filter by items that have an IMDb id or not. + ///@param hasTmdbId Optional filter by items that have a TMDb id or not. + ///@param hasTvdbId Optional filter by items that have a TVDb id or not. + ///@param isMovie Optional filter for live tv movies. + ///@param isSeries Optional filter for live tv series. + ///@param isNews Optional filter for live tv news. + ///@param isKids Optional filter for live tv kids. + ///@param isSports Optional filter for live tv sports. + ///@param excludeItemIds Optional. If specified, results will be filtered by excluding item ids. This allows multiple, comma delimited. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param recursive When searching within folders, this determines whether or not the search will be recursive. true/false. + ///@param searchTerm Optional. Filter based on a search term. + ///@param sortOrder Sort Order - Ascending, Descending. + ///@param parentId Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param fields Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines. + ///@param excludeItemTypes Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited. + ///@param filters Optional. Specify additional filters to apply. This allows multiple, comma delimited. Options: IsFolder, IsNotFolder, IsUnplayed, IsPlayed, IsFavorite, IsResumable, Likes, Dislikes. + ///@param isFavorite Optional filter by items that are marked as favorite, or not. + ///@param mediaTypes Optional filter by MediaType. Allows multiple, comma delimited. + ///@param imageTypes Optional. If specified, results will be filtered based on those containing image types. This allows multiple, comma delimited. + ///@param sortBy Optional. Specify one or more sort orders, comma delimited. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime. + ///@param isPlayed Optional filter by items that are played, or not. + ///@param genres Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimited. + ///@param officialRatings Optional. If specified, results will be filtered based on OfficialRating. This allows multiple, pipe delimited. + ///@param tags Optional. If specified, results will be filtered based on tag. This allows multiple, pipe delimited. + ///@param years Optional. If specified, results will be filtered based on production year. This allows multiple, comma delimited. + ///@param enableUserData Optional, include user data. + ///@param imageTypeLimit Optional, the max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param person Optional. If specified, results will be filtered to include only those containing the specified person. + ///@param personIds Optional. If specified, results will be filtered to include only those containing the specified person id. + ///@param personTypes Optional. If specified, along with Person, results will be filtered to include only those containing the specified person and PersonType. Allows multiple, comma-delimited. + ///@param studios Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimited. + ///@param artists Optional. If specified, results will be filtered based on artists. This allows multiple, pipe delimited. + ///@param excludeArtistIds Optional. If specified, results will be filtered based on artist id. This allows multiple, pipe delimited. + ///@param artistIds Optional. If specified, results will be filtered to include only those containing the specified artist id. + ///@param albumArtistIds Optional. If specified, results will be filtered to include only those containing the specified album artist id. + ///@param contributingArtistIds Optional. If specified, results will be filtered to include only those containing the specified contributing artist id. + ///@param albums Optional. If specified, results will be filtered based on album. This allows multiple, pipe delimited. + ///@param albumIds Optional. If specified, results will be filtered based on album id. This allows multiple, pipe delimited. + ///@param ids Optional. If specific items are needed, specify a list of item id's to retrieve. This allows multiple, comma delimited. + ///@param videoTypes Optional filter by VideoType (videofile, dvd, bluray, iso). Allows multiple, comma delimited. + ///@param minOfficialRating Optional filter by minimum official rating (PG, PG-13, TV-MA, etc). + ///@param isLocked Optional filter by items that are locked. + ///@param isPlaceHolder Optional filter by items that are placeholders. + ///@param hasOfficialRating Optional filter by items that have official ratings. + ///@param collapseBoxSetItems Whether or not to hide items behind their boxsets. + ///@param minWidth Optional. Filter by the minimum width of the item. + ///@param minHeight Optional. Filter by the minimum height of the item. + ///@param maxWidth Optional. Filter by the maximum width of the item. + ///@param maxHeight Optional. Filter by the maximum height of the item. + ///@param is3D Optional filter by items that are 3D, or not. + ///@param seriesStatus Optional filter by Series Status. Allows multiple, comma delimited. + ///@param nameStartsWithOrGreater Optional filter by items whose name is sorted equally or greater than a given input string. + ///@param nameStartsWith Optional filter by items whose name is sorted equally than a given input string. + ///@param nameLessThan Optional filter by items whose name is equally or lesser than a given input string. + ///@param studioIds Optional. If specified, results will be filtered based on studio id. This allows multiple, pipe delimited. + ///@param genreIds Optional. If specified, results will be filtered based on genre id. This allows multiple, pipe delimited. + ///@param enableTotalRecordCount Optional. Enable the total record count. + ///@param enableImages Optional, include image information in output. + @Get(path: '/Trailers') + Future> _trailersGet({ + @Query('userId') String? userId, + @Query('maxOfficialRating') String? maxOfficialRating, + @Query('hasThemeSong') bool? hasThemeSong, + @Query('hasThemeVideo') bool? hasThemeVideo, + @Query('hasSubtitles') bool? hasSubtitles, + @Query('hasSpecialFeature') bool? hasSpecialFeature, + @Query('hasTrailer') bool? hasTrailer, + @Query('adjacentTo') String? adjacentTo, + @Query('parentIndexNumber') int? parentIndexNumber, + @Query('hasParentalRating') bool? hasParentalRating, + @Query('isHd') bool? isHd, + @Query('is4K') bool? is4K, + @Query('locationTypes') List? locationTypes, + @Query('excludeLocationTypes') List? excludeLocationTypes, + @Query('isMissing') bool? isMissing, + @Query('isUnaired') bool? isUnaired, + @Query('minCommunityRating') num? minCommunityRating, + @Query('minCriticRating') num? minCriticRating, + @Query('minPremiereDate') DateTime? minPremiereDate, + @Query('minDateLastSaved') DateTime? minDateLastSaved, + @Query('minDateLastSavedForUser') DateTime? minDateLastSavedForUser, + @Query('maxPremiereDate') DateTime? maxPremiereDate, + @Query('hasOverview') bool? hasOverview, + @Query('hasImdbId') bool? hasImdbId, + @Query('hasTmdbId') bool? hasTmdbId, + @Query('hasTvdbId') bool? hasTvdbId, + @Query('isMovie') bool? isMovie, + @Query('isSeries') bool? isSeries, + @Query('isNews') bool? isNews, + @Query('isKids') bool? isKids, + @Query('isSports') bool? isSports, + @Query('excludeItemIds') List? excludeItemIds, + @Query('startIndex') int? startIndex, + @Query('limit') int? limit, + @Query('recursive') bool? recursive, + @Query('searchTerm') String? searchTerm, + @Query('sortOrder') List? sortOrder, + @Query('parentId') String? parentId, + @Query('fields') List? fields, + @Query('excludeItemTypes') List? excludeItemTypes, + @Query('filters') List? filters, + @Query('isFavorite') bool? isFavorite, + @Query('mediaTypes') List? mediaTypes, + @Query('imageTypes') List? imageTypes, + @Query('sortBy') List? sortBy, + @Query('isPlayed') bool? isPlayed, + @Query('genres') List? genres, + @Query('officialRatings') List? officialRatings, + @Query('tags') List? tags, + @Query('years') List? years, + @Query('enableUserData') bool? enableUserData, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + @Query('person') String? person, + @Query('personIds') List? personIds, + @Query('personTypes') List? personTypes, + @Query('studios') List? studios, + @Query('artists') List? artists, + @Query('excludeArtistIds') List? excludeArtistIds, + @Query('artistIds') List? artistIds, + @Query('albumArtistIds') List? albumArtistIds, + @Query('contributingArtistIds') List? contributingArtistIds, + @Query('albums') List? albums, + @Query('albumIds') List? albumIds, + @Query('ids') List? ids, + @Query('videoTypes') List? videoTypes, + @Query('minOfficialRating') String? minOfficialRating, + @Query('isLocked') bool? isLocked, + @Query('isPlaceHolder') bool? isPlaceHolder, + @Query('hasOfficialRating') bool? hasOfficialRating, + @Query('collapseBoxSetItems') bool? collapseBoxSetItems, + @Query('minWidth') int? minWidth, + @Query('minHeight') int? minHeight, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('is3D') bool? is3D, + @Query('seriesStatus') List? seriesStatus, + @Query('nameStartsWithOrGreater') String? nameStartsWithOrGreater, + @Query('nameStartsWith') String? nameStartsWith, + @Query('nameLessThan') String? nameLessThan, + @Query('studioIds') List? studioIds, + @Query('genreIds') List? genreIds, + @Query('enableTotalRecordCount') bool? enableTotalRecordCount, + @Query('enableImages') bool? enableImages, + }); + + /// + ///@param userGuid + Future traktUsersUserGuidAuthorizePost( + {required String? userGuid}) { + return _traktUsersUserGuidAuthorizePost(userGuid: userGuid); + } + + /// + ///@param userGuid + @Post( + path: '/Trakt/Users/{userGuid}/Authorize', + optionalBody: true, + ) + Future _traktUsersUserGuidAuthorizePost( + {@Path('userGuid') required String? userGuid}); + + /// + ///@param userGuid + Future> traktUsersUserGuidDeauthorizePost( + {required String? userGuid}) { + return _traktUsersUserGuidDeauthorizePost(userGuid: userGuid); + } + + /// + ///@param userGuid + @Post( + path: '/Trakt/Users/{userGuid}/Deauthorize', + optionalBody: true, + ) + Future> _traktUsersUserGuidDeauthorizePost( + {@Path('userGuid') required String? userGuid}); + + /// + ///@param userGuid + ///@param itemId + ///@param rating + Future> + traktUsersUserGuidItemsItemIdRatePost({ + required String? userGuid, + required String? itemId, + int? rating, + }) { + generatedMapping.putIfAbsent( + TraktSyncResponse, () => TraktSyncResponse.fromJsonFactory); + + return _traktUsersUserGuidItemsItemIdRatePost( + userGuid: userGuid, itemId: itemId, rating: rating); + } + + /// + ///@param userGuid + ///@param itemId + ///@param rating + @Post( + path: '/Trakt/Users/{userGuid}/Items/{itemId}/Rate', + optionalBody: true, + ) + Future> + _traktUsersUserGuidItemsItemIdRatePost({ + @Path('userGuid') required String? userGuid, + @Path('itemId') required String? itemId, + @Query('rating') int? rating, + }); + + /// + ///@param userGuid + Future traktUsersUserGuidPollAuthorizationStatusGet( + {required String? userGuid}) { + return _traktUsersUserGuidPollAuthorizationStatusGet(userGuid: userGuid); + } + + /// + ///@param userGuid + @Get(path: '/Trakt/Users/{userGuid}/PollAuthorizationStatus') + Future _traktUsersUserGuidPollAuthorizationStatusGet( + {@Path('userGuid') required String? userGuid}); + + /// + ///@param userGuid + Future>> + traktUsersUserGuidRecommendedMoviesPost({required String? userGuid}) { + generatedMapping.putIfAbsent(TraktMovie, () => TraktMovie.fromJsonFactory); + + return _traktUsersUserGuidRecommendedMoviesPost(userGuid: userGuid); + } + + /// + ///@param userGuid + @Post( + path: '/Trakt/Users/{userGuid}/RecommendedMovies', + optionalBody: true, + ) + Future>> + _traktUsersUserGuidRecommendedMoviesPost( + {@Path('userGuid') required String? userGuid}); + + /// + ///@param userGuid + Future>> + traktUsersUserGuidRecommendedShowsPost({required String? userGuid}) { + generatedMapping.putIfAbsent(TraktShow, () => TraktShow.fromJsonFactory); + + return _traktUsersUserGuidRecommendedShowsPost(userGuid: userGuid); + } + + /// + ///@param userGuid + @Post( + path: '/Trakt/Users/{userGuid}/RecommendedShows', + optionalBody: true, + ) + Future>> + _traktUsersUserGuidRecommendedShowsPost( + {@Path('userGuid') required String? userGuid}); + + ///Gets a trickplay tile image. + ///@param itemId The item id. + ///@param width The width of a single tile. + ///@param index The index of the desired tile. + ///@param mediaSourceId The media version id, if using an alternate version. + Future> videosItemIdTrickplayWidthIndexJpgGet({ + required String? itemId, + required int? width, + required int? index, + String? mediaSourceId, + }) { + return _videosItemIdTrickplayWidthIndexJpgGet( + itemId: itemId, + width: width, + index: index, + mediaSourceId: mediaSourceId); + } + + ///Gets a trickplay tile image. + ///@param itemId The item id. + ///@param width The width of a single tile. + ///@param index The index of the desired tile. + ///@param mediaSourceId The media version id, if using an alternate version. + @Get(path: '/Videos/{itemId}/Trickplay/{width}/{index}.jpg') + Future> _videosItemIdTrickplayWidthIndexJpgGet({ + @Path('itemId') required String? itemId, + @Path('width') required int? width, + @Path('index') required int? index, + @Query('mediaSourceId') String? mediaSourceId, + }); + + ///Gets an image tiles playlist for trickplay. + ///@param itemId The item id. + ///@param width The width of a single tile. + ///@param mediaSourceId The media version id, if using an alternate version. + Future> videosItemIdTrickplayWidthTilesM3u8Get({ + required String? itemId, + required int? width, + String? mediaSourceId, + }) { + return _videosItemIdTrickplayWidthTilesM3u8Get( + itemId: itemId, width: width, mediaSourceId: mediaSourceId); + } + + ///Gets an image tiles playlist for trickplay. + ///@param itemId The item id. + ///@param width The width of a single tile. + ///@param mediaSourceId The media version id, if using an alternate version. + @Get(path: '/Videos/{itemId}/Trickplay/{width}/tiles.m3u8') + Future> _videosItemIdTrickplayWidthTilesM3u8Get({ + @Path('itemId') required String? itemId, + @Path('width') required int? width, + @Query('mediaSourceId') String? mediaSourceId, + }); + + /// + Future> introSkipperSupportBundleGet() { + return _introSkipperSupportBundleGet(); + } + + /// + @Get(path: '/IntroSkipper/SupportBundle') + Future> _introSkipperSupportBundleGet(); + + ///Gets episodes for a tv season. + ///@param seriesId The series id. + ///@param userId The user id. + ///@param fields Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls. + ///@param season Optional filter by season number. + ///@param seasonId Optional. Filter by season id. + ///@param isMissing Optional. Filter by items that are missing episodes or not. + ///@param adjacentTo Optional. Return items that are siblings of a supplied item. + ///@param startItemId Optional. Skip through the list until a given item is found. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param enableImages Optional, include image information in output. + ///@param imageTypeLimit Optional, the max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param enableUserData Optional. Include user data. + ///@param sortBy Optional. Specify one or more sort orders, comma delimited. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime. + Future> showsSeriesIdEpisodesGet({ + required String? seriesId, + String? userId, + List? fields, + int? season, + String? seasonId, + bool? isMissing, + String? adjacentTo, + String? startItemId, + int? startIndex, + int? limit, + bool? enableImages, + int? imageTypeLimit, + List? enableImageTypes, + bool? enableUserData, + enums.ShowsSeriesIdEpisodesGetSortBy? sortBy, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _showsSeriesIdEpisodesGet( + seriesId: seriesId, + userId: userId, + fields: itemFieldsListToJson(fields), + season: season, + seasonId: seasonId, + isMissing: isMissing, + adjacentTo: adjacentTo, + startItemId: startItemId, + startIndex: startIndex, + limit: limit, + enableImages: enableImages, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes), + enableUserData: enableUserData, + sortBy: sortBy?.value?.toString()); + } + + ///Gets episodes for a tv season. + ///@param seriesId The series id. + ///@param userId The user id. + ///@param fields Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls. + ///@param season Optional filter by season number. + ///@param seasonId Optional. Filter by season id. + ///@param isMissing Optional. Filter by items that are missing episodes or not. + ///@param adjacentTo Optional. Return items that are siblings of a supplied item. + ///@param startItemId Optional. Skip through the list until a given item is found. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param enableImages Optional, include image information in output. + ///@param imageTypeLimit Optional, the max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param enableUserData Optional. Include user data. + ///@param sortBy Optional. Specify one or more sort orders, comma delimited. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime. + @Get(path: '/Shows/{seriesId}/Episodes') + Future> _showsSeriesIdEpisodesGet({ + @Path('seriesId') required String? seriesId, + @Query('userId') String? userId, + @Query('fields') List? fields, + @Query('season') int? season, + @Query('seasonId') String? seasonId, + @Query('isMissing') bool? isMissing, + @Query('adjacentTo') String? adjacentTo, + @Query('startItemId') String? startItemId, + @Query('startIndex') int? startIndex, + @Query('limit') int? limit, + @Query('enableImages') bool? enableImages, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + @Query('enableUserData') bool? enableUserData, + @Query('sortBy') String? sortBy, + }); + + ///Gets seasons for a tv series. + ///@param seriesId The series id. + ///@param userId The user id. + ///@param fields Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls. + ///@param isSpecialSeason Optional. Filter by special season. + ///@param isMissing Optional. Filter by items that are missing episodes or not. + ///@param adjacentTo Optional. Return items that are siblings of a supplied item. + ///@param enableImages Optional. Include image information in output. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param enableUserData Optional. Include user data. + Future> showsSeriesIdSeasonsGet({ + required String? seriesId, + String? userId, + List? fields, + bool? isSpecialSeason, + bool? isMissing, + String? adjacentTo, + bool? enableImages, + int? imageTypeLimit, + List? enableImageTypes, + bool? enableUserData, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _showsSeriesIdSeasonsGet( + seriesId: seriesId, + userId: userId, + fields: itemFieldsListToJson(fields), + isSpecialSeason: isSpecialSeason, + isMissing: isMissing, + adjacentTo: adjacentTo, + enableImages: enableImages, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes), + enableUserData: enableUserData); + } + + ///Gets seasons for a tv series. + ///@param seriesId The series id. + ///@param userId The user id. + ///@param fields Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls. + ///@param isSpecialSeason Optional. Filter by special season. + ///@param isMissing Optional. Filter by items that are missing episodes or not. + ///@param adjacentTo Optional. Return items that are siblings of a supplied item. + ///@param enableImages Optional. Include image information in output. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param enableUserData Optional. Include user data. + @Get(path: '/Shows/{seriesId}/Seasons') + Future> _showsSeriesIdSeasonsGet({ + @Path('seriesId') required String? seriesId, + @Query('userId') String? userId, + @Query('fields') List? fields, + @Query('isSpecialSeason') bool? isSpecialSeason, + @Query('isMissing') bool? isMissing, + @Query('adjacentTo') String? adjacentTo, + @Query('enableImages') bool? enableImages, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + @Query('enableUserData') bool? enableUserData, + }); + + ///Gets a list of next up episodes. + ///@param userId The user id of the user to get the next up episodes for. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param seriesId Optional. Filter by series id. + ///@param parentId Optional. Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param enableImages Optional. Include image information in output. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param enableUserData Optional. Include user data. + ///@param nextUpDateCutoff Optional. Starting date of shows to show in Next Up section. + ///@param enableTotalRecordCount Whether to enable the total records count. Defaults to true. + ///@param disableFirstEpisode Whether to disable sending the first episode in a series as next up. + ///@param enableResumable Whether to include resumable episodes in next up results. + ///@param enableRewatching Whether to include watched episodes in next up results. + Future> showsNextUpGet({ + String? userId, + int? startIndex, + int? limit, + List? fields, + String? seriesId, + String? parentId, + bool? enableImages, + int? imageTypeLimit, + List? enableImageTypes, + bool? enableUserData, + DateTime? nextUpDateCutoff, + bool? enableTotalRecordCount, + bool? disableFirstEpisode, + bool? enableResumable, + bool? enableRewatching, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _showsNextUpGet( + userId: userId, + startIndex: startIndex, + limit: limit, + fields: itemFieldsListToJson(fields), + seriesId: seriesId, + parentId: parentId, + enableImages: enableImages, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes), + enableUserData: enableUserData, + nextUpDateCutoff: nextUpDateCutoff, + enableTotalRecordCount: enableTotalRecordCount, + disableFirstEpisode: disableFirstEpisode, + enableResumable: enableResumable, + enableRewatching: enableRewatching); + } + + ///Gets a list of next up episodes. + ///@param userId The user id of the user to get the next up episodes for. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param seriesId Optional. Filter by series id. + ///@param parentId Optional. Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param enableImages Optional. Include image information in output. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param enableUserData Optional. Include user data. + ///@param nextUpDateCutoff Optional. Starting date of shows to show in Next Up section. + ///@param enableTotalRecordCount Whether to enable the total records count. Defaults to true. + ///@param disableFirstEpisode Whether to disable sending the first episode in a series as next up. + ///@param enableResumable Whether to include resumable episodes in next up results. + ///@param enableRewatching Whether to include watched episodes in next up results. + @Get(path: '/Shows/NextUp') + Future> _showsNextUpGet({ + @Query('userId') String? userId, + @Query('startIndex') int? startIndex, + @Query('limit') int? limit, + @Query('fields') List? fields, + @Query('seriesId') String? seriesId, + @Query('parentId') String? parentId, + @Query('enableImages') bool? enableImages, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + @Query('enableUserData') bool? enableUserData, + @Query('nextUpDateCutoff') DateTime? nextUpDateCutoff, + @Query('enableTotalRecordCount') bool? enableTotalRecordCount, + @Query('disableFirstEpisode') bool? disableFirstEpisode, + @Query('enableResumable') bool? enableResumable, + @Query('enableRewatching') bool? enableRewatching, + }); + + ///Gets a list of upcoming episodes. + ///@param userId The user id of the user to get the upcoming episodes for. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param parentId Optional. Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param enableImages Optional. Include image information in output. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param enableUserData Optional. Include user data. + Future> showsUpcomingGet({ + String? userId, + int? startIndex, + int? limit, + List? fields, + String? parentId, + bool? enableImages, + int? imageTypeLimit, + List? enableImageTypes, + bool? enableUserData, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _showsUpcomingGet( + userId: userId, + startIndex: startIndex, + limit: limit, + fields: itemFieldsListToJson(fields), + parentId: parentId, + enableImages: enableImages, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes), + enableUserData: enableUserData); + } + + ///Gets a list of upcoming episodes. + ///@param userId The user id of the user to get the upcoming episodes for. + ///@param startIndex Optional. The record index to start at. All items with a lower index will be dropped from the results. + ///@param limit Optional. The maximum number of records to return. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param parentId Optional. Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param enableImages Optional. Include image information in output. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param enableUserData Optional. Include user data. + @Get(path: '/Shows/Upcoming') + Future> _showsUpcomingGet({ + @Query('userId') String? userId, + @Query('startIndex') int? startIndex, + @Query('limit') int? limit, + @Query('fields') List? fields, + @Query('parentId') String? parentId, + @Query('enableImages') bool? enableImages, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + @Query('enableUserData') bool? enableUserData, + }); + + ///Gets an audio stream. + ///@param itemId The item id. + ///@param container Optional. The audio container. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param userId Optional. The user id. + ///@param audioCodec Optional. The audio codec to transcode to. + ///@param maxAudioChannels Optional. The maximum number of audio channels. + ///@param transcodingAudioChannels Optional. The number of how many audio channels to transcode to. + ///@param maxStreamingBitrate Optional. The maximum streaming bitrate. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param transcodingContainer Optional. The container to transcode to. + ///@param transcodingProtocol Optional. The transcoding protocol. + ///@param maxAudioSampleRate Optional. The maximum audio sample rate. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param enableRemoteMedia Optional. Whether to enable remote media. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param enableRedirection Whether to enable redirection. Defaults to true. + Future> audioItemIdUniversalGet({ + required String? itemId, + List? container, + String? mediaSourceId, + String? deviceId, + String? userId, + String? audioCodec, + int? maxAudioChannels, + int? transcodingAudioChannels, + int? maxStreamingBitrate, + int? audioBitRate, + int? startTimeTicks, + String? transcodingContainer, + enums.AudioItemIdUniversalGetTranscodingProtocol? transcodingProtocol, + int? maxAudioSampleRate, + int? maxAudioBitDepth, + bool? enableRemoteMedia, + bool? breakOnNonKeyFrames, + bool? enableRedirection, + }) { + return _audioItemIdUniversalGet( + itemId: itemId, + container: container, + mediaSourceId: mediaSourceId, + deviceId: deviceId, + userId: userId, + audioCodec: audioCodec, + maxAudioChannels: maxAudioChannels, + transcodingAudioChannels: transcodingAudioChannels, + maxStreamingBitrate: maxStreamingBitrate, + audioBitRate: audioBitRate, + startTimeTicks: startTimeTicks, + transcodingContainer: transcodingContainer, + transcodingProtocol: transcodingProtocol?.value?.toString(), + maxAudioSampleRate: maxAudioSampleRate, + maxAudioBitDepth: maxAudioBitDepth, + enableRemoteMedia: enableRemoteMedia, + breakOnNonKeyFrames: breakOnNonKeyFrames, + enableRedirection: enableRedirection); + } + + ///Gets an audio stream. + ///@param itemId The item id. + ///@param container Optional. The audio container. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param userId Optional. The user id. + ///@param audioCodec Optional. The audio codec to transcode to. + ///@param maxAudioChannels Optional. The maximum number of audio channels. + ///@param transcodingAudioChannels Optional. The number of how many audio channels to transcode to. + ///@param maxStreamingBitrate Optional. The maximum streaming bitrate. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param transcodingContainer Optional. The container to transcode to. + ///@param transcodingProtocol Optional. The transcoding protocol. + ///@param maxAudioSampleRate Optional. The maximum audio sample rate. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param enableRemoteMedia Optional. Whether to enable remote media. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param enableRedirection Whether to enable redirection. Defaults to true. + @Get(path: '/Audio/{itemId}/universal') + Future> _audioItemIdUniversalGet({ + @Path('itemId') required String? itemId, + @Query('container') List? container, + @Query('mediaSourceId') String? mediaSourceId, + @Query('deviceId') String? deviceId, + @Query('userId') String? userId, + @Query('audioCodec') String? audioCodec, + @Query('maxAudioChannels') int? maxAudioChannels, + @Query('transcodingAudioChannels') int? transcodingAudioChannels, + @Query('maxStreamingBitrate') int? maxStreamingBitrate, + @Query('audioBitRate') int? audioBitRate, + @Query('startTimeTicks') int? startTimeTicks, + @Query('transcodingContainer') String? transcodingContainer, + @Query('transcodingProtocol') String? transcodingProtocol, + @Query('maxAudioSampleRate') int? maxAudioSampleRate, + @Query('maxAudioBitDepth') int? maxAudioBitDepth, + @Query('enableRemoteMedia') bool? enableRemoteMedia, + @Query('breakOnNonKeyFrames') bool? breakOnNonKeyFrames, + @Query('enableRedirection') bool? enableRedirection, + }); + + ///Gets an audio stream. + ///@param itemId The item id. + ///@param container Optional. The audio container. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param userId Optional. The user id. + ///@param audioCodec Optional. The audio codec to transcode to. + ///@param maxAudioChannels Optional. The maximum number of audio channels. + ///@param transcodingAudioChannels Optional. The number of how many audio channels to transcode to. + ///@param maxStreamingBitrate Optional. The maximum streaming bitrate. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param transcodingContainer Optional. The container to transcode to. + ///@param transcodingProtocol Optional. The transcoding protocol. + ///@param maxAudioSampleRate Optional. The maximum audio sample rate. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param enableRemoteMedia Optional. Whether to enable remote media. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param enableRedirection Whether to enable redirection. Defaults to true. + Future> audioItemIdUniversalHead({ + required String? itemId, + List? container, + String? mediaSourceId, + String? deviceId, + String? userId, + String? audioCodec, + int? maxAudioChannels, + int? transcodingAudioChannels, + int? maxStreamingBitrate, + int? audioBitRate, + int? startTimeTicks, + String? transcodingContainer, + enums.AudioItemIdUniversalHeadTranscodingProtocol? transcodingProtocol, + int? maxAudioSampleRate, + int? maxAudioBitDepth, + bool? enableRemoteMedia, + bool? breakOnNonKeyFrames, + bool? enableRedirection, + }) { + return _audioItemIdUniversalHead( + itemId: itemId, + container: container, + mediaSourceId: mediaSourceId, + deviceId: deviceId, + userId: userId, + audioCodec: audioCodec, + maxAudioChannels: maxAudioChannels, + transcodingAudioChannels: transcodingAudioChannels, + maxStreamingBitrate: maxStreamingBitrate, + audioBitRate: audioBitRate, + startTimeTicks: startTimeTicks, + transcodingContainer: transcodingContainer, + transcodingProtocol: transcodingProtocol?.value?.toString(), + maxAudioSampleRate: maxAudioSampleRate, + maxAudioBitDepth: maxAudioBitDepth, + enableRemoteMedia: enableRemoteMedia, + breakOnNonKeyFrames: breakOnNonKeyFrames, + enableRedirection: enableRedirection); + } + + ///Gets an audio stream. + ///@param itemId The item id. + ///@param container Optional. The audio container. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param userId Optional. The user id. + ///@param audioCodec Optional. The audio codec to transcode to. + ///@param maxAudioChannels Optional. The maximum number of audio channels. + ///@param transcodingAudioChannels Optional. The number of how many audio channels to transcode to. + ///@param maxStreamingBitrate Optional. The maximum streaming bitrate. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param transcodingContainer Optional. The container to transcode to. + ///@param transcodingProtocol Optional. The transcoding protocol. + ///@param maxAudioSampleRate Optional. The maximum audio sample rate. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param enableRemoteMedia Optional. Whether to enable remote media. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param enableRedirection Whether to enable redirection. Defaults to true. + @Head(path: '/Audio/{itemId}/universal') + Future> _audioItemIdUniversalHead({ + @Path('itemId') required String? itemId, + @Query('container') List? container, + @Query('mediaSourceId') String? mediaSourceId, + @Query('deviceId') String? deviceId, + @Query('userId') String? userId, + @Query('audioCodec') String? audioCodec, + @Query('maxAudioChannels') int? maxAudioChannels, + @Query('transcodingAudioChannels') int? transcodingAudioChannels, + @Query('maxStreamingBitrate') int? maxStreamingBitrate, + @Query('audioBitRate') int? audioBitRate, + @Query('startTimeTicks') int? startTimeTicks, + @Query('transcodingContainer') String? transcodingContainer, + @Query('transcodingProtocol') String? transcodingProtocol, + @Query('maxAudioSampleRate') int? maxAudioSampleRate, + @Query('maxAudioBitDepth') int? maxAudioBitDepth, + @Query('enableRemoteMedia') bool? enableRemoteMedia, + @Query('breakOnNonKeyFrames') bool? breakOnNonKeyFrames, + @Query('enableRedirection') bool? enableRedirection, + }); + + ///Gets a list of users. + ///@param isHidden Optional filter by IsHidden=true or false. + ///@param isDisabled Optional filter by IsDisabled=true or false. + Future>> usersGet({ + bool? isHidden, + bool? isDisabled, + }) { + generatedMapping.putIfAbsent(UserDto, () => UserDto.fromJsonFactory); + + return _usersGet(isHidden: isHidden, isDisabled: isDisabled); + } + + ///Gets a list of users. + ///@param isHidden Optional filter by IsHidden=true or false. + ///@param isDisabled Optional filter by IsDisabled=true or false. + @Get(path: '/Users') + Future>> _usersGet({ + @Query('isHidden') bool? isHidden, + @Query('isDisabled') bool? isDisabled, + }); + + ///Updates a user. + ///@param userId The user id. + Future usersPost({ + String? userId, + required UserDto? body, + }) { + return _usersPost(userId: userId, body: body); + } + + ///Updates a user. + ///@param userId The user id. + @Post( + path: '/Users', + optionalBody: true, + ) + Future _usersPost({ + @Query('userId') String? userId, + @Body() required UserDto? body, + }); + + ///Gets a user by Id. + ///@param userId The user id. + Future> usersUserIdGet({required String? userId}) { + generatedMapping.putIfAbsent(UserDto, () => UserDto.fromJsonFactory); + + return _usersUserIdGet(userId: userId); + } + + ///Gets a user by Id. + ///@param userId The user id. + @Get(path: '/Users/{userId}') + Future> _usersUserIdGet( + {@Path('userId') required String? userId}); + + ///Deletes a user. + ///@param userId The user id. + Future usersUserIdDelete({required String? userId}) { + return _usersUserIdDelete(userId: userId); + } + + ///Deletes a user. + ///@param userId The user id. + @Delete(path: '/Users/{userId}') + Future _usersUserIdDelete( + {@Path('userId') required String? userId}); + + ///Updates a user policy. + ///@param userId The user id. + Future usersUserIdPolicyPost({ + required String? userId, + required UserPolicy? body, + }) { + return _usersUserIdPolicyPost(userId: userId, body: body); + } + + ///Updates a user policy. + ///@param userId The user id. + @Post( + path: '/Users/{userId}/Policy', + optionalBody: true, + ) + Future _usersUserIdPolicyPost({ + @Path('userId') required String? userId, + @Body() required UserPolicy? body, + }); + + ///Authenticates a user by name. + Future> usersAuthenticateByNamePost( + {required AuthenticateUserByName? body}) { + generatedMapping.putIfAbsent( + AuthenticationResult, () => AuthenticationResult.fromJsonFactory); + + return _usersAuthenticateByNamePost(body: body); + } + + ///Authenticates a user by name. + @Post( + path: '/Users/AuthenticateByName', + optionalBody: true, + ) + Future> _usersAuthenticateByNamePost( + {@Body() required AuthenticateUserByName? body}); + + ///Authenticates a user with quick connect. + Future> + usersAuthenticateWithQuickConnectPost({required QuickConnectDto? body}) { + generatedMapping.putIfAbsent( + AuthenticationResult, () => AuthenticationResult.fromJsonFactory); + + return _usersAuthenticateWithQuickConnectPost(body: body); + } + + ///Authenticates a user with quick connect. + @Post( + path: '/Users/AuthenticateWithQuickConnect', + optionalBody: true, + ) + Future> + _usersAuthenticateWithQuickConnectPost( + {@Body() required QuickConnectDto? body}); + + ///Updates a user configuration. + ///@param userId The user id. + Future usersConfigurationPost({ + String? userId, + required UserConfiguration? body, + }) { + return _usersConfigurationPost(userId: userId, body: body); + } + + ///Updates a user configuration. + ///@param userId The user id. + @Post( + path: '/Users/Configuration', + optionalBody: true, + ) + Future _usersConfigurationPost({ + @Query('userId') String? userId, + @Body() required UserConfiguration? body, + }); + + ///Initiates the forgot password process for a local user. + Future> usersForgotPasswordPost( + {required ForgotPasswordDto? body}) { + generatedMapping.putIfAbsent( + ForgotPasswordResult, () => ForgotPasswordResult.fromJsonFactory); + + return _usersForgotPasswordPost(body: body); + } + + ///Initiates the forgot password process for a local user. + @Post( + path: '/Users/ForgotPassword', + optionalBody: true, + ) + Future> _usersForgotPasswordPost( + {@Body() required ForgotPasswordDto? body}); + + ///Redeems a forgot password pin. + Future> usersForgotPasswordPinPost( + {required ForgotPasswordPinDto? body}) { + generatedMapping.putIfAbsent( + PinRedeemResult, () => PinRedeemResult.fromJsonFactory); + + return _usersForgotPasswordPinPost(body: body); + } + + ///Redeems a forgot password pin. + @Post( + path: '/Users/ForgotPassword/Pin', + optionalBody: true, + ) + Future> _usersForgotPasswordPinPost( + {@Body() required ForgotPasswordPinDto? body}); + + ///Gets the user based on auth token. + Future> usersMeGet() { + generatedMapping.putIfAbsent(UserDto, () => UserDto.fromJsonFactory); + + return _usersMeGet(); + } + + ///Gets the user based on auth token. + @Get(path: '/Users/Me') + Future> _usersMeGet(); + + ///Creates a user. + Future> usersNewPost( + {required CreateUserByName? body}) { + generatedMapping.putIfAbsent(UserDto, () => UserDto.fromJsonFactory); + + return _usersNewPost(body: body); + } + + ///Creates a user. + @Post( + path: '/Users/New', + optionalBody: true, + ) + Future> _usersNewPost( + {@Body() required CreateUserByName? body}); + + ///Updates a user's password. + ///@param userId The user id. + Future usersPasswordPost({ + String? userId, + required UpdateUserPassword? body, + }) { + return _usersPasswordPost(userId: userId, body: body); + } + + ///Updates a user's password. + ///@param userId The user id. + @Post( + path: '/Users/Password', + optionalBody: true, + ) + Future _usersPasswordPost({ + @Query('userId') String? userId, + @Body() required UpdateUserPassword? body, + }); + + ///Gets a list of publicly visible users for display on a login screen. + Future>> usersPublicGet() { + generatedMapping.putIfAbsent(UserDto, () => UserDto.fromJsonFactory); + + return _usersPublicGet(); + } + + ///Gets a list of publicly visible users for display on a login screen. + @Get(path: '/Users/Public') + Future>> _usersPublicGet(); + + ///Gets intros to play before the main media item plays. + ///@param userId User id. + ///@param itemId Item id. + Future> itemsItemIdIntrosGet({ + String? userId, + required String? itemId, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _itemsItemIdIntrosGet(userId: userId, itemId: itemId); + } + + ///Gets intros to play before the main media item plays. + ///@param userId User id. + ///@param itemId Item id. + @Get(path: '/Items/{itemId}/Intros') + Future> _itemsItemIdIntrosGet({ + @Query('userId') String? userId, + @Path('itemId') required String? itemId, + }); + + ///Gets local trailers for an item. + ///@param userId User id. + ///@param itemId Item id. + Future>> itemsItemIdLocalTrailersGet({ + String? userId, + required String? itemId, + }) { + generatedMapping.putIfAbsent( + BaseItemDto, () => BaseItemDto.fromJsonFactory); + + return _itemsItemIdLocalTrailersGet(userId: userId, itemId: itemId); + } + + ///Gets local trailers for an item. + ///@param userId User id. + ///@param itemId Item id. + @Get(path: '/Items/{itemId}/LocalTrailers') + Future>> _itemsItemIdLocalTrailersGet({ + @Query('userId') String? userId, + @Path('itemId') required String? itemId, + }); + + ///Gets special features for an item. + ///@param userId User id. + ///@param itemId Item id. + Future>> itemsItemIdSpecialFeaturesGet({ + String? userId, + required String? itemId, + }) { + generatedMapping.putIfAbsent( + BaseItemDto, () => BaseItemDto.fromJsonFactory); + + return _itemsItemIdSpecialFeaturesGet(userId: userId, itemId: itemId); + } + + ///Gets special features for an item. + ///@param userId User id. + ///@param itemId Item id. + @Get(path: '/Items/{itemId}/SpecialFeatures') + Future>> _itemsItemIdSpecialFeaturesGet({ + @Query('userId') String? userId, + @Path('itemId') required String? itemId, + }); + + ///Gets latest media. + ///@param userId User id. + ///@param parentId Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param includeItemTypes Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited. + ///@param isPlayed Filter by items that are played, or not. + ///@param enableImages Optional. include image information in output. + ///@param imageTypeLimit Optional. the max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param enableUserData Optional. include user data. + ///@param limit Return item limit. + ///@param groupItems Whether or not to group items into a parent container. + Future>> itemsLatestGet({ + String? userId, + String? parentId, + List? fields, + List? includeItemTypes, + bool? isPlayed, + bool? enableImages, + int? imageTypeLimit, + List? enableImageTypes, + bool? enableUserData, + int? limit, + bool? groupItems, + }) { + generatedMapping.putIfAbsent( + BaseItemDto, () => BaseItemDto.fromJsonFactory); + + return _itemsLatestGet( + userId: userId, + parentId: parentId, + fields: itemFieldsListToJson(fields), + includeItemTypes: baseItemKindListToJson(includeItemTypes), + isPlayed: isPlayed, + enableImages: enableImages, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes), + enableUserData: enableUserData, + limit: limit, + groupItems: groupItems); + } + + ///Gets latest media. + ///@param userId User id. + ///@param parentId Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param includeItemTypes Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited. + ///@param isPlayed Filter by items that are played, or not. + ///@param enableImages Optional. include image information in output. + ///@param imageTypeLimit Optional. the max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param enableUserData Optional. include user data. + ///@param limit Return item limit. + ///@param groupItems Whether or not to group items into a parent container. + @Get(path: '/Items/Latest') + Future>> _itemsLatestGet({ + @Query('userId') String? userId, + @Query('parentId') String? parentId, + @Query('fields') List? fields, + @Query('includeItemTypes') List? includeItemTypes, + @Query('isPlayed') bool? isPlayed, + @Query('enableImages') bool? enableImages, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + @Query('enableUserData') bool? enableUserData, + @Query('limit') int? limit, + @Query('groupItems') bool? groupItems, + }); + + ///Gets the root folder from a user's library. + ///@param userId User id. + Future> itemsRootGet({String? userId}) { + generatedMapping.putIfAbsent( + BaseItemDto, () => BaseItemDto.fromJsonFactory); + + return _itemsRootGet(userId: userId); + } + + ///Gets the root folder from a user's library. + ///@param userId User id. + @Get(path: '/Items/Root') + Future> _itemsRootGet( + {@Query('userId') String? userId}); + + ///Marks an item as a favorite. + ///@param userId User id. + ///@param itemId Item id. + Future> userFavoriteItemsItemIdPost({ + String? userId, + required String? itemId, + }) { + generatedMapping.putIfAbsent( + UserItemDataDto, () => UserItemDataDto.fromJsonFactory); + + return _userFavoriteItemsItemIdPost(userId: userId, itemId: itemId); + } + + ///Marks an item as a favorite. + ///@param userId User id. + ///@param itemId Item id. + @Post( + path: '/UserFavoriteItems/{itemId}', + optionalBody: true, + ) + Future> _userFavoriteItemsItemIdPost({ + @Query('userId') String? userId, + @Path('itemId') required String? itemId, + }); + + ///Unmarks item as a favorite. + ///@param userId User id. + ///@param itemId Item id. + Future> userFavoriteItemsItemIdDelete({ + String? userId, + required String? itemId, + }) { + generatedMapping.putIfAbsent( + UserItemDataDto, () => UserItemDataDto.fromJsonFactory); + + return _userFavoriteItemsItemIdDelete(userId: userId, itemId: itemId); + } + + ///Unmarks item as a favorite. + ///@param userId User id. + ///@param itemId Item id. + @Delete(path: '/UserFavoriteItems/{itemId}') + Future> _userFavoriteItemsItemIdDelete({ + @Query('userId') String? userId, + @Path('itemId') required String? itemId, + }); + + ///Deletes a user's saved personal rating for an item. + ///@param userId User id. + ///@param itemId Item id. + Future> userItemsItemIdRatingDelete({ + String? userId, + required String? itemId, + }) { + generatedMapping.putIfAbsent( + UserItemDataDto, () => UserItemDataDto.fromJsonFactory); + + return _userItemsItemIdRatingDelete(userId: userId, itemId: itemId); + } + + ///Deletes a user's saved personal rating for an item. + ///@param userId User id. + ///@param itemId Item id. + @Delete(path: '/UserItems/{itemId}/Rating') + Future> _userItemsItemIdRatingDelete({ + @Query('userId') String? userId, + @Path('itemId') required String? itemId, + }); + + ///Updates a user's rating for an item. + ///@param userId User id. + ///@param itemId Item id. + ///@param likes Whether this M:Jellyfin.Api.Controllers.UserLibraryController.UpdateUserItemRating(System.Nullable{System.Guid},System.Guid,System.Nullable{System.Boolean}) is likes. + Future> userItemsItemIdRatingPost({ + String? userId, + required String? itemId, + bool? likes, + }) { + generatedMapping.putIfAbsent( + UserItemDataDto, () => UserItemDataDto.fromJsonFactory); + + return _userItemsItemIdRatingPost( + userId: userId, itemId: itemId, likes: likes); + } + + ///Updates a user's rating for an item. + ///@param userId User id. + ///@param itemId Item id. + ///@param likes Whether this M:Jellyfin.Api.Controllers.UserLibraryController.UpdateUserItemRating(System.Nullable{System.Guid},System.Guid,System.Nullable{System.Boolean}) is likes. + @Post( + path: '/UserItems/{itemId}/Rating', + optionalBody: true, + ) + Future> _userItemsItemIdRatingPost({ + @Query('userId') String? userId, + @Path('itemId') required String? itemId, + @Query('likes') bool? likes, + }); + + ///Get user views. + ///@param userId User id. + ///@param includeExternalContent Whether or not to include external views such as channels or live tv. + ///@param presetViews Preset views. + ///@param includeHidden Whether or not to include hidden content. + Future> userViewsGet({ + String? userId, + bool? includeExternalContent, + List? presetViews, + bool? includeHidden, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _userViewsGet( + userId: userId, + includeExternalContent: includeExternalContent, + presetViews: collectionTypeListToJson(presetViews), + includeHidden: includeHidden); + } + + ///Get user views. + ///@param userId User id. + ///@param includeExternalContent Whether or not to include external views such as channels or live tv. + ///@param presetViews Preset views. + ///@param includeHidden Whether or not to include hidden content. + @Get(path: '/UserViews') + Future> _userViewsGet({ + @Query('userId') String? userId, + @Query('includeExternalContent') bool? includeExternalContent, + @Query('presetViews') List? presetViews, + @Query('includeHidden') bool? includeHidden, + }); + + ///Get user view grouping options. + ///@param userId User id. + Future>> + userViewsGroupingOptionsGet({String? userId}) { + generatedMapping.putIfAbsent( + SpecialViewOptionDto, () => SpecialViewOptionDto.fromJsonFactory); + + return _userViewsGroupingOptionsGet(userId: userId); + } + + ///Get user view grouping options. + ///@param userId User id. + @Get(path: '/UserViews/GroupingOptions') + Future>> + _userViewsGroupingOptionsGet({@Query('userId') String? userId}); + + ///Get video attachment. + ///@param videoId Video ID. + ///@param mediaSourceId Media Source ID. + ///@param index Attachment Index. + Future> + videosVideoIdMediaSourceIdAttachmentsIndexGet({ + required String? videoId, + required String? mediaSourceId, + required int? index, + }) { + return _videosVideoIdMediaSourceIdAttachmentsIndexGet( + videoId: videoId, mediaSourceId: mediaSourceId, index: index); + } + + ///Get video attachment. + ///@param videoId Video ID. + ///@param mediaSourceId Media Source ID. + ///@param index Attachment Index. + @Get(path: '/Videos/{videoId}/{mediaSourceId}/Attachments/{index}') + Future> + _videosVideoIdMediaSourceIdAttachmentsIndexGet({ + @Path('videoId') required String? videoId, + @Path('mediaSourceId') required String? mediaSourceId, + @Path('index') required int? index, + }); + + ///Gets additional parts for a video. + ///@param itemId The item id. + ///@param userId Optional. Filter by user id, and attach user data. + Future> + videosItemIdAdditionalPartsGet({ + required String? itemId, + String? userId, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _videosItemIdAdditionalPartsGet(itemId: itemId, userId: userId); + } + + ///Gets additional parts for a video. + ///@param itemId The item id. + ///@param userId Optional. Filter by user id, and attach user data. + @Get(path: '/Videos/{itemId}/AdditionalParts') + Future> + _videosItemIdAdditionalPartsGet({ + @Path('itemId') required String? itemId, + @Query('userId') String? userId, + }); + + ///Removes alternate video sources. + ///@param itemId The item id. + Future videosItemIdAlternateSourcesDelete( + {required String? itemId}) { + return _videosItemIdAlternateSourcesDelete(itemId: itemId); + } + + ///Removes alternate video sources. + ///@param itemId The item id. + @Delete(path: '/Videos/{itemId}/AlternateSources') + Future _videosItemIdAlternateSourcesDelete( + {@Path('itemId') required String? itemId}); + + ///Gets a video stream. + ///@param itemId The item id. + ///@param container The video container. Possible values are: ts, webm, asf, wmv, ogv, mp4, m4v, mkv, mpeg, mpg, avi, 3gp, wmv, wtv, m2ts, mov, iso, flv. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param maxWidth Optional. The maximum horizontal resolution of the encoded video. + ///@param maxHeight Optional. The maximum vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + Future> videosItemIdStreamGet({ + required String? itemId, + String? container, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? maxWidth, + int? maxHeight, + int? videoBitRate, + int? subtitleStreamIndex, + enums.VideosItemIdStreamGetSubtitleMethod? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + enums.VideosItemIdStreamGetContext? context, + Object? streamOptions, + }) { + return _videosItemIdStreamGet( + itemId: itemId, + container: container, + $static: $static, + params: params, + tag: tag, + deviceProfileId: deviceProfileId, + playSessionId: playSessionId, + segmentContainer: segmentContainer, + segmentLength: segmentLength, + minSegments: minSegments, + mediaSourceId: mediaSourceId, + deviceId: deviceId, + audioCodec: audioCodec, + enableAutoStreamCopy: enableAutoStreamCopy, + allowVideoStreamCopy: allowVideoStreamCopy, + allowAudioStreamCopy: allowAudioStreamCopy, + breakOnNonKeyFrames: breakOnNonKeyFrames, + audioSampleRate: audioSampleRate, + maxAudioBitDepth: maxAudioBitDepth, + audioBitRate: audioBitRate, + audioChannels: audioChannels, + maxAudioChannels: maxAudioChannels, + profile: profile, + level: level, + framerate: framerate, + maxFramerate: maxFramerate, + copyTimestamps: copyTimestamps, + startTimeTicks: startTimeTicks, + width: width, + height: height, + maxWidth: maxWidth, + maxHeight: maxHeight, + videoBitRate: videoBitRate, + subtitleStreamIndex: subtitleStreamIndex, + subtitleMethod: subtitleMethod?.value?.toString(), + maxRefFrames: maxRefFrames, + maxVideoBitDepth: maxVideoBitDepth, + requireAvc: requireAvc, + deInterlace: deInterlace, + requireNonAnamorphic: requireNonAnamorphic, + transcodingMaxAudioChannels: transcodingMaxAudioChannels, + cpuCoreLimit: cpuCoreLimit, + liveStreamId: liveStreamId, + enableMpegtsM2TsMode: enableMpegtsM2TsMode, + videoCodec: videoCodec, + subtitleCodec: subtitleCodec, + transcodeReasons: transcodeReasons, + audioStreamIndex: audioStreamIndex, + videoStreamIndex: videoStreamIndex, + context: context?.value?.toString(), + streamOptions: streamOptions); + } + + ///Gets a video stream. + ///@param itemId The item id. + ///@param container The video container. Possible values are: ts, webm, asf, wmv, ogv, mp4, m4v, mkv, mpeg, mpg, avi, 3gp, wmv, wtv, m2ts, mov, iso, flv. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param maxWidth Optional. The maximum horizontal resolution of the encoded video. + ///@param maxHeight Optional. The maximum vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + @Get(path: '/Videos/{itemId}/stream') + Future> _videosItemIdStreamGet({ + @Path('itemId') required String? itemId, + @Query('container') String? container, + @Query('static') bool? $static, + @Query('params') String? params, + @Query('tag') String? tag, + @Query('deviceProfileId') String? deviceProfileId, + @Query('playSessionId') String? playSessionId, + @Query('segmentContainer') String? segmentContainer, + @Query('segmentLength') int? segmentLength, + @Query('minSegments') int? minSegments, + @Query('mediaSourceId') String? mediaSourceId, + @Query('deviceId') String? deviceId, + @Query('audioCodec') String? audioCodec, + @Query('enableAutoStreamCopy') bool? enableAutoStreamCopy, + @Query('allowVideoStreamCopy') bool? allowVideoStreamCopy, + @Query('allowAudioStreamCopy') bool? allowAudioStreamCopy, + @Query('breakOnNonKeyFrames') bool? breakOnNonKeyFrames, + @Query('audioSampleRate') int? audioSampleRate, + @Query('maxAudioBitDepth') int? maxAudioBitDepth, + @Query('audioBitRate') int? audioBitRate, + @Query('audioChannels') int? audioChannels, + @Query('maxAudioChannels') int? maxAudioChannels, + @Query('profile') String? profile, + @Query('level') String? level, + @Query('framerate') num? framerate, + @Query('maxFramerate') num? maxFramerate, + @Query('copyTimestamps') bool? copyTimestamps, + @Query('startTimeTicks') int? startTimeTicks, + @Query('width') int? width, + @Query('height') int? height, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('videoBitRate') int? videoBitRate, + @Query('subtitleStreamIndex') int? subtitleStreamIndex, + @Query('subtitleMethod') String? subtitleMethod, + @Query('maxRefFrames') int? maxRefFrames, + @Query('maxVideoBitDepth') int? maxVideoBitDepth, + @Query('requireAvc') bool? requireAvc, + @Query('deInterlace') bool? deInterlace, + @Query('requireNonAnamorphic') bool? requireNonAnamorphic, + @Query('transcodingMaxAudioChannels') int? transcodingMaxAudioChannels, + @Query('cpuCoreLimit') int? cpuCoreLimit, + @Query('liveStreamId') String? liveStreamId, + @Query('enableMpegtsM2TsMode') bool? enableMpegtsM2TsMode, + @Query('videoCodec') String? videoCodec, + @Query('subtitleCodec') String? subtitleCodec, + @Query('transcodeReasons') String? transcodeReasons, + @Query('audioStreamIndex') int? audioStreamIndex, + @Query('videoStreamIndex') int? videoStreamIndex, + @Query('context') String? context, + @Query('streamOptions') Object? streamOptions, + }); + + ///Gets a video stream. + ///@param itemId The item id. + ///@param container The video container. Possible values are: ts, webm, asf, wmv, ogv, mp4, m4v, mkv, mpeg, mpg, avi, 3gp, wmv, wtv, m2ts, mov, iso, flv. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param maxWidth Optional. The maximum horizontal resolution of the encoded video. + ///@param maxHeight Optional. The maximum vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + Future> videosItemIdStreamHead({ + required String? itemId, + String? container, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? maxWidth, + int? maxHeight, + int? videoBitRate, + int? subtitleStreamIndex, + enums.VideosItemIdStreamHeadSubtitleMethod? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + enums.VideosItemIdStreamHeadContext? context, + Object? streamOptions, + }) { + return _videosItemIdStreamHead( + itemId: itemId, + container: container, + $static: $static, + params: params, + tag: tag, + deviceProfileId: deviceProfileId, + playSessionId: playSessionId, + segmentContainer: segmentContainer, + segmentLength: segmentLength, + minSegments: minSegments, + mediaSourceId: mediaSourceId, + deviceId: deviceId, + audioCodec: audioCodec, + enableAutoStreamCopy: enableAutoStreamCopy, + allowVideoStreamCopy: allowVideoStreamCopy, + allowAudioStreamCopy: allowAudioStreamCopy, + breakOnNonKeyFrames: breakOnNonKeyFrames, + audioSampleRate: audioSampleRate, + maxAudioBitDepth: maxAudioBitDepth, + audioBitRate: audioBitRate, + audioChannels: audioChannels, + maxAudioChannels: maxAudioChannels, + profile: profile, + level: level, + framerate: framerate, + maxFramerate: maxFramerate, + copyTimestamps: copyTimestamps, + startTimeTicks: startTimeTicks, + width: width, + height: height, + maxWidth: maxWidth, + maxHeight: maxHeight, + videoBitRate: videoBitRate, + subtitleStreamIndex: subtitleStreamIndex, + subtitleMethod: subtitleMethod?.value?.toString(), + maxRefFrames: maxRefFrames, + maxVideoBitDepth: maxVideoBitDepth, + requireAvc: requireAvc, + deInterlace: deInterlace, + requireNonAnamorphic: requireNonAnamorphic, + transcodingMaxAudioChannels: transcodingMaxAudioChannels, + cpuCoreLimit: cpuCoreLimit, + liveStreamId: liveStreamId, + enableMpegtsM2TsMode: enableMpegtsM2TsMode, + videoCodec: videoCodec, + subtitleCodec: subtitleCodec, + transcodeReasons: transcodeReasons, + audioStreamIndex: audioStreamIndex, + videoStreamIndex: videoStreamIndex, + context: context?.value?.toString(), + streamOptions: streamOptions); + } + + ///Gets a video stream. + ///@param itemId The item id. + ///@param container The video container. Possible values are: ts, webm, asf, wmv, ogv, mp4, m4v, mkv, mpeg, mpg, avi, 3gp, wmv, wtv, m2ts, mov, iso, flv. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param maxWidth Optional. The maximum horizontal resolution of the encoded video. + ///@param maxHeight Optional. The maximum vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + @Head(path: '/Videos/{itemId}/stream') + Future> _videosItemIdStreamHead({ + @Path('itemId') required String? itemId, + @Query('container') String? container, + @Query('static') bool? $static, + @Query('params') String? params, + @Query('tag') String? tag, + @Query('deviceProfileId') String? deviceProfileId, + @Query('playSessionId') String? playSessionId, + @Query('segmentContainer') String? segmentContainer, + @Query('segmentLength') int? segmentLength, + @Query('minSegments') int? minSegments, + @Query('mediaSourceId') String? mediaSourceId, + @Query('deviceId') String? deviceId, + @Query('audioCodec') String? audioCodec, + @Query('enableAutoStreamCopy') bool? enableAutoStreamCopy, + @Query('allowVideoStreamCopy') bool? allowVideoStreamCopy, + @Query('allowAudioStreamCopy') bool? allowAudioStreamCopy, + @Query('breakOnNonKeyFrames') bool? breakOnNonKeyFrames, + @Query('audioSampleRate') int? audioSampleRate, + @Query('maxAudioBitDepth') int? maxAudioBitDepth, + @Query('audioBitRate') int? audioBitRate, + @Query('audioChannels') int? audioChannels, + @Query('maxAudioChannels') int? maxAudioChannels, + @Query('profile') String? profile, + @Query('level') String? level, + @Query('framerate') num? framerate, + @Query('maxFramerate') num? maxFramerate, + @Query('copyTimestamps') bool? copyTimestamps, + @Query('startTimeTicks') int? startTimeTicks, + @Query('width') int? width, + @Query('height') int? height, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('videoBitRate') int? videoBitRate, + @Query('subtitleStreamIndex') int? subtitleStreamIndex, + @Query('subtitleMethod') String? subtitleMethod, + @Query('maxRefFrames') int? maxRefFrames, + @Query('maxVideoBitDepth') int? maxVideoBitDepth, + @Query('requireAvc') bool? requireAvc, + @Query('deInterlace') bool? deInterlace, + @Query('requireNonAnamorphic') bool? requireNonAnamorphic, + @Query('transcodingMaxAudioChannels') int? transcodingMaxAudioChannels, + @Query('cpuCoreLimit') int? cpuCoreLimit, + @Query('liveStreamId') String? liveStreamId, + @Query('enableMpegtsM2TsMode') bool? enableMpegtsM2TsMode, + @Query('videoCodec') String? videoCodec, + @Query('subtitleCodec') String? subtitleCodec, + @Query('transcodeReasons') String? transcodeReasons, + @Query('audioStreamIndex') int? audioStreamIndex, + @Query('videoStreamIndex') int? videoStreamIndex, + @Query('context') String? context, + @Query('streamOptions') Object? streamOptions, + }); + + ///Gets a video stream. + ///@param itemId The item id. + ///@param container The video container. Possible values are: ts, webm, asf, wmv, ogv, mp4, m4v, mkv, mpeg, mpg, avi, 3gp, wmv, wtv, m2ts, mov, iso, flv. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param maxWidth Optional. The maximum horizontal resolution of the encoded video. + ///@param maxHeight Optional. The maximum vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + Future> videosItemIdStreamContainerGet({ + required String? itemId, + required String? container, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? maxWidth, + int? maxHeight, + int? videoBitRate, + int? subtitleStreamIndex, + enums.VideosItemIdStreamContainerGetSubtitleMethod? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + enums.VideosItemIdStreamContainerGetContext? context, + Object? streamOptions, + }) { + return _videosItemIdStreamContainerGet( + itemId: itemId, + container: container, + $static: $static, + params: params, + tag: tag, + deviceProfileId: deviceProfileId, + playSessionId: playSessionId, + segmentContainer: segmentContainer, + segmentLength: segmentLength, + minSegments: minSegments, + mediaSourceId: mediaSourceId, + deviceId: deviceId, + audioCodec: audioCodec, + enableAutoStreamCopy: enableAutoStreamCopy, + allowVideoStreamCopy: allowVideoStreamCopy, + allowAudioStreamCopy: allowAudioStreamCopy, + breakOnNonKeyFrames: breakOnNonKeyFrames, + audioSampleRate: audioSampleRate, + maxAudioBitDepth: maxAudioBitDepth, + audioBitRate: audioBitRate, + audioChannels: audioChannels, + maxAudioChannels: maxAudioChannels, + profile: profile, + level: level, + framerate: framerate, + maxFramerate: maxFramerate, + copyTimestamps: copyTimestamps, + startTimeTicks: startTimeTicks, + width: width, + height: height, + maxWidth: maxWidth, + maxHeight: maxHeight, + videoBitRate: videoBitRate, + subtitleStreamIndex: subtitleStreamIndex, + subtitleMethod: subtitleMethod?.value?.toString(), + maxRefFrames: maxRefFrames, + maxVideoBitDepth: maxVideoBitDepth, + requireAvc: requireAvc, + deInterlace: deInterlace, + requireNonAnamorphic: requireNonAnamorphic, + transcodingMaxAudioChannels: transcodingMaxAudioChannels, + cpuCoreLimit: cpuCoreLimit, + liveStreamId: liveStreamId, + enableMpegtsM2TsMode: enableMpegtsM2TsMode, + videoCodec: videoCodec, + subtitleCodec: subtitleCodec, + transcodeReasons: transcodeReasons, + audioStreamIndex: audioStreamIndex, + videoStreamIndex: videoStreamIndex, + context: context?.value?.toString(), + streamOptions: streamOptions); + } + + ///Gets a video stream. + ///@param itemId The item id. + ///@param container The video container. Possible values are: ts, webm, asf, wmv, ogv, mp4, m4v, mkv, mpeg, mpg, avi, 3gp, wmv, wtv, m2ts, mov, iso, flv. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param maxWidth Optional. The maximum horizontal resolution of the encoded video. + ///@param maxHeight Optional. The maximum vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + @Get(path: '/Videos/{itemId}/stream.{container}') + Future> _videosItemIdStreamContainerGet({ + @Path('itemId') required String? itemId, + @Path('container') required String? container, + @Query('static') bool? $static, + @Query('params') String? params, + @Query('tag') String? tag, + @Query('deviceProfileId') String? deviceProfileId, + @Query('playSessionId') String? playSessionId, + @Query('segmentContainer') String? segmentContainer, + @Query('segmentLength') int? segmentLength, + @Query('minSegments') int? minSegments, + @Query('mediaSourceId') String? mediaSourceId, + @Query('deviceId') String? deviceId, + @Query('audioCodec') String? audioCodec, + @Query('enableAutoStreamCopy') bool? enableAutoStreamCopy, + @Query('allowVideoStreamCopy') bool? allowVideoStreamCopy, + @Query('allowAudioStreamCopy') bool? allowAudioStreamCopy, + @Query('breakOnNonKeyFrames') bool? breakOnNonKeyFrames, + @Query('audioSampleRate') int? audioSampleRate, + @Query('maxAudioBitDepth') int? maxAudioBitDepth, + @Query('audioBitRate') int? audioBitRate, + @Query('audioChannels') int? audioChannels, + @Query('maxAudioChannels') int? maxAudioChannels, + @Query('profile') String? profile, + @Query('level') String? level, + @Query('framerate') num? framerate, + @Query('maxFramerate') num? maxFramerate, + @Query('copyTimestamps') bool? copyTimestamps, + @Query('startTimeTicks') int? startTimeTicks, + @Query('width') int? width, + @Query('height') int? height, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('videoBitRate') int? videoBitRate, + @Query('subtitleStreamIndex') int? subtitleStreamIndex, + @Query('subtitleMethod') String? subtitleMethod, + @Query('maxRefFrames') int? maxRefFrames, + @Query('maxVideoBitDepth') int? maxVideoBitDepth, + @Query('requireAvc') bool? requireAvc, + @Query('deInterlace') bool? deInterlace, + @Query('requireNonAnamorphic') bool? requireNonAnamorphic, + @Query('transcodingMaxAudioChannels') int? transcodingMaxAudioChannels, + @Query('cpuCoreLimit') int? cpuCoreLimit, + @Query('liveStreamId') String? liveStreamId, + @Query('enableMpegtsM2TsMode') bool? enableMpegtsM2TsMode, + @Query('videoCodec') String? videoCodec, + @Query('subtitleCodec') String? subtitleCodec, + @Query('transcodeReasons') String? transcodeReasons, + @Query('audioStreamIndex') int? audioStreamIndex, + @Query('videoStreamIndex') int? videoStreamIndex, + @Query('context') String? context, + @Query('streamOptions') Object? streamOptions, + }); + + ///Gets a video stream. + ///@param itemId The item id. + ///@param container The video container. Possible values are: ts, webm, asf, wmv, ogv, mp4, m4v, mkv, mpeg, mpg, avi, 3gp, wmv, wtv, m2ts, mov, iso, flv. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param maxWidth Optional. The maximum horizontal resolution of the encoded video. + ///@param maxHeight Optional. The maximum vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + Future> videosItemIdStreamContainerHead({ + required String? itemId, + required String? container, + bool? $static, + String? params, + String? tag, + String? deviceProfileId, + String? playSessionId, + String? segmentContainer, + int? segmentLength, + int? minSegments, + String? mediaSourceId, + String? deviceId, + String? audioCodec, + bool? enableAutoStreamCopy, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? breakOnNonKeyFrames, + int? audioSampleRate, + int? maxAudioBitDepth, + int? audioBitRate, + int? audioChannels, + int? maxAudioChannels, + String? profile, + String? level, + num? framerate, + num? maxFramerate, + bool? copyTimestamps, + int? startTimeTicks, + int? width, + int? height, + int? maxWidth, + int? maxHeight, + int? videoBitRate, + int? subtitleStreamIndex, + enums.VideosItemIdStreamContainerHeadSubtitleMethod? subtitleMethod, + int? maxRefFrames, + int? maxVideoBitDepth, + bool? requireAvc, + bool? deInterlace, + bool? requireNonAnamorphic, + int? transcodingMaxAudioChannels, + int? cpuCoreLimit, + String? liveStreamId, + bool? enableMpegtsM2TsMode, + String? videoCodec, + String? subtitleCodec, + String? transcodeReasons, + int? audioStreamIndex, + int? videoStreamIndex, + enums.VideosItemIdStreamContainerHeadContext? context, + Object? streamOptions, + }) { + return _videosItemIdStreamContainerHead( + itemId: itemId, + container: container, + $static: $static, + params: params, + tag: tag, + deviceProfileId: deviceProfileId, + playSessionId: playSessionId, + segmentContainer: segmentContainer, + segmentLength: segmentLength, + minSegments: minSegments, + mediaSourceId: mediaSourceId, + deviceId: deviceId, + audioCodec: audioCodec, + enableAutoStreamCopy: enableAutoStreamCopy, + allowVideoStreamCopy: allowVideoStreamCopy, + allowAudioStreamCopy: allowAudioStreamCopy, + breakOnNonKeyFrames: breakOnNonKeyFrames, + audioSampleRate: audioSampleRate, + maxAudioBitDepth: maxAudioBitDepth, + audioBitRate: audioBitRate, + audioChannels: audioChannels, + maxAudioChannels: maxAudioChannels, + profile: profile, + level: level, + framerate: framerate, + maxFramerate: maxFramerate, + copyTimestamps: copyTimestamps, + startTimeTicks: startTimeTicks, + width: width, + height: height, + maxWidth: maxWidth, + maxHeight: maxHeight, + videoBitRate: videoBitRate, + subtitleStreamIndex: subtitleStreamIndex, + subtitleMethod: subtitleMethod?.value?.toString(), + maxRefFrames: maxRefFrames, + maxVideoBitDepth: maxVideoBitDepth, + requireAvc: requireAvc, + deInterlace: deInterlace, + requireNonAnamorphic: requireNonAnamorphic, + transcodingMaxAudioChannels: transcodingMaxAudioChannels, + cpuCoreLimit: cpuCoreLimit, + liveStreamId: liveStreamId, + enableMpegtsM2TsMode: enableMpegtsM2TsMode, + videoCodec: videoCodec, + subtitleCodec: subtitleCodec, + transcodeReasons: transcodeReasons, + audioStreamIndex: audioStreamIndex, + videoStreamIndex: videoStreamIndex, + context: context?.value?.toString(), + streamOptions: streamOptions); + } + + ///Gets a video stream. + ///@param itemId The item id. + ///@param container The video container. Possible values are: ts, webm, asf, wmv, ogv, mp4, m4v, mkv, mpeg, mpg, avi, 3gp, wmv, wtv, m2ts, mov, iso, flv. + ///@param static Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + ///@param params The streaming parameters. + ///@param tag The tag. + ///@param deviceProfileId Optional. The dlna device profile id to utilize. + ///@param playSessionId The play session id. + ///@param segmentContainer The segment container. + ///@param segmentLength The segment length. + ///@param minSegments The minimum number of segments. + ///@param mediaSourceId The media version id, if playing an alternate version. + ///@param deviceId The device id of the client requesting. Used to stop encoding processes when needed. + ///@param audioCodec Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + ///@param enableAutoStreamCopy Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + ///@param allowVideoStreamCopy Whether or not to allow copying of the video stream url. + ///@param allowAudioStreamCopy Whether or not to allow copying of the audio stream url. + ///@param breakOnNonKeyFrames Optional. Whether to break on non key frames. + ///@param audioSampleRate Optional. Specify a specific audio sample rate, e.g. 44100. + ///@param maxAudioBitDepth Optional. The maximum audio bit depth. + ///@param audioBitRate Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + ///@param audioChannels Optional. Specify a specific number of audio channels to encode to, e.g. 2. + ///@param maxAudioChannels Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + ///@param profile Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + ///@param level Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + ///@param framerate Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param maxFramerate Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + ///@param copyTimestamps Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + ///@param startTimeTicks Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + ///@param width Optional. The fixed horizontal resolution of the encoded video. + ///@param height Optional. The fixed vertical resolution of the encoded video. + ///@param maxWidth Optional. The maximum horizontal resolution of the encoded video. + ///@param maxHeight Optional. The maximum vertical resolution of the encoded video. + ///@param videoBitRate Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + ///@param subtitleStreamIndex Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + ///@param subtitleMethod Optional. Specify the subtitle delivery method. + ///@param maxRefFrames Optional. + ///@param maxVideoBitDepth Optional. The maximum video bit depth. + ///@param requireAvc Optional. Whether to require avc. + ///@param deInterlace Optional. Whether to deinterlace the video. + ///@param requireNonAnamorphic Optional. Whether to require a non anamorphic stream. + ///@param transcodingMaxAudioChannels Optional. The maximum number of audio channels to transcode. + ///@param cpuCoreLimit Optional. The limit of how many cpu cores to use. + ///@param liveStreamId The live stream id. + ///@param enableMpegtsM2TsMode Optional. Whether to enable the MpegtsM2Ts mode. + ///@param videoCodec Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv. + ///@param subtitleCodec Optional. Specify a subtitle codec to encode to. + ///@param transcodeReasons Optional. The transcoding reason. + ///@param audioStreamIndex Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + ///@param videoStreamIndex Optional. The index of the video stream to use. If omitted the first video stream will be used. + ///@param context Optional. The MediaBrowser.Model.Dlna.EncodingContext. + ///@param streamOptions Optional. The streaming options. + @Head(path: '/Videos/{itemId}/stream.{container}') + Future> _videosItemIdStreamContainerHead({ + @Path('itemId') required String? itemId, + @Path('container') required String? container, + @Query('static') bool? $static, + @Query('params') String? params, + @Query('tag') String? tag, + @Query('deviceProfileId') String? deviceProfileId, + @Query('playSessionId') String? playSessionId, + @Query('segmentContainer') String? segmentContainer, + @Query('segmentLength') int? segmentLength, + @Query('minSegments') int? minSegments, + @Query('mediaSourceId') String? mediaSourceId, + @Query('deviceId') String? deviceId, + @Query('audioCodec') String? audioCodec, + @Query('enableAutoStreamCopy') bool? enableAutoStreamCopy, + @Query('allowVideoStreamCopy') bool? allowVideoStreamCopy, + @Query('allowAudioStreamCopy') bool? allowAudioStreamCopy, + @Query('breakOnNonKeyFrames') bool? breakOnNonKeyFrames, + @Query('audioSampleRate') int? audioSampleRate, + @Query('maxAudioBitDepth') int? maxAudioBitDepth, + @Query('audioBitRate') int? audioBitRate, + @Query('audioChannels') int? audioChannels, + @Query('maxAudioChannels') int? maxAudioChannels, + @Query('profile') String? profile, + @Query('level') String? level, + @Query('framerate') num? framerate, + @Query('maxFramerate') num? maxFramerate, + @Query('copyTimestamps') bool? copyTimestamps, + @Query('startTimeTicks') int? startTimeTicks, + @Query('width') int? width, + @Query('height') int? height, + @Query('maxWidth') int? maxWidth, + @Query('maxHeight') int? maxHeight, + @Query('videoBitRate') int? videoBitRate, + @Query('subtitleStreamIndex') int? subtitleStreamIndex, + @Query('subtitleMethod') String? subtitleMethod, + @Query('maxRefFrames') int? maxRefFrames, + @Query('maxVideoBitDepth') int? maxVideoBitDepth, + @Query('requireAvc') bool? requireAvc, + @Query('deInterlace') bool? deInterlace, + @Query('requireNonAnamorphic') bool? requireNonAnamorphic, + @Query('transcodingMaxAudioChannels') int? transcodingMaxAudioChannels, + @Query('cpuCoreLimit') int? cpuCoreLimit, + @Query('liveStreamId') String? liveStreamId, + @Query('enableMpegtsM2TsMode') bool? enableMpegtsM2TsMode, + @Query('videoCodec') String? videoCodec, + @Query('subtitleCodec') String? subtitleCodec, + @Query('transcodeReasons') String? transcodeReasons, + @Query('audioStreamIndex') int? audioStreamIndex, + @Query('videoStreamIndex') int? videoStreamIndex, + @Query('context') String? context, + @Query('streamOptions') Object? streamOptions, + }); + + ///Merges videos into a single record. + ///@param ids Item id list. This allows multiple, comma delimited. + Future videosMergeVersionsPost( + {required List? ids}) { + return _videosMergeVersionsPost(ids: ids); + } + + ///Merges videos into a single record. + ///@param ids Item id list. This allows multiple, comma delimited. + @Post( + path: '/Videos/MergeVersions', + optionalBody: true, + ) + Future _videosMergeVersionsPost( + {@Query('ids') required List? ids}); + + /// + ///@param id + Future>> introsEpisodeIdChromaprintGet( + {required String? id}) { + return _introsEpisodeIdChromaprintGet(id: id); + } + + /// + ///@param id + @Get(path: '/Intros/Episode/{Id}/Chromaprint') + Future>> _introsEpisodeIdChromaprintGet( + {@Path('id') required String? id}); + + /// + ///@param id + Future introsEpisodeIdUpdateIntroTimestampsPost({ + required String? id, + required Intro? body, + }) { + return _introsEpisodeIdUpdateIntroTimestampsPost(id: id, body: body); + } + + /// + ///@param id + @Post( + path: '/Intros/Episode/{Id}/UpdateIntroTimestamps', + optionalBody: true, + ) + Future _introsEpisodeIdUpdateIntroTimestampsPost({ + @Path('id') required String? id, + @Body() required Intro? body, + }); + + /// + ///@param series + ///@param season + Future>> + introsShowSeriesSeasonGet({ + required String? series, + required String? season, + }) { + generatedMapping.putIfAbsent( + EpisodeVisualization, () => EpisodeVisualization.fromJsonFactory); + + return _introsShowSeriesSeasonGet(series: series, season: season); + } + + /// + ///@param series + ///@param season + @Get(path: '/Intros/Show/{Series}/{Season}') + Future>> + _introsShowSeriesSeasonGet({ + @Path('series') required String? series, + @Path('season') required String? season, + }); + + /// + ///@param series + ///@param season + ///@param eraseCache + Future introsShowSeriesSeasonDelete({ + required String? series, + required String? season, + bool? eraseCache, + }) { + return _introsShowSeriesSeasonDelete( + series: series, season: season, eraseCache: eraseCache); + } + + /// + ///@param series + ///@param season + ///@param eraseCache + @Delete(path: '/Intros/Show/{Series}/{Season}') + Future _introsShowSeriesSeasonDelete({ + @Path('series') required String? series, + @Path('season') required String? season, + @Query('eraseCache') bool? eraseCache, + }); + + /// + Future> introsShowsGet() { + return _introsShowsGet(); + } + + /// + @Get(path: '/Intros/Shows') + Future> _introsShowsGet(); + + ///Get years. + ///@param startIndex Skips over a given number of items within the results. Use for paging. + ///@param limit Optional. The maximum number of records to return. + ///@param sortOrder Sort Order - Ascending,Descending. + ///@param parentId Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param excludeItemTypes Optional. If specified, results will be excluded based on item type. This allows multiple, comma delimited. + ///@param includeItemTypes Optional. If specified, results will be included based on item type. This allows multiple, comma delimited. + ///@param mediaTypes Optional. Filter by MediaType. Allows multiple, comma delimited. + ///@param sortBy Optional. Specify one or more sort orders, comma delimited. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime. + ///@param enableUserData Optional. Include user data. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param userId User Id. + ///@param recursive Search recursively. + ///@param enableImages Optional. Include image information in output. + Future> yearsGet({ + int? startIndex, + int? limit, + List? sortOrder, + String? parentId, + List? fields, + List? excludeItemTypes, + List? includeItemTypes, + List? mediaTypes, + List? sortBy, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + String? userId, + bool? recursive, + bool? enableImages, + }) { + generatedMapping.putIfAbsent( + BaseItemDtoQueryResult, () => BaseItemDtoQueryResult.fromJsonFactory); + + return _yearsGet( + startIndex: startIndex, + limit: limit, + sortOrder: sortOrderListToJson(sortOrder), + parentId: parentId, + fields: itemFieldsListToJson(fields), + excludeItemTypes: baseItemKindListToJson(excludeItemTypes), + includeItemTypes: baseItemKindListToJson(includeItemTypes), + mediaTypes: mediaTypeListToJson(mediaTypes), + sortBy: itemSortByListToJson(sortBy), + enableUserData: enableUserData, + imageTypeLimit: imageTypeLimit, + enableImageTypes: imageTypeListToJson(enableImageTypes), + userId: userId, + recursive: recursive, + enableImages: enableImages); + } + + ///Get years. + ///@param startIndex Skips over a given number of items within the results. Use for paging. + ///@param limit Optional. The maximum number of records to return. + ///@param sortOrder Sort Order - Ascending,Descending. + ///@param parentId Specify this to localize the search to a specific item or folder. Omit to use the root. + ///@param fields Optional. Specify additional fields of information to return in the output. + ///@param excludeItemTypes Optional. If specified, results will be excluded based on item type. This allows multiple, comma delimited. + ///@param includeItemTypes Optional. If specified, results will be included based on item type. This allows multiple, comma delimited. + ///@param mediaTypes Optional. Filter by MediaType. Allows multiple, comma delimited. + ///@param sortBy Optional. Specify one or more sort orders, comma delimited. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime. + ///@param enableUserData Optional. Include user data. + ///@param imageTypeLimit Optional. The max number of images to return, per image type. + ///@param enableImageTypes Optional. The image types to include in the output. + ///@param userId User Id. + ///@param recursive Search recursively. + ///@param enableImages Optional. Include image information in output. + @Get(path: '/Years') + Future> _yearsGet({ + @Query('startIndex') int? startIndex, + @Query('limit') int? limit, + @Query('sortOrder') List? sortOrder, + @Query('parentId') String? parentId, + @Query('fields') List? fields, + @Query('excludeItemTypes') List? excludeItemTypes, + @Query('includeItemTypes') List? includeItemTypes, + @Query('mediaTypes') List? mediaTypes, + @Query('sortBy') List? sortBy, + @Query('enableUserData') bool? enableUserData, + @Query('imageTypeLimit') int? imageTypeLimit, + @Query('enableImageTypes') List? enableImageTypes, + @Query('userId') String? userId, + @Query('recursive') bool? recursive, + @Query('enableImages') bool? enableImages, + }); + + ///Gets a year. + ///@param year The year. + ///@param userId Optional. Filter by user id, and attach user data. + Future> yearsYearGet({ + required int? year, + String? userId, + }) { + generatedMapping.putIfAbsent( + BaseItemDto, () => BaseItemDto.fromJsonFactory); + + return _yearsYearGet(year: year, userId: userId); + } + + ///Gets a year. + ///@param year The year. + ///@param userId Optional. Filter by user id, and attach user data. + @Get(path: '/Years/{year}') + Future> _yearsYearGet({ + @Path('year') required int? year, + @Query('userId') String? userId, + }); +} + +@JsonSerializable(explicitToJson: true) +class AccessSchedule { + const AccessSchedule({ + this.id, + this.userId, + this.dayOfWeek, + this.startHour, + this.endHour, + }); + + factory AccessSchedule.fromJson(Map json) => + _$AccessScheduleFromJson(json); + + static const toJsonFactory = _$AccessScheduleToJson; + Map toJson() => _$AccessScheduleToJson(this); + + @JsonKey(name: 'Id', includeIfNull: false) + final int? id; + @JsonKey(name: 'UserId', includeIfNull: false) + final String? userId; + @JsonKey( + name: 'DayOfWeek', + includeIfNull: false, + toJson: dynamicDayOfWeekNullableToJson, + fromJson: dynamicDayOfWeekNullableFromJson, + ) + final enums.DynamicDayOfWeek? dayOfWeek; + @JsonKey(name: 'StartHour', includeIfNull: false) + final double? startHour; + @JsonKey(name: 'EndHour', includeIfNull: false) + final double? endHour; + static const fromJsonFactory = _$AccessScheduleFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is AccessSchedule && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.userId, userId) || + const DeepCollectionEquality().equals(other.userId, userId)) && + (identical(other.dayOfWeek, dayOfWeek) || + const DeepCollectionEquality() + .equals(other.dayOfWeek, dayOfWeek)) && + (identical(other.startHour, startHour) || + const DeepCollectionEquality() + .equals(other.startHour, startHour)) && + (identical(other.endHour, endHour) || + const DeepCollectionEquality().equals(other.endHour, endHour))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(userId) ^ + const DeepCollectionEquality().hash(dayOfWeek) ^ + const DeepCollectionEquality().hash(startHour) ^ + const DeepCollectionEquality().hash(endHour) ^ + runtimeType.hashCode; +} + +extension $AccessScheduleExtension on AccessSchedule { + AccessSchedule copyWith( + {int? id, + String? userId, + enums.DynamicDayOfWeek? dayOfWeek, + double? startHour, + double? endHour}) { + return AccessSchedule( + id: id ?? this.id, + userId: userId ?? this.userId, + dayOfWeek: dayOfWeek ?? this.dayOfWeek, + startHour: startHour ?? this.startHour, + endHour: endHour ?? this.endHour); + } + + AccessSchedule copyWithWrapped( + {Wrapped? id, + Wrapped? userId, + Wrapped? dayOfWeek, + Wrapped? startHour, + Wrapped? endHour}) { + return AccessSchedule( + id: (id != null ? id.value : this.id), + userId: (userId != null ? userId.value : this.userId), + dayOfWeek: (dayOfWeek != null ? dayOfWeek.value : this.dayOfWeek), + startHour: (startHour != null ? startHour.value : this.startHour), + endHour: (endHour != null ? endHour.value : this.endHour)); + } +} + +@JsonSerializable(explicitToJson: true) +class ActivityLogEntry { + const ActivityLogEntry({ + this.id, + this.name, + this.overview, + this.shortOverview, + this.type, + this.itemId, + this.date, + this.userId, + this.userPrimaryImageTag, + this.severity, + }); + + factory ActivityLogEntry.fromJson(Map json) => + _$ActivityLogEntryFromJson(json); + + static const toJsonFactory = _$ActivityLogEntryToJson; + Map toJson() => _$ActivityLogEntryToJson(this); + + @JsonKey(name: 'Id', includeIfNull: false) + final int? id; + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'Overview', includeIfNull: false) + final String? overview; + @JsonKey(name: 'ShortOverview', includeIfNull: false) + final String? shortOverview; + @JsonKey(name: 'Type', includeIfNull: false) + final String? type; + @JsonKey(name: 'ItemId', includeIfNull: false) + final String? itemId; + @JsonKey(name: 'Date', includeIfNull: false) + final DateTime? date; + @JsonKey(name: 'UserId', includeIfNull: false) + final String? userId; + @JsonKey(name: 'UserPrimaryImageTag', includeIfNull: false) + @deprecated + final String? userPrimaryImageTag; + @JsonKey( + name: 'Severity', + includeIfNull: false, + toJson: logLevelNullableToJson, + fromJson: logLevelNullableFromJson, + ) + final enums.LogLevel? severity; + static const fromJsonFactory = _$ActivityLogEntryFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ActivityLogEntry && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.overview, overview) || + const DeepCollectionEquality() + .equals(other.overview, overview)) && + (identical(other.shortOverview, shortOverview) || + const DeepCollectionEquality() + .equals(other.shortOverview, shortOverview)) && + (identical(other.type, type) || + const DeepCollectionEquality().equals(other.type, type)) && + (identical(other.itemId, itemId) || + const DeepCollectionEquality().equals(other.itemId, itemId)) && + (identical(other.date, date) || + const DeepCollectionEquality().equals(other.date, date)) && + (identical(other.userId, userId) || + const DeepCollectionEquality().equals(other.userId, userId)) && + (identical(other.userPrimaryImageTag, userPrimaryImageTag) || + const DeepCollectionEquality() + .equals(other.userPrimaryImageTag, userPrimaryImageTag)) && + (identical(other.severity, severity) || + const DeepCollectionEquality() + .equals(other.severity, severity))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(overview) ^ + const DeepCollectionEquality().hash(shortOverview) ^ + const DeepCollectionEquality().hash(type) ^ + const DeepCollectionEquality().hash(itemId) ^ + const DeepCollectionEquality().hash(date) ^ + const DeepCollectionEquality().hash(userId) ^ + const DeepCollectionEquality().hash(userPrimaryImageTag) ^ + const DeepCollectionEquality().hash(severity) ^ + runtimeType.hashCode; +} + +extension $ActivityLogEntryExtension on ActivityLogEntry { + ActivityLogEntry copyWith( + {int? id, + String? name, + String? overview, + String? shortOverview, + String? type, + String? itemId, + DateTime? date, + String? userId, + String? userPrimaryImageTag, + enums.LogLevel? severity}) { + return ActivityLogEntry( + id: id ?? this.id, + name: name ?? this.name, + overview: overview ?? this.overview, + shortOverview: shortOverview ?? this.shortOverview, + type: type ?? this.type, + itemId: itemId ?? this.itemId, + date: date ?? this.date, + userId: userId ?? this.userId, + userPrimaryImageTag: userPrimaryImageTag ?? this.userPrimaryImageTag, + severity: severity ?? this.severity); + } + + ActivityLogEntry copyWithWrapped( + {Wrapped? id, + Wrapped? name, + Wrapped? overview, + Wrapped? shortOverview, + Wrapped? type, + Wrapped? itemId, + Wrapped? date, + Wrapped? userId, + Wrapped? userPrimaryImageTag, + Wrapped? severity}) { + return ActivityLogEntry( + id: (id != null ? id.value : this.id), + name: (name != null ? name.value : this.name), + overview: (overview != null ? overview.value : this.overview), + shortOverview: + (shortOverview != null ? shortOverview.value : this.shortOverview), + type: (type != null ? type.value : this.type), + itemId: (itemId != null ? itemId.value : this.itemId), + date: (date != null ? date.value : this.date), + userId: (userId != null ? userId.value : this.userId), + userPrimaryImageTag: (userPrimaryImageTag != null + ? userPrimaryImageTag.value + : this.userPrimaryImageTag), + severity: (severity != null ? severity.value : this.severity)); + } +} + +@JsonSerializable(explicitToJson: true) +class ActivityLogEntryMessage { + const ActivityLogEntryMessage({ + this.data, + this.messageId, + this.messageType, + }); + + factory ActivityLogEntryMessage.fromJson(Map json) => + _$ActivityLogEntryMessageFromJson(json); + + static const toJsonFactory = _$ActivityLogEntryMessageToJson; + Map toJson() => _$ActivityLogEntryMessageToJson(this); + + @JsonKey( + name: 'Data', includeIfNull: false, defaultValue: []) + final List? data; + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.activitylogentry); + + static const fromJsonFactory = _$ActivityLogEntryMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ActivityLogEntryMessage && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data)) && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(data) ^ + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $ActivityLogEntryMessageExtension on ActivityLogEntryMessage { + ActivityLogEntryMessage copyWith( + {List? data, + String? messageId, + enums.SessionMessageType? messageType}) { + return ActivityLogEntryMessage( + data: data ?? this.data, + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + ActivityLogEntryMessage copyWithWrapped( + {Wrapped?>? data, + Wrapped? messageId, + Wrapped? messageType}) { + return ActivityLogEntryMessage( + data: (data != null ? data.value : this.data), + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class ActivityLogEntryQueryResult { + const ActivityLogEntryQueryResult({ + this.items, + this.totalRecordCount, + this.startIndex, + }); + + factory ActivityLogEntryQueryResult.fromJson(Map json) => + _$ActivityLogEntryQueryResultFromJson(json); + + static const toJsonFactory = _$ActivityLogEntryQueryResultToJson; + Map toJson() => _$ActivityLogEntryQueryResultToJson(this); + + @JsonKey( + name: 'Items', includeIfNull: false, defaultValue: []) + final List? items; + @JsonKey(name: 'TotalRecordCount', includeIfNull: false) + final int? totalRecordCount; + @JsonKey(name: 'StartIndex', includeIfNull: false) + final int? startIndex; + static const fromJsonFactory = _$ActivityLogEntryQueryResultFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ActivityLogEntryQueryResult && + (identical(other.items, items) || + const DeepCollectionEquality().equals(other.items, items)) && + (identical(other.totalRecordCount, totalRecordCount) || + const DeepCollectionEquality() + .equals(other.totalRecordCount, totalRecordCount)) && + (identical(other.startIndex, startIndex) || + const DeepCollectionEquality() + .equals(other.startIndex, startIndex))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(items) ^ + const DeepCollectionEquality().hash(totalRecordCount) ^ + const DeepCollectionEquality().hash(startIndex) ^ + runtimeType.hashCode; +} + +extension $ActivityLogEntryQueryResultExtension on ActivityLogEntryQueryResult { + ActivityLogEntryQueryResult copyWith( + {List? items, int? totalRecordCount, int? startIndex}) { + return ActivityLogEntryQueryResult( + items: items ?? this.items, + totalRecordCount: totalRecordCount ?? this.totalRecordCount, + startIndex: startIndex ?? this.startIndex); + } + + ActivityLogEntryQueryResult copyWithWrapped( + {Wrapped?>? items, + Wrapped? totalRecordCount, + Wrapped? startIndex}) { + return ActivityLogEntryQueryResult( + items: (items != null ? items.value : this.items), + totalRecordCount: (totalRecordCount != null + ? totalRecordCount.value + : this.totalRecordCount), + startIndex: (startIndex != null ? startIndex.value : this.startIndex)); + } +} + +@JsonSerializable(explicitToJson: true) +class ActivityLogEntryStartMessage { + const ActivityLogEntryStartMessage({ + this.data, + this.messageType, + }); + + factory ActivityLogEntryStartMessage.fromJson(Map json) => + _$ActivityLogEntryStartMessageFromJson(json); + + static const toJsonFactory = _$ActivityLogEntryStartMessageToJson; + Map toJson() => _$ActivityLogEntryStartMessageToJson(this); + + @JsonKey(name: 'Data', includeIfNull: false) + final String? data; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.activitylogentrystart); + + static const fromJsonFactory = _$ActivityLogEntryStartMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ActivityLogEntryStartMessage && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(data) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $ActivityLogEntryStartMessageExtension + on ActivityLogEntryStartMessage { + ActivityLogEntryStartMessage copyWith( + {String? data, enums.SessionMessageType? messageType}) { + return ActivityLogEntryStartMessage( + data: data ?? this.data, messageType: messageType ?? this.messageType); + } + + ActivityLogEntryStartMessage copyWithWrapped( + {Wrapped? data, + Wrapped? messageType}) { + return ActivityLogEntryStartMessage( + data: (data != null ? data.value : this.data), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class ActivityLogEntryStopMessage { + const ActivityLogEntryStopMessage({ + this.messageType, + }); + + factory ActivityLogEntryStopMessage.fromJson(Map json) => + _$ActivityLogEntryStopMessageFromJson(json); + + static const toJsonFactory = _$ActivityLogEntryStopMessageToJson; + Map toJson() => _$ActivityLogEntryStopMessageToJson(this); + + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.activitylogentrystop); + + static const fromJsonFactory = _$ActivityLogEntryStopMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ActivityLogEntryStopMessage && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(messageType) ^ runtimeType.hashCode; +} + +extension $ActivityLogEntryStopMessageExtension on ActivityLogEntryStopMessage { + ActivityLogEntryStopMessage copyWith( + {enums.SessionMessageType? messageType}) { + return ActivityLogEntryStopMessage( + messageType: messageType ?? this.messageType); + } + + ActivityLogEntryStopMessage copyWithWrapped( + {Wrapped? messageType}) { + return ActivityLogEntryStopMessage( + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class AddVirtualFolderDto { + const AddVirtualFolderDto({ + this.libraryOptions, + }); + + factory AddVirtualFolderDto.fromJson(Map json) => + _$AddVirtualFolderDtoFromJson(json); + + static const toJsonFactory = _$AddVirtualFolderDtoToJson; + Map toJson() => _$AddVirtualFolderDtoToJson(this); + + @JsonKey(name: 'LibraryOptions', includeIfNull: false) + final LibraryOptions? libraryOptions; + static const fromJsonFactory = _$AddVirtualFolderDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is AddVirtualFolderDto && + (identical(other.libraryOptions, libraryOptions) || + const DeepCollectionEquality() + .equals(other.libraryOptions, libraryOptions))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(libraryOptions) ^ + runtimeType.hashCode; +} + +extension $AddVirtualFolderDtoExtension on AddVirtualFolderDto { + AddVirtualFolderDto copyWith({LibraryOptions? libraryOptions}) { + return AddVirtualFolderDto( + libraryOptions: libraryOptions ?? this.libraryOptions); + } + + AddVirtualFolderDto copyWithWrapped( + {Wrapped? libraryOptions}) { + return AddVirtualFolderDto( + libraryOptions: (libraryOptions != null + ? libraryOptions.value + : this.libraryOptions)); + } +} + +@JsonSerializable(explicitToJson: true) +class AlbumInfo { + const AlbumInfo({ + this.name, + this.originalTitle, + this.path, + this.metadataLanguage, + this.metadataCountryCode, + this.providerIds, + this.year, + this.indexNumber, + this.parentIndexNumber, + this.premiereDate, + this.isAutomated, + this.albumArtists, + this.artistProviderIds, + this.songInfos, + }); + + factory AlbumInfo.fromJson(Map json) => + _$AlbumInfoFromJson(json); + + static const toJsonFactory = _$AlbumInfoToJson; + Map toJson() => _$AlbumInfoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'OriginalTitle', includeIfNull: false) + final String? originalTitle; + @JsonKey(name: 'Path', includeIfNull: false) + final String? path; + @JsonKey(name: 'MetadataLanguage', includeIfNull: false) + final String? metadataLanguage; + @JsonKey(name: 'MetadataCountryCode', includeIfNull: false) + final String? metadataCountryCode; + @JsonKey(name: 'ProviderIds', includeIfNull: false) + final Map? providerIds; + @JsonKey(name: 'Year', includeIfNull: false) + final int? year; + @JsonKey(name: 'IndexNumber', includeIfNull: false) + final int? indexNumber; + @JsonKey(name: 'ParentIndexNumber', includeIfNull: false) + final int? parentIndexNumber; + @JsonKey(name: 'PremiereDate', includeIfNull: false) + final DateTime? premiereDate; + @JsonKey(name: 'IsAutomated', includeIfNull: false) + final bool? isAutomated; + @JsonKey(name: 'AlbumArtists', includeIfNull: false, defaultValue: []) + final List? albumArtists; + @JsonKey(name: 'ArtistProviderIds', includeIfNull: false) + final Map? artistProviderIds; + @JsonKey(name: 'SongInfos', includeIfNull: false, defaultValue: []) + final List? songInfos; + static const fromJsonFactory = _$AlbumInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is AlbumInfo && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.originalTitle, originalTitle) || + const DeepCollectionEquality() + .equals(other.originalTitle, originalTitle)) && + (identical(other.path, path) || + const DeepCollectionEquality().equals(other.path, path)) && + (identical(other.metadataLanguage, metadataLanguage) || + const DeepCollectionEquality() + .equals(other.metadataLanguage, metadataLanguage)) && + (identical(other.metadataCountryCode, metadataCountryCode) || + const DeepCollectionEquality() + .equals(other.metadataCountryCode, metadataCountryCode)) && + (identical(other.providerIds, providerIds) || + const DeepCollectionEquality() + .equals(other.providerIds, providerIds)) && + (identical(other.year, year) || + const DeepCollectionEquality().equals(other.year, year)) && + (identical(other.indexNumber, indexNumber) || + const DeepCollectionEquality() + .equals(other.indexNumber, indexNumber)) && + (identical(other.parentIndexNumber, parentIndexNumber) || + const DeepCollectionEquality() + .equals(other.parentIndexNumber, parentIndexNumber)) && + (identical(other.premiereDate, premiereDate) || + const DeepCollectionEquality() + .equals(other.premiereDate, premiereDate)) && + (identical(other.isAutomated, isAutomated) || + const DeepCollectionEquality() + .equals(other.isAutomated, isAutomated)) && + (identical(other.albumArtists, albumArtists) || + const DeepCollectionEquality() + .equals(other.albumArtists, albumArtists)) && + (identical(other.artistProviderIds, artistProviderIds) || + const DeepCollectionEquality() + .equals(other.artistProviderIds, artistProviderIds)) && + (identical(other.songInfos, songInfos) || + const DeepCollectionEquality() + .equals(other.songInfos, songInfos))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(originalTitle) ^ + const DeepCollectionEquality().hash(path) ^ + const DeepCollectionEquality().hash(metadataLanguage) ^ + const DeepCollectionEquality().hash(metadataCountryCode) ^ + const DeepCollectionEquality().hash(providerIds) ^ + const DeepCollectionEquality().hash(year) ^ + const DeepCollectionEquality().hash(indexNumber) ^ + const DeepCollectionEquality().hash(parentIndexNumber) ^ + const DeepCollectionEquality().hash(premiereDate) ^ + const DeepCollectionEquality().hash(isAutomated) ^ + const DeepCollectionEquality().hash(albumArtists) ^ + const DeepCollectionEquality().hash(artistProviderIds) ^ + const DeepCollectionEquality().hash(songInfos) ^ + runtimeType.hashCode; +} + +extension $AlbumInfoExtension on AlbumInfo { + AlbumInfo copyWith( + {String? name, + String? originalTitle, + String? path, + String? metadataLanguage, + String? metadataCountryCode, + Map? providerIds, + int? year, + int? indexNumber, + int? parentIndexNumber, + DateTime? premiereDate, + bool? isAutomated, + List? albumArtists, + Map? artistProviderIds, + List? songInfos}) { + return AlbumInfo( + name: name ?? this.name, + originalTitle: originalTitle ?? this.originalTitle, + path: path ?? this.path, + metadataLanguage: metadataLanguage ?? this.metadataLanguage, + metadataCountryCode: metadataCountryCode ?? this.metadataCountryCode, + providerIds: providerIds ?? this.providerIds, + year: year ?? this.year, + indexNumber: indexNumber ?? this.indexNumber, + parentIndexNumber: parentIndexNumber ?? this.parentIndexNumber, + premiereDate: premiereDate ?? this.premiereDate, + isAutomated: isAutomated ?? this.isAutomated, + albumArtists: albumArtists ?? this.albumArtists, + artistProviderIds: artistProviderIds ?? this.artistProviderIds, + songInfos: songInfos ?? this.songInfos); + } + + AlbumInfo copyWithWrapped( + {Wrapped? name, + Wrapped? originalTitle, + Wrapped? path, + Wrapped? metadataLanguage, + Wrapped? metadataCountryCode, + Wrapped?>? providerIds, + Wrapped? year, + Wrapped? indexNumber, + Wrapped? parentIndexNumber, + Wrapped? premiereDate, + Wrapped? isAutomated, + Wrapped?>? albumArtists, + Wrapped?>? artistProviderIds, + Wrapped?>? songInfos}) { + return AlbumInfo( + name: (name != null ? name.value : this.name), + originalTitle: + (originalTitle != null ? originalTitle.value : this.originalTitle), + path: (path != null ? path.value : this.path), + metadataLanguage: (metadataLanguage != null + ? metadataLanguage.value + : this.metadataLanguage), + metadataCountryCode: (metadataCountryCode != null + ? metadataCountryCode.value + : this.metadataCountryCode), + providerIds: + (providerIds != null ? providerIds.value : this.providerIds), + year: (year != null ? year.value : this.year), + indexNumber: + (indexNumber != null ? indexNumber.value : this.indexNumber), + parentIndexNumber: (parentIndexNumber != null + ? parentIndexNumber.value + : this.parentIndexNumber), + premiereDate: + (premiereDate != null ? premiereDate.value : this.premiereDate), + isAutomated: + (isAutomated != null ? isAutomated.value : this.isAutomated), + albumArtists: + (albumArtists != null ? albumArtists.value : this.albumArtists), + artistProviderIds: (artistProviderIds != null + ? artistProviderIds.value + : this.artistProviderIds), + songInfos: (songInfos != null ? songInfos.value : this.songInfos)); + } +} + +@JsonSerializable(explicitToJson: true) +class AlbumInfoRemoteSearchQuery { + const AlbumInfoRemoteSearchQuery({ + this.searchInfo, + this.itemId, + this.searchProviderName, + this.includeDisabledProviders, + }); + + factory AlbumInfoRemoteSearchQuery.fromJson(Map json) => + _$AlbumInfoRemoteSearchQueryFromJson(json); + + static const toJsonFactory = _$AlbumInfoRemoteSearchQueryToJson; + Map toJson() => _$AlbumInfoRemoteSearchQueryToJson(this); + + @JsonKey(name: 'SearchInfo', includeIfNull: false) + final AlbumInfo? searchInfo; + @JsonKey(name: 'ItemId', includeIfNull: false) + final String? itemId; + @JsonKey(name: 'SearchProviderName', includeIfNull: false) + final String? searchProviderName; + @JsonKey(name: 'IncludeDisabledProviders', includeIfNull: false) + final bool? includeDisabledProviders; + static const fromJsonFactory = _$AlbumInfoRemoteSearchQueryFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is AlbumInfoRemoteSearchQuery && + (identical(other.searchInfo, searchInfo) || + const DeepCollectionEquality() + .equals(other.searchInfo, searchInfo)) && + (identical(other.itemId, itemId) || + const DeepCollectionEquality().equals(other.itemId, itemId)) && + (identical(other.searchProviderName, searchProviderName) || + const DeepCollectionEquality() + .equals(other.searchProviderName, searchProviderName)) && + (identical( + other.includeDisabledProviders, includeDisabledProviders) || + const DeepCollectionEquality().equals( + other.includeDisabledProviders, includeDisabledProviders))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(searchInfo) ^ + const DeepCollectionEquality().hash(itemId) ^ + const DeepCollectionEquality().hash(searchProviderName) ^ + const DeepCollectionEquality().hash(includeDisabledProviders) ^ + runtimeType.hashCode; +} + +extension $AlbumInfoRemoteSearchQueryExtension on AlbumInfoRemoteSearchQuery { + AlbumInfoRemoteSearchQuery copyWith( + {AlbumInfo? searchInfo, + String? itemId, + String? searchProviderName, + bool? includeDisabledProviders}) { + return AlbumInfoRemoteSearchQuery( + searchInfo: searchInfo ?? this.searchInfo, + itemId: itemId ?? this.itemId, + searchProviderName: searchProviderName ?? this.searchProviderName, + includeDisabledProviders: + includeDisabledProviders ?? this.includeDisabledProviders); + } + + AlbumInfoRemoteSearchQuery copyWithWrapped( + {Wrapped? searchInfo, + Wrapped? itemId, + Wrapped? searchProviderName, + Wrapped? includeDisabledProviders}) { + return AlbumInfoRemoteSearchQuery( + searchInfo: (searchInfo != null ? searchInfo.value : this.searchInfo), + itemId: (itemId != null ? itemId.value : this.itemId), + searchProviderName: (searchProviderName != null + ? searchProviderName.value + : this.searchProviderName), + includeDisabledProviders: (includeDisabledProviders != null + ? includeDisabledProviders.value + : this.includeDisabledProviders)); + } +} + +@JsonSerializable(explicitToJson: true) +class AllThemeMediaResult { + const AllThemeMediaResult({ + this.themeVideosResult, + this.themeSongsResult, + this.soundtrackSongsResult, + }); + + factory AllThemeMediaResult.fromJson(Map json) => + _$AllThemeMediaResultFromJson(json); + + static const toJsonFactory = _$AllThemeMediaResultToJson; + Map toJson() => _$AllThemeMediaResultToJson(this); + + @JsonKey(name: 'ThemeVideosResult', includeIfNull: false) + final ThemeMediaResult? themeVideosResult; + @JsonKey(name: 'ThemeSongsResult', includeIfNull: false) + final ThemeMediaResult? themeSongsResult; + @JsonKey(name: 'SoundtrackSongsResult', includeIfNull: false) + final ThemeMediaResult? soundtrackSongsResult; + static const fromJsonFactory = _$AllThemeMediaResultFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is AllThemeMediaResult && + (identical(other.themeVideosResult, themeVideosResult) || + const DeepCollectionEquality() + .equals(other.themeVideosResult, themeVideosResult)) && + (identical(other.themeSongsResult, themeSongsResult) || + const DeepCollectionEquality() + .equals(other.themeSongsResult, themeSongsResult)) && + (identical(other.soundtrackSongsResult, soundtrackSongsResult) || + const DeepCollectionEquality().equals( + other.soundtrackSongsResult, soundtrackSongsResult))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(themeVideosResult) ^ + const DeepCollectionEquality().hash(themeSongsResult) ^ + const DeepCollectionEquality().hash(soundtrackSongsResult) ^ + runtimeType.hashCode; +} + +extension $AllThemeMediaResultExtension on AllThemeMediaResult { + AllThemeMediaResult copyWith( + {ThemeMediaResult? themeVideosResult, + ThemeMediaResult? themeSongsResult, + ThemeMediaResult? soundtrackSongsResult}) { + return AllThemeMediaResult( + themeVideosResult: themeVideosResult ?? this.themeVideosResult, + themeSongsResult: themeSongsResult ?? this.themeSongsResult, + soundtrackSongsResult: + soundtrackSongsResult ?? this.soundtrackSongsResult); + } + + AllThemeMediaResult copyWithWrapped( + {Wrapped? themeVideosResult, + Wrapped? themeSongsResult, + Wrapped? soundtrackSongsResult}) { + return AllThemeMediaResult( + themeVideosResult: (themeVideosResult != null + ? themeVideosResult.value + : this.themeVideosResult), + themeSongsResult: (themeSongsResult != null + ? themeSongsResult.value + : this.themeSongsResult), + soundtrackSongsResult: (soundtrackSongsResult != null + ? soundtrackSongsResult.value + : this.soundtrackSongsResult)); + } +} + +@JsonSerializable(explicitToJson: true) +class ArtistInfo { + const ArtistInfo({ + this.name, + this.originalTitle, + this.path, + this.metadataLanguage, + this.metadataCountryCode, + this.providerIds, + this.year, + this.indexNumber, + this.parentIndexNumber, + this.premiereDate, + this.isAutomated, + this.songInfos, + }); + + factory ArtistInfo.fromJson(Map json) => + _$ArtistInfoFromJson(json); + + static const toJsonFactory = _$ArtistInfoToJson; + Map toJson() => _$ArtistInfoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'OriginalTitle', includeIfNull: false) + final String? originalTitle; + @JsonKey(name: 'Path', includeIfNull: false) + final String? path; + @JsonKey(name: 'MetadataLanguage', includeIfNull: false) + final String? metadataLanguage; + @JsonKey(name: 'MetadataCountryCode', includeIfNull: false) + final String? metadataCountryCode; + @JsonKey(name: 'ProviderIds', includeIfNull: false) + final Map? providerIds; + @JsonKey(name: 'Year', includeIfNull: false) + final int? year; + @JsonKey(name: 'IndexNumber', includeIfNull: false) + final int? indexNumber; + @JsonKey(name: 'ParentIndexNumber', includeIfNull: false) + final int? parentIndexNumber; + @JsonKey(name: 'PremiereDate', includeIfNull: false) + final DateTime? premiereDate; + @JsonKey(name: 'IsAutomated', includeIfNull: false) + final bool? isAutomated; + @JsonKey(name: 'SongInfos', includeIfNull: false, defaultValue: []) + final List? songInfos; + static const fromJsonFactory = _$ArtistInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ArtistInfo && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.originalTitle, originalTitle) || + const DeepCollectionEquality() + .equals(other.originalTitle, originalTitle)) && + (identical(other.path, path) || + const DeepCollectionEquality().equals(other.path, path)) && + (identical(other.metadataLanguage, metadataLanguage) || + const DeepCollectionEquality() + .equals(other.metadataLanguage, metadataLanguage)) && + (identical(other.metadataCountryCode, metadataCountryCode) || + const DeepCollectionEquality() + .equals(other.metadataCountryCode, metadataCountryCode)) && + (identical(other.providerIds, providerIds) || + const DeepCollectionEquality() + .equals(other.providerIds, providerIds)) && + (identical(other.year, year) || + const DeepCollectionEquality().equals(other.year, year)) && + (identical(other.indexNumber, indexNumber) || + const DeepCollectionEquality() + .equals(other.indexNumber, indexNumber)) && + (identical(other.parentIndexNumber, parentIndexNumber) || + const DeepCollectionEquality() + .equals(other.parentIndexNumber, parentIndexNumber)) && + (identical(other.premiereDate, premiereDate) || + const DeepCollectionEquality() + .equals(other.premiereDate, premiereDate)) && + (identical(other.isAutomated, isAutomated) || + const DeepCollectionEquality() + .equals(other.isAutomated, isAutomated)) && + (identical(other.songInfos, songInfos) || + const DeepCollectionEquality() + .equals(other.songInfos, songInfos))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(originalTitle) ^ + const DeepCollectionEquality().hash(path) ^ + const DeepCollectionEquality().hash(metadataLanguage) ^ + const DeepCollectionEquality().hash(metadataCountryCode) ^ + const DeepCollectionEquality().hash(providerIds) ^ + const DeepCollectionEquality().hash(year) ^ + const DeepCollectionEquality().hash(indexNumber) ^ + const DeepCollectionEquality().hash(parentIndexNumber) ^ + const DeepCollectionEquality().hash(premiereDate) ^ + const DeepCollectionEquality().hash(isAutomated) ^ + const DeepCollectionEquality().hash(songInfos) ^ + runtimeType.hashCode; +} + +extension $ArtistInfoExtension on ArtistInfo { + ArtistInfo copyWith( + {String? name, + String? originalTitle, + String? path, + String? metadataLanguage, + String? metadataCountryCode, + Map? providerIds, + int? year, + int? indexNumber, + int? parentIndexNumber, + DateTime? premiereDate, + bool? isAutomated, + List? songInfos}) { + return ArtistInfo( + name: name ?? this.name, + originalTitle: originalTitle ?? this.originalTitle, + path: path ?? this.path, + metadataLanguage: metadataLanguage ?? this.metadataLanguage, + metadataCountryCode: metadataCountryCode ?? this.metadataCountryCode, + providerIds: providerIds ?? this.providerIds, + year: year ?? this.year, + indexNumber: indexNumber ?? this.indexNumber, + parentIndexNumber: parentIndexNumber ?? this.parentIndexNumber, + premiereDate: premiereDate ?? this.premiereDate, + isAutomated: isAutomated ?? this.isAutomated, + songInfos: songInfos ?? this.songInfos); + } + + ArtistInfo copyWithWrapped( + {Wrapped? name, + Wrapped? originalTitle, + Wrapped? path, + Wrapped? metadataLanguage, + Wrapped? metadataCountryCode, + Wrapped?>? providerIds, + Wrapped? year, + Wrapped? indexNumber, + Wrapped? parentIndexNumber, + Wrapped? premiereDate, + Wrapped? isAutomated, + Wrapped?>? songInfos}) { + return ArtistInfo( + name: (name != null ? name.value : this.name), + originalTitle: + (originalTitle != null ? originalTitle.value : this.originalTitle), + path: (path != null ? path.value : this.path), + metadataLanguage: (metadataLanguage != null + ? metadataLanguage.value + : this.metadataLanguage), + metadataCountryCode: (metadataCountryCode != null + ? metadataCountryCode.value + : this.metadataCountryCode), + providerIds: + (providerIds != null ? providerIds.value : this.providerIds), + year: (year != null ? year.value : this.year), + indexNumber: + (indexNumber != null ? indexNumber.value : this.indexNumber), + parentIndexNumber: (parentIndexNumber != null + ? parentIndexNumber.value + : this.parentIndexNumber), + premiereDate: + (premiereDate != null ? premiereDate.value : this.premiereDate), + isAutomated: + (isAutomated != null ? isAutomated.value : this.isAutomated), + songInfos: (songInfos != null ? songInfos.value : this.songInfos)); + } +} + +@JsonSerializable(explicitToJson: true) +class ArtistInfoRemoteSearchQuery { + const ArtistInfoRemoteSearchQuery({ + this.searchInfo, + this.itemId, + this.searchProviderName, + this.includeDisabledProviders, + }); + + factory ArtistInfoRemoteSearchQuery.fromJson(Map json) => + _$ArtistInfoRemoteSearchQueryFromJson(json); + + static const toJsonFactory = _$ArtistInfoRemoteSearchQueryToJson; + Map toJson() => _$ArtistInfoRemoteSearchQueryToJson(this); + + @JsonKey(name: 'SearchInfo', includeIfNull: false) + final ArtistInfo? searchInfo; + @JsonKey(name: 'ItemId', includeIfNull: false) + final String? itemId; + @JsonKey(name: 'SearchProviderName', includeIfNull: false) + final String? searchProviderName; + @JsonKey(name: 'IncludeDisabledProviders', includeIfNull: false) + final bool? includeDisabledProviders; + static const fromJsonFactory = _$ArtistInfoRemoteSearchQueryFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ArtistInfoRemoteSearchQuery && + (identical(other.searchInfo, searchInfo) || + const DeepCollectionEquality() + .equals(other.searchInfo, searchInfo)) && + (identical(other.itemId, itemId) || + const DeepCollectionEquality().equals(other.itemId, itemId)) && + (identical(other.searchProviderName, searchProviderName) || + const DeepCollectionEquality() + .equals(other.searchProviderName, searchProviderName)) && + (identical( + other.includeDisabledProviders, includeDisabledProviders) || + const DeepCollectionEquality().equals( + other.includeDisabledProviders, includeDisabledProviders))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(searchInfo) ^ + const DeepCollectionEquality().hash(itemId) ^ + const DeepCollectionEquality().hash(searchProviderName) ^ + const DeepCollectionEquality().hash(includeDisabledProviders) ^ + runtimeType.hashCode; +} + +extension $ArtistInfoRemoteSearchQueryExtension on ArtistInfoRemoteSearchQuery { + ArtistInfoRemoteSearchQuery copyWith( + {ArtistInfo? searchInfo, + String? itemId, + String? searchProviderName, + bool? includeDisabledProviders}) { + return ArtistInfoRemoteSearchQuery( + searchInfo: searchInfo ?? this.searchInfo, + itemId: itemId ?? this.itemId, + searchProviderName: searchProviderName ?? this.searchProviderName, + includeDisabledProviders: + includeDisabledProviders ?? this.includeDisabledProviders); + } + + ArtistInfoRemoteSearchQuery copyWithWrapped( + {Wrapped? searchInfo, + Wrapped? itemId, + Wrapped? searchProviderName, + Wrapped? includeDisabledProviders}) { + return ArtistInfoRemoteSearchQuery( + searchInfo: (searchInfo != null ? searchInfo.value : this.searchInfo), + itemId: (itemId != null ? itemId.value : this.itemId), + searchProviderName: (searchProviderName != null + ? searchProviderName.value + : this.searchProviderName), + includeDisabledProviders: (includeDisabledProviders != null + ? includeDisabledProviders.value + : this.includeDisabledProviders)); + } +} + +@JsonSerializable(explicitToJson: true) +class AuthenticateUserByName { + const AuthenticateUserByName({ + this.username, + this.pw, + }); + + factory AuthenticateUserByName.fromJson(Map json) => + _$AuthenticateUserByNameFromJson(json); + + static const toJsonFactory = _$AuthenticateUserByNameToJson; + Map toJson() => _$AuthenticateUserByNameToJson(this); + + @JsonKey(name: 'Username', includeIfNull: false) + final String? username; + @JsonKey(name: 'Pw', includeIfNull: false) + final String? pw; + static const fromJsonFactory = _$AuthenticateUserByNameFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is AuthenticateUserByName && + (identical(other.username, username) || + const DeepCollectionEquality() + .equals(other.username, username)) && + (identical(other.pw, pw) || + const DeepCollectionEquality().equals(other.pw, pw))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(username) ^ + const DeepCollectionEquality().hash(pw) ^ + runtimeType.hashCode; +} + +extension $AuthenticateUserByNameExtension on AuthenticateUserByName { + AuthenticateUserByName copyWith({String? username, String? pw}) { + return AuthenticateUserByName( + username: username ?? this.username, pw: pw ?? this.pw); + } + + AuthenticateUserByName copyWithWrapped( + {Wrapped? username, Wrapped? pw}) { + return AuthenticateUserByName( + username: (username != null ? username.value : this.username), + pw: (pw != null ? pw.value : this.pw)); + } +} + +@JsonSerializable(explicitToJson: true) +class AuthenticationInfo { + const AuthenticationInfo({ + this.id, + this.accessToken, + this.deviceId, + this.appName, + this.appVersion, + this.deviceName, + this.userId, + this.isActive, + this.dateCreated, + this.dateRevoked, + this.dateLastActivity, + this.userName, + }); + + factory AuthenticationInfo.fromJson(Map json) => + _$AuthenticationInfoFromJson(json); + + static const toJsonFactory = _$AuthenticationInfoToJson; + Map toJson() => _$AuthenticationInfoToJson(this); + + @JsonKey(name: 'Id', includeIfNull: false) + final int? id; + @JsonKey(name: 'AccessToken', includeIfNull: false) + final String? accessToken; + @JsonKey(name: 'DeviceId', includeIfNull: false) + final String? deviceId; + @JsonKey(name: 'AppName', includeIfNull: false) + final String? appName; + @JsonKey(name: 'AppVersion', includeIfNull: false) + final String? appVersion; + @JsonKey(name: 'DeviceName', includeIfNull: false) + final String? deviceName; + @JsonKey(name: 'UserId', includeIfNull: false) + final String? userId; + @JsonKey(name: 'IsActive', includeIfNull: false) + final bool? isActive; + @JsonKey(name: 'DateCreated', includeIfNull: false) + final DateTime? dateCreated; + @JsonKey(name: 'DateRevoked', includeIfNull: false) + final DateTime? dateRevoked; + @JsonKey(name: 'DateLastActivity', includeIfNull: false) + final DateTime? dateLastActivity; + @JsonKey(name: 'UserName', includeIfNull: false) + final String? userName; + static const fromJsonFactory = _$AuthenticationInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is AuthenticationInfo && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.accessToken, accessToken) || + const DeepCollectionEquality() + .equals(other.accessToken, accessToken)) && + (identical(other.deviceId, deviceId) || + const DeepCollectionEquality() + .equals(other.deviceId, deviceId)) && + (identical(other.appName, appName) || + const DeepCollectionEquality() + .equals(other.appName, appName)) && + (identical(other.appVersion, appVersion) || + const DeepCollectionEquality() + .equals(other.appVersion, appVersion)) && + (identical(other.deviceName, deviceName) || + const DeepCollectionEquality() + .equals(other.deviceName, deviceName)) && + (identical(other.userId, userId) || + const DeepCollectionEquality().equals(other.userId, userId)) && + (identical(other.isActive, isActive) || + const DeepCollectionEquality() + .equals(other.isActive, isActive)) && + (identical(other.dateCreated, dateCreated) || + const DeepCollectionEquality() + .equals(other.dateCreated, dateCreated)) && + (identical(other.dateRevoked, dateRevoked) || + const DeepCollectionEquality() + .equals(other.dateRevoked, dateRevoked)) && + (identical(other.dateLastActivity, dateLastActivity) || + const DeepCollectionEquality() + .equals(other.dateLastActivity, dateLastActivity)) && + (identical(other.userName, userName) || + const DeepCollectionEquality() + .equals(other.userName, userName))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(accessToken) ^ + const DeepCollectionEquality().hash(deviceId) ^ + const DeepCollectionEquality().hash(appName) ^ + const DeepCollectionEquality().hash(appVersion) ^ + const DeepCollectionEquality().hash(deviceName) ^ + const DeepCollectionEquality().hash(userId) ^ + const DeepCollectionEquality().hash(isActive) ^ + const DeepCollectionEquality().hash(dateCreated) ^ + const DeepCollectionEquality().hash(dateRevoked) ^ + const DeepCollectionEquality().hash(dateLastActivity) ^ + const DeepCollectionEquality().hash(userName) ^ + runtimeType.hashCode; +} + +extension $AuthenticationInfoExtension on AuthenticationInfo { + AuthenticationInfo copyWith( + {int? id, + String? accessToken, + String? deviceId, + String? appName, + String? appVersion, + String? deviceName, + String? userId, + bool? isActive, + DateTime? dateCreated, + DateTime? dateRevoked, + DateTime? dateLastActivity, + String? userName}) { + return AuthenticationInfo( + id: id ?? this.id, + accessToken: accessToken ?? this.accessToken, + deviceId: deviceId ?? this.deviceId, + appName: appName ?? this.appName, + appVersion: appVersion ?? this.appVersion, + deviceName: deviceName ?? this.deviceName, + userId: userId ?? this.userId, + isActive: isActive ?? this.isActive, + dateCreated: dateCreated ?? this.dateCreated, + dateRevoked: dateRevoked ?? this.dateRevoked, + dateLastActivity: dateLastActivity ?? this.dateLastActivity, + userName: userName ?? this.userName); + } + + AuthenticationInfo copyWithWrapped( + {Wrapped? id, + Wrapped? accessToken, + Wrapped? deviceId, + Wrapped? appName, + Wrapped? appVersion, + Wrapped? deviceName, + Wrapped? userId, + Wrapped? isActive, + Wrapped? dateCreated, + Wrapped? dateRevoked, + Wrapped? dateLastActivity, + Wrapped? userName}) { + return AuthenticationInfo( + id: (id != null ? id.value : this.id), + accessToken: + (accessToken != null ? accessToken.value : this.accessToken), + deviceId: (deviceId != null ? deviceId.value : this.deviceId), + appName: (appName != null ? appName.value : this.appName), + appVersion: (appVersion != null ? appVersion.value : this.appVersion), + deviceName: (deviceName != null ? deviceName.value : this.deviceName), + userId: (userId != null ? userId.value : this.userId), + isActive: (isActive != null ? isActive.value : this.isActive), + dateCreated: + (dateCreated != null ? dateCreated.value : this.dateCreated), + dateRevoked: + (dateRevoked != null ? dateRevoked.value : this.dateRevoked), + dateLastActivity: (dateLastActivity != null + ? dateLastActivity.value + : this.dateLastActivity), + userName: (userName != null ? userName.value : this.userName)); + } +} + +@JsonSerializable(explicitToJson: true) +class AuthenticationInfoQueryResult { + const AuthenticationInfoQueryResult({ + this.items, + this.totalRecordCount, + this.startIndex, + }); + + factory AuthenticationInfoQueryResult.fromJson(Map json) => + _$AuthenticationInfoQueryResultFromJson(json); + + static const toJsonFactory = _$AuthenticationInfoQueryResultToJson; + Map toJson() => _$AuthenticationInfoQueryResultToJson(this); + + @JsonKey( + name: 'Items', includeIfNull: false, defaultValue: []) + final List? items; + @JsonKey(name: 'TotalRecordCount', includeIfNull: false) + final int? totalRecordCount; + @JsonKey(name: 'StartIndex', includeIfNull: false) + final int? startIndex; + static const fromJsonFactory = _$AuthenticationInfoQueryResultFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is AuthenticationInfoQueryResult && + (identical(other.items, items) || + const DeepCollectionEquality().equals(other.items, items)) && + (identical(other.totalRecordCount, totalRecordCount) || + const DeepCollectionEquality() + .equals(other.totalRecordCount, totalRecordCount)) && + (identical(other.startIndex, startIndex) || + const DeepCollectionEquality() + .equals(other.startIndex, startIndex))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(items) ^ + const DeepCollectionEquality().hash(totalRecordCount) ^ + const DeepCollectionEquality().hash(startIndex) ^ + runtimeType.hashCode; +} + +extension $AuthenticationInfoQueryResultExtension + on AuthenticationInfoQueryResult { + AuthenticationInfoQueryResult copyWith( + {List? items, + int? totalRecordCount, + int? startIndex}) { + return AuthenticationInfoQueryResult( + items: items ?? this.items, + totalRecordCount: totalRecordCount ?? this.totalRecordCount, + startIndex: startIndex ?? this.startIndex); + } + + AuthenticationInfoQueryResult copyWithWrapped( + {Wrapped?>? items, + Wrapped? totalRecordCount, + Wrapped? startIndex}) { + return AuthenticationInfoQueryResult( + items: (items != null ? items.value : this.items), + totalRecordCount: (totalRecordCount != null + ? totalRecordCount.value + : this.totalRecordCount), + startIndex: (startIndex != null ? startIndex.value : this.startIndex)); + } +} + +@JsonSerializable(explicitToJson: true) +class AuthenticationResult { + const AuthenticationResult({ + this.user, + this.sessionInfo, + this.accessToken, + this.serverId, + }); + + factory AuthenticationResult.fromJson(Map json) => + _$AuthenticationResultFromJson(json); + + static const toJsonFactory = _$AuthenticationResultToJson; + Map toJson() => _$AuthenticationResultToJson(this); + + @JsonKey(name: 'User', includeIfNull: false) + final UserDto? user; + @JsonKey(name: 'SessionInfo', includeIfNull: false) + final SessionInfo? sessionInfo; + @JsonKey(name: 'AccessToken', includeIfNull: false) + final String? accessToken; + @JsonKey(name: 'ServerId', includeIfNull: false) + final String? serverId; + static const fromJsonFactory = _$AuthenticationResultFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is AuthenticationResult && + (identical(other.user, user) || + const DeepCollectionEquality().equals(other.user, user)) && + (identical(other.sessionInfo, sessionInfo) || + const DeepCollectionEquality() + .equals(other.sessionInfo, sessionInfo)) && + (identical(other.accessToken, accessToken) || + const DeepCollectionEquality() + .equals(other.accessToken, accessToken)) && + (identical(other.serverId, serverId) || + const DeepCollectionEquality() + .equals(other.serverId, serverId))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(user) ^ + const DeepCollectionEquality().hash(sessionInfo) ^ + const DeepCollectionEquality().hash(accessToken) ^ + const DeepCollectionEquality().hash(serverId) ^ + runtimeType.hashCode; +} + +extension $AuthenticationResultExtension on AuthenticationResult { + AuthenticationResult copyWith( + {UserDto? user, + SessionInfo? sessionInfo, + String? accessToken, + String? serverId}) { + return AuthenticationResult( + user: user ?? this.user, + sessionInfo: sessionInfo ?? this.sessionInfo, + accessToken: accessToken ?? this.accessToken, + serverId: serverId ?? this.serverId); + } + + AuthenticationResult copyWithWrapped( + {Wrapped? user, + Wrapped? sessionInfo, + Wrapped? accessToken, + Wrapped? serverId}) { + return AuthenticationResult( + user: (user != null ? user.value : this.user), + sessionInfo: + (sessionInfo != null ? sessionInfo.value : this.sessionInfo), + accessToken: + (accessToken != null ? accessToken.value : this.accessToken), + serverId: (serverId != null ? serverId.value : this.serverId)); + } +} + +@JsonSerializable(explicitToJson: true) +class BaseItemDto { + const BaseItemDto({ + this.name, + this.originalTitle, + this.serverId, + this.id, + this.etag, + this.sourceType, + this.playlistItemId, + this.dateCreated, + this.dateLastMediaAdded, + this.extraType, + this.airsBeforeSeasonNumber, + this.airsAfterSeasonNumber, + this.airsBeforeEpisodeNumber, + this.canDelete, + this.canDownload, + this.hasLyrics, + this.hasSubtitles, + this.preferredMetadataLanguage, + this.preferredMetadataCountryCode, + this.container, + this.sortName, + this.forcedSortName, + this.video3DFormat, + this.premiereDate, + this.externalUrls, + this.mediaSources, + this.criticRating, + this.productionLocations, + this.path, + this.enableMediaSourceDisplay, + this.officialRating, + this.customRating, + this.channelId, + this.channelName, + this.overview, + this.taglines, + this.genres, + this.communityRating, + this.cumulativeRunTimeTicks, + this.runTimeTicks, + this.playAccess, + this.aspectRatio, + this.productionYear, + this.isPlaceHolder, + this.number, + this.channelNumber, + this.indexNumber, + this.indexNumberEnd, + this.parentIndexNumber, + this.remoteTrailers, + this.providerIds, + this.isHD, + this.isFolder, + this.parentId, + this.type, + this.people, + this.studios, + this.genreItems, + this.parentLogoItemId, + this.parentBackdropItemId, + this.parentBackdropImageTags, + this.localTrailerCount, + this.userData, + this.recursiveItemCount, + this.childCount, + this.seriesName, + this.seriesId, + this.seasonId, + this.specialFeatureCount, + this.displayPreferencesId, + this.status, + this.airTime, + this.airDays, + this.tags, + this.primaryImageAspectRatio, + this.artists, + this.artistItems, + this.album, + this.collectionType, + this.displayOrder, + this.albumId, + this.albumPrimaryImageTag, + this.seriesPrimaryImageTag, + this.albumArtist, + this.albumArtists, + this.seasonName, + this.mediaStreams, + this.videoType, + this.partCount, + this.mediaSourceCount, + this.imageTags, + this.backdropImageTags, + this.screenshotImageTags, + this.parentLogoImageTag, + this.parentArtItemId, + this.parentArtImageTag, + this.seriesThumbImageTag, + this.imageBlurHashes, + this.seriesStudio, + this.parentThumbItemId, + this.parentThumbImageTag, + this.parentPrimaryImageItemId, + this.parentPrimaryImageTag, + this.chapters, + this.trickplay, + this.locationType, + this.isoType, + this.mediaType, + this.endDate, + this.lockedFields, + this.trailerCount, + this.movieCount, + this.seriesCount, + this.programCount, + this.episodeCount, + this.songCount, + this.albumCount, + this.artistCount, + this.musicVideoCount, + this.lockData, + this.width, + this.height, + this.cameraMake, + this.cameraModel, + this.software, + this.exposureTime, + this.focalLength, + this.imageOrientation, + this.aperture, + this.shutterSpeed, + this.latitude, + this.longitude, + this.altitude, + this.isoSpeedRating, + this.seriesTimerId, + this.programId, + this.channelPrimaryImageTag, + this.startDate, + this.completionPercentage, + this.isRepeat, + this.episodeTitle, + this.channelType, + this.audio, + this.isMovie, + this.isSports, + this.isSeries, + this.isLive, + this.isNews, + this.isKids, + this.isPremiere, + this.timerId, + this.normalizationGain, + this.currentProgram, + }); + + factory BaseItemDto.fromJson(Map json) => + _$BaseItemDtoFromJson(json); + + static const toJsonFactory = _$BaseItemDtoToJson; + Map toJson() => _$BaseItemDtoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'OriginalTitle', includeIfNull: false) + final String? originalTitle; + @JsonKey(name: 'ServerId', includeIfNull: false) + final String? serverId; + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'Etag', includeIfNull: false) + final String? etag; + @JsonKey(name: 'SourceType', includeIfNull: false) + final String? sourceType; + @JsonKey(name: 'PlaylistItemId', includeIfNull: false) + final String? playlistItemId; + @JsonKey(name: 'DateCreated', includeIfNull: false) + final DateTime? dateCreated; + @JsonKey(name: 'DateLastMediaAdded', includeIfNull: false) + final DateTime? dateLastMediaAdded; + @JsonKey( + name: 'ExtraType', + includeIfNull: false, + toJson: extraTypeNullableToJson, + fromJson: extraTypeNullableFromJson, + ) + final enums.ExtraType? extraType; + @JsonKey(name: 'AirsBeforeSeasonNumber', includeIfNull: false) + final int? airsBeforeSeasonNumber; + @JsonKey(name: 'AirsAfterSeasonNumber', includeIfNull: false) + final int? airsAfterSeasonNumber; + @JsonKey(name: 'AirsBeforeEpisodeNumber', includeIfNull: false) + final int? airsBeforeEpisodeNumber; + @JsonKey(name: 'CanDelete', includeIfNull: false) + final bool? canDelete; + @JsonKey(name: 'CanDownload', includeIfNull: false) + final bool? canDownload; + @JsonKey(name: 'HasLyrics', includeIfNull: false) + final bool? hasLyrics; + @JsonKey(name: 'HasSubtitles', includeIfNull: false) + final bool? hasSubtitles; + @JsonKey(name: 'PreferredMetadataLanguage', includeIfNull: false) + final String? preferredMetadataLanguage; + @JsonKey(name: 'PreferredMetadataCountryCode', includeIfNull: false) + final String? preferredMetadataCountryCode; + @JsonKey(name: 'Container', includeIfNull: false) + final String? container; + @JsonKey(name: 'SortName', includeIfNull: false) + final String? sortName; + @JsonKey(name: 'ForcedSortName', includeIfNull: false) + final String? forcedSortName; + @JsonKey( + name: 'Video3DFormat', + includeIfNull: false, + toJson: video3DFormatNullableToJson, + fromJson: video3DFormatNullableFromJson, + ) + final enums.Video3DFormat? video3DFormat; + @JsonKey(name: 'PremiereDate', includeIfNull: false) + final DateTime? premiereDate; + @JsonKey( + name: 'ExternalUrls', includeIfNull: false, defaultValue: []) + final List? externalUrls; + @JsonKey( + name: 'MediaSources', + includeIfNull: false, + defaultValue: []) + final List? mediaSources; + @JsonKey(name: 'CriticRating', includeIfNull: false) + final double? criticRating; + @JsonKey( + name: 'ProductionLocations', + includeIfNull: false, + defaultValue: []) + final List? productionLocations; + @JsonKey(name: 'Path', includeIfNull: false) + final String? path; + @JsonKey(name: 'EnableMediaSourceDisplay', includeIfNull: false) + final bool? enableMediaSourceDisplay; + @JsonKey(name: 'OfficialRating', includeIfNull: false) + final String? officialRating; + @JsonKey(name: 'CustomRating', includeIfNull: false) + final String? customRating; + @JsonKey(name: 'ChannelId', includeIfNull: false) + final String? channelId; + @JsonKey(name: 'ChannelName', includeIfNull: false) + final String? channelName; + @JsonKey(name: 'Overview', includeIfNull: false) + final String? overview; + @JsonKey(name: 'Taglines', includeIfNull: false, defaultValue: []) + final List? taglines; + @JsonKey(name: 'Genres', includeIfNull: false, defaultValue: []) + final List? genres; + @JsonKey(name: 'CommunityRating', includeIfNull: false) + final double? communityRating; + @JsonKey(name: 'CumulativeRunTimeTicks', includeIfNull: false) + final int? cumulativeRunTimeTicks; + @JsonKey(name: 'RunTimeTicks', includeIfNull: false) + final int? runTimeTicks; + @JsonKey( + name: 'PlayAccess', + includeIfNull: false, + toJson: playAccessNullableToJson, + fromJson: playAccessNullableFromJson, + ) + final enums.PlayAccess? playAccess; + @JsonKey(name: 'AspectRatio', includeIfNull: false) + final String? aspectRatio; + @JsonKey(name: 'ProductionYear', includeIfNull: false) + final int? productionYear; + @JsonKey(name: 'IsPlaceHolder', includeIfNull: false) + final bool? isPlaceHolder; + @JsonKey(name: 'Number', includeIfNull: false) + final String? number; + @JsonKey(name: 'ChannelNumber', includeIfNull: false) + final String? channelNumber; + @JsonKey(name: 'IndexNumber', includeIfNull: false) + final int? indexNumber; + @JsonKey(name: 'IndexNumberEnd', includeIfNull: false) + final int? indexNumberEnd; + @JsonKey(name: 'ParentIndexNumber', includeIfNull: false) + final int? parentIndexNumber; + @JsonKey( + name: 'RemoteTrailers', includeIfNull: false, defaultValue: []) + final List? remoteTrailers; + @JsonKey(name: 'ProviderIds', includeIfNull: false) + final Map? providerIds; + @JsonKey(name: 'IsHD', includeIfNull: false) + final bool? isHD; + @JsonKey(name: 'IsFolder', includeIfNull: false) + final bool? isFolder; + @JsonKey(name: 'ParentId', includeIfNull: false) + final String? parentId; + @JsonKey( + name: 'Type', + includeIfNull: false, + toJson: baseItemKindNullableToJson, + fromJson: baseItemKindNullableFromJson, + ) + final enums.BaseItemKind? type; + @JsonKey( + name: 'People', includeIfNull: false, defaultValue: []) + final List? people; + @JsonKey( + name: 'Studios', includeIfNull: false, defaultValue: []) + final List? studios; + @JsonKey( + name: 'GenreItems', includeIfNull: false, defaultValue: []) + final List? genreItems; + @JsonKey(name: 'ParentLogoItemId', includeIfNull: false) + final String? parentLogoItemId; + @JsonKey(name: 'ParentBackdropItemId', includeIfNull: false) + final String? parentBackdropItemId; + @JsonKey( + name: 'ParentBackdropImageTags', + includeIfNull: false, + defaultValue: []) + final List? parentBackdropImageTags; + @JsonKey(name: 'LocalTrailerCount', includeIfNull: false) + final int? localTrailerCount; + @JsonKey(name: 'UserData', includeIfNull: false) + final UserItemDataDto? userData; + @JsonKey(name: 'RecursiveItemCount', includeIfNull: false) + final int? recursiveItemCount; + @JsonKey(name: 'ChildCount', includeIfNull: false) + final int? childCount; + @JsonKey(name: 'SeriesName', includeIfNull: false) + final String? seriesName; + @JsonKey(name: 'SeriesId', includeIfNull: false) + final String? seriesId; + @JsonKey(name: 'SeasonId', includeIfNull: false) + final String? seasonId; + @JsonKey(name: 'SpecialFeatureCount', includeIfNull: false) + final int? specialFeatureCount; + @JsonKey(name: 'DisplayPreferencesId', includeIfNull: false) + final String? displayPreferencesId; + @JsonKey(name: 'Status', includeIfNull: false) + final String? status; + @JsonKey(name: 'AirTime', includeIfNull: false) + final String? airTime; + @JsonKey( + name: 'AirDays', + includeIfNull: false, + toJson: dayOfWeekListToJson, + fromJson: dayOfWeekListFromJson, + ) + final List? airDays; + @JsonKey(name: 'Tags', includeIfNull: false, defaultValue: []) + final List? tags; + @JsonKey(name: 'PrimaryImageAspectRatio', includeIfNull: false) + final double? primaryImageAspectRatio; + @JsonKey(name: 'Artists', includeIfNull: false, defaultValue: []) + final List? artists; + @JsonKey( + name: 'ArtistItems', includeIfNull: false, defaultValue: []) + final List? artistItems; + @JsonKey(name: 'Album', includeIfNull: false) + final String? album; + @JsonKey( + name: 'CollectionType', + includeIfNull: false, + toJson: collectionTypeNullableToJson, + fromJson: collectionTypeNullableFromJson, + ) + final enums.CollectionType? collectionType; + @JsonKey(name: 'DisplayOrder', includeIfNull: false) + final String? displayOrder; + @JsonKey(name: 'AlbumId', includeIfNull: false) + final String? albumId; + @JsonKey(name: 'AlbumPrimaryImageTag', includeIfNull: false) + final String? albumPrimaryImageTag; + @JsonKey(name: 'SeriesPrimaryImageTag', includeIfNull: false) + final String? seriesPrimaryImageTag; + @JsonKey(name: 'AlbumArtist', includeIfNull: false) + final String? albumArtist; + @JsonKey( + name: 'AlbumArtists', + includeIfNull: false, + defaultValue: []) + final List? albumArtists; + @JsonKey(name: 'SeasonName', includeIfNull: false) + final String? seasonName; + @JsonKey( + name: 'MediaStreams', includeIfNull: false, defaultValue: []) + final List? mediaStreams; + @JsonKey( + name: 'VideoType', + includeIfNull: false, + toJson: videoTypeNullableToJson, + fromJson: videoTypeNullableFromJson, + ) + final enums.VideoType? videoType; + @JsonKey(name: 'PartCount', includeIfNull: false) + final int? partCount; + @JsonKey(name: 'MediaSourceCount', includeIfNull: false) + final int? mediaSourceCount; + @JsonKey(name: 'ImageTags', includeIfNull: false) + final Map? imageTags; + @JsonKey( + name: 'BackdropImageTags', includeIfNull: false, defaultValue: []) + final List? backdropImageTags; + @JsonKey( + name: 'ScreenshotImageTags', + includeIfNull: false, + defaultValue: []) + final List? screenshotImageTags; + @JsonKey(name: 'ParentLogoImageTag', includeIfNull: false) + final String? parentLogoImageTag; + @JsonKey(name: 'ParentArtItemId', includeIfNull: false) + final String? parentArtItemId; + @JsonKey(name: 'ParentArtImageTag', includeIfNull: false) + final String? parentArtImageTag; + @JsonKey(name: 'SeriesThumbImageTag', includeIfNull: false) + final String? seriesThumbImageTag; + @JsonKey(name: 'ImageBlurHashes', includeIfNull: false) + final BaseItemDto$ImageBlurHashes? imageBlurHashes; + @JsonKey(name: 'SeriesStudio', includeIfNull: false) + final String? seriesStudio; + @JsonKey(name: 'ParentThumbItemId', includeIfNull: false) + final String? parentThumbItemId; + @JsonKey(name: 'ParentThumbImageTag', includeIfNull: false) + final String? parentThumbImageTag; + @JsonKey(name: 'ParentPrimaryImageItemId', includeIfNull: false) + final String? parentPrimaryImageItemId; + @JsonKey(name: 'ParentPrimaryImageTag', includeIfNull: false) + final String? parentPrimaryImageTag; + @JsonKey( + name: 'Chapters', includeIfNull: false, defaultValue: []) + final List? chapters; + @JsonKey(name: 'Trickplay', includeIfNull: false) + final Map? trickplay; + @JsonKey( + name: 'LocationType', + includeIfNull: false, + toJson: locationTypeNullableToJson, + fromJson: locationTypeNullableFromJson, + ) + final enums.LocationType? locationType; + @JsonKey( + name: 'IsoType', + includeIfNull: false, + toJson: isoTypeNullableToJson, + fromJson: isoTypeNullableFromJson, + ) + final enums.IsoType? isoType; + @JsonKey( + name: 'MediaType', + includeIfNull: false, + toJson: mediaTypeNullableToJson, + fromJson: mediaTypeNullableFromJson, + ) + final enums.MediaType? mediaType; + @JsonKey(name: 'EndDate', includeIfNull: false) + final DateTime? endDate; + @JsonKey( + name: 'LockedFields', + includeIfNull: false, + toJson: metadataFieldListToJson, + fromJson: metadataFieldListFromJson, + ) + final List? lockedFields; + @JsonKey(name: 'TrailerCount', includeIfNull: false) + final int? trailerCount; + @JsonKey(name: 'MovieCount', includeIfNull: false) + final int? movieCount; + @JsonKey(name: 'SeriesCount', includeIfNull: false) + final int? seriesCount; + @JsonKey(name: 'ProgramCount', includeIfNull: false) + final int? programCount; + @JsonKey(name: 'EpisodeCount', includeIfNull: false) + final int? episodeCount; + @JsonKey(name: 'SongCount', includeIfNull: false) + final int? songCount; + @JsonKey(name: 'AlbumCount', includeIfNull: false) + final int? albumCount; + @JsonKey(name: 'ArtistCount', includeIfNull: false) + final int? artistCount; + @JsonKey(name: 'MusicVideoCount', includeIfNull: false) + final int? musicVideoCount; + @JsonKey(name: 'LockData', includeIfNull: false) + final bool? lockData; + @JsonKey(name: 'Width', includeIfNull: false) + final int? width; + @JsonKey(name: 'Height', includeIfNull: false) + final int? height; + @JsonKey(name: 'CameraMake', includeIfNull: false) + final String? cameraMake; + @JsonKey(name: 'CameraModel', includeIfNull: false) + final String? cameraModel; + @JsonKey(name: 'Software', includeIfNull: false) + final String? software; + @JsonKey(name: 'ExposureTime', includeIfNull: false) + final double? exposureTime; + @JsonKey(name: 'FocalLength', includeIfNull: false) + final double? focalLength; + @JsonKey( + name: 'ImageOrientation', + includeIfNull: false, + toJson: imageOrientationNullableToJson, + fromJson: imageOrientationNullableFromJson, + ) + final enums.ImageOrientation? imageOrientation; + @JsonKey(name: 'Aperture', includeIfNull: false) + final double? aperture; + @JsonKey(name: 'ShutterSpeed', includeIfNull: false) + final double? shutterSpeed; + @JsonKey(name: 'Latitude', includeIfNull: false) + final double? latitude; + @JsonKey(name: 'Longitude', includeIfNull: false) + final double? longitude; + @JsonKey(name: 'Altitude', includeIfNull: false) + final double? altitude; + @JsonKey(name: 'IsoSpeedRating', includeIfNull: false) + final int? isoSpeedRating; + @JsonKey(name: 'SeriesTimerId', includeIfNull: false) + final String? seriesTimerId; + @JsonKey(name: 'ProgramId', includeIfNull: false) + final String? programId; + @JsonKey(name: 'ChannelPrimaryImageTag', includeIfNull: false) + final String? channelPrimaryImageTag; + @JsonKey(name: 'StartDate', includeIfNull: false) + final DateTime? startDate; + @JsonKey(name: 'CompletionPercentage', includeIfNull: false) + final double? completionPercentage; + @JsonKey(name: 'IsRepeat', includeIfNull: false) + final bool? isRepeat; + @JsonKey(name: 'EpisodeTitle', includeIfNull: false) + final String? episodeTitle; + @JsonKey( + name: 'ChannelType', + includeIfNull: false, + toJson: channelTypeNullableToJson, + fromJson: channelTypeNullableFromJson, + ) + final enums.ChannelType? channelType; + @JsonKey( + name: 'Audio', + includeIfNull: false, + toJson: programAudioNullableToJson, + fromJson: programAudioNullableFromJson, + ) + final enums.ProgramAudio? audio; + @JsonKey(name: 'IsMovie', includeIfNull: false) + final bool? isMovie; + @JsonKey(name: 'IsSports', includeIfNull: false) + final bool? isSports; + @JsonKey(name: 'IsSeries', includeIfNull: false) + final bool? isSeries; + @JsonKey(name: 'IsLive', includeIfNull: false) + final bool? isLive; + @JsonKey(name: 'IsNews', includeIfNull: false) + final bool? isNews; + @JsonKey(name: 'IsKids', includeIfNull: false) + final bool? isKids; + @JsonKey(name: 'IsPremiere', includeIfNull: false) + final bool? isPremiere; + @JsonKey(name: 'TimerId', includeIfNull: false) + final String? timerId; + @JsonKey(name: 'NormalizationGain', includeIfNull: false) + final double? normalizationGain; + @JsonKey(name: 'CurrentProgram', includeIfNull: false) + final BaseItemDto? currentProgram; + static const fromJsonFactory = _$BaseItemDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is BaseItemDto && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.originalTitle, originalTitle) || + const DeepCollectionEquality() + .equals(other.originalTitle, originalTitle)) && + (identical(other.serverId, serverId) || + const DeepCollectionEquality() + .equals(other.serverId, serverId)) && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.etag, etag) || + const DeepCollectionEquality().equals(other.etag, etag)) && + (identical(other.sourceType, sourceType) || + const DeepCollectionEquality() + .equals(other.sourceType, sourceType)) && + (identical(other.playlistItemId, playlistItemId) || + const DeepCollectionEquality() + .equals(other.playlistItemId, playlistItemId)) && + (identical(other.dateCreated, dateCreated) || + const DeepCollectionEquality() + .equals(other.dateCreated, dateCreated)) && + (identical(other.dateLastMediaAdded, dateLastMediaAdded) || + const DeepCollectionEquality() + .equals(other.dateLastMediaAdded, dateLastMediaAdded)) && + (identical(other.extraType, extraType) || + const DeepCollectionEquality() + .equals(other.extraType, extraType)) && + (identical(other.airsBeforeSeasonNumber, airsBeforeSeasonNumber) || + const DeepCollectionEquality().equals( + other.airsBeforeSeasonNumber, airsBeforeSeasonNumber)) && + (identical(other.airsAfterSeasonNumber, airsAfterSeasonNumber) || + const DeepCollectionEquality().equals( + other.airsAfterSeasonNumber, airsAfterSeasonNumber)) && + (identical(other.airsBeforeEpisodeNumber, airsBeforeEpisodeNumber) || + const DeepCollectionEquality().equals( + other.airsBeforeEpisodeNumber, airsBeforeEpisodeNumber)) && + (identical(other.canDelete, canDelete) || + const DeepCollectionEquality() + .equals(other.canDelete, canDelete)) && + (identical(other.canDownload, canDownload) || + const DeepCollectionEquality() + .equals(other.canDownload, canDownload)) && + (identical(other.hasLyrics, hasLyrics) || + const DeepCollectionEquality() + .equals(other.hasLyrics, hasLyrics)) && + (identical(other.hasSubtitles, hasSubtitles) || + const DeepCollectionEquality() + .equals(other.hasSubtitles, hasSubtitles)) && + (identical(other.preferredMetadataLanguage, preferredMetadataLanguage) || + const DeepCollectionEquality().equals( + other.preferredMetadataLanguage, + preferredMetadataLanguage)) && + (identical(other.preferredMetadataCountryCode, preferredMetadataCountryCode) || + const DeepCollectionEquality().equals( + other.preferredMetadataCountryCode, + preferredMetadataCountryCode)) && + (identical(other.container, container) || const DeepCollectionEquality().equals(other.container, container)) && + (identical(other.sortName, sortName) || const DeepCollectionEquality().equals(other.sortName, sortName)) && + (identical(other.forcedSortName, forcedSortName) || const DeepCollectionEquality().equals(other.forcedSortName, forcedSortName)) && + (identical(other.video3DFormat, video3DFormat) || const DeepCollectionEquality().equals(other.video3DFormat, video3DFormat)) && + (identical(other.premiereDate, premiereDate) || const DeepCollectionEquality().equals(other.premiereDate, premiereDate)) && + (identical(other.externalUrls, externalUrls) || const DeepCollectionEquality().equals(other.externalUrls, externalUrls)) && + (identical(other.mediaSources, mediaSources) || const DeepCollectionEquality().equals(other.mediaSources, mediaSources)) && + (identical(other.criticRating, criticRating) || const DeepCollectionEquality().equals(other.criticRating, criticRating)) && + (identical(other.productionLocations, productionLocations) || const DeepCollectionEquality().equals(other.productionLocations, productionLocations)) && + (identical(other.path, path) || const DeepCollectionEquality().equals(other.path, path)) && + (identical(other.enableMediaSourceDisplay, enableMediaSourceDisplay) || const DeepCollectionEquality().equals(other.enableMediaSourceDisplay, enableMediaSourceDisplay)) && + (identical(other.officialRating, officialRating) || const DeepCollectionEquality().equals(other.officialRating, officialRating)) && + (identical(other.customRating, customRating) || const DeepCollectionEquality().equals(other.customRating, customRating)) && + (identical(other.channelId, channelId) || const DeepCollectionEquality().equals(other.channelId, channelId)) && + (identical(other.channelName, channelName) || const DeepCollectionEquality().equals(other.channelName, channelName)) && + (identical(other.overview, overview) || const DeepCollectionEquality().equals(other.overview, overview)) && + (identical(other.taglines, taglines) || const DeepCollectionEquality().equals(other.taglines, taglines)) && + (identical(other.genres, genres) || const DeepCollectionEquality().equals(other.genres, genres)) && + (identical(other.communityRating, communityRating) || const DeepCollectionEquality().equals(other.communityRating, communityRating)) && + (identical(other.cumulativeRunTimeTicks, cumulativeRunTimeTicks) || const DeepCollectionEquality().equals(other.cumulativeRunTimeTicks, cumulativeRunTimeTicks)) && + (identical(other.runTimeTicks, runTimeTicks) || const DeepCollectionEquality().equals(other.runTimeTicks, runTimeTicks)) && + (identical(other.playAccess, playAccess) || const DeepCollectionEquality().equals(other.playAccess, playAccess)) && + (identical(other.aspectRatio, aspectRatio) || const DeepCollectionEquality().equals(other.aspectRatio, aspectRatio)) && + (identical(other.productionYear, productionYear) || const DeepCollectionEquality().equals(other.productionYear, productionYear)) && + (identical(other.isPlaceHolder, isPlaceHolder) || const DeepCollectionEquality().equals(other.isPlaceHolder, isPlaceHolder)) && + (identical(other.number, number) || const DeepCollectionEquality().equals(other.number, number)) && + (identical(other.channelNumber, channelNumber) || const DeepCollectionEquality().equals(other.channelNumber, channelNumber)) && + (identical(other.indexNumber, indexNumber) || const DeepCollectionEquality().equals(other.indexNumber, indexNumber)) && + (identical(other.indexNumberEnd, indexNumberEnd) || const DeepCollectionEquality().equals(other.indexNumberEnd, indexNumberEnd)) && + (identical(other.parentIndexNumber, parentIndexNumber) || const DeepCollectionEquality().equals(other.parentIndexNumber, parentIndexNumber)) && + (identical(other.remoteTrailers, remoteTrailers) || const DeepCollectionEquality().equals(other.remoteTrailers, remoteTrailers)) && + (identical(other.providerIds, providerIds) || const DeepCollectionEquality().equals(other.providerIds, providerIds)) && + (identical(other.isHD, isHD) || const DeepCollectionEquality().equals(other.isHD, isHD)) && + (identical(other.isFolder, isFolder) || const DeepCollectionEquality().equals(other.isFolder, isFolder)) && + (identical(other.parentId, parentId) || const DeepCollectionEquality().equals(other.parentId, parentId)) && + (identical(other.type, type) || const DeepCollectionEquality().equals(other.type, type)) && + (identical(other.people, people) || const DeepCollectionEquality().equals(other.people, people)) && + (identical(other.studios, studios) || const DeepCollectionEquality().equals(other.studios, studios)) && + (identical(other.genreItems, genreItems) || const DeepCollectionEquality().equals(other.genreItems, genreItems)) && + (identical(other.parentLogoItemId, parentLogoItemId) || const DeepCollectionEquality().equals(other.parentLogoItemId, parentLogoItemId)) && + (identical(other.parentBackdropItemId, parentBackdropItemId) || const DeepCollectionEquality().equals(other.parentBackdropItemId, parentBackdropItemId)) && + (identical(other.parentBackdropImageTags, parentBackdropImageTags) || const DeepCollectionEquality().equals(other.parentBackdropImageTags, parentBackdropImageTags)) && + (identical(other.localTrailerCount, localTrailerCount) || const DeepCollectionEquality().equals(other.localTrailerCount, localTrailerCount)) && + (identical(other.userData, userData) || const DeepCollectionEquality().equals(other.userData, userData)) && + (identical(other.recursiveItemCount, recursiveItemCount) || const DeepCollectionEquality().equals(other.recursiveItemCount, recursiveItemCount)) && + (identical(other.childCount, childCount) || const DeepCollectionEquality().equals(other.childCount, childCount)) && + (identical(other.seriesName, seriesName) || const DeepCollectionEquality().equals(other.seriesName, seriesName)) && + (identical(other.seriesId, seriesId) || const DeepCollectionEquality().equals(other.seriesId, seriesId)) && + (identical(other.seasonId, seasonId) || const DeepCollectionEquality().equals(other.seasonId, seasonId)) && + (identical(other.specialFeatureCount, specialFeatureCount) || const DeepCollectionEquality().equals(other.specialFeatureCount, specialFeatureCount)) && + (identical(other.displayPreferencesId, displayPreferencesId) || const DeepCollectionEquality().equals(other.displayPreferencesId, displayPreferencesId)) && + (identical(other.status, status) || const DeepCollectionEquality().equals(other.status, status)) && + (identical(other.airTime, airTime) || const DeepCollectionEquality().equals(other.airTime, airTime)) && + (identical(other.airDays, airDays) || const DeepCollectionEquality().equals(other.airDays, airDays)) && + (identical(other.tags, tags) || const DeepCollectionEquality().equals(other.tags, tags)) && + (identical(other.primaryImageAspectRatio, primaryImageAspectRatio) || const DeepCollectionEquality().equals(other.primaryImageAspectRatio, primaryImageAspectRatio)) && + (identical(other.artists, artists) || const DeepCollectionEquality().equals(other.artists, artists)) && + (identical(other.artistItems, artistItems) || const DeepCollectionEquality().equals(other.artistItems, artistItems)) && + (identical(other.album, album) || const DeepCollectionEquality().equals(other.album, album)) && + (identical(other.collectionType, collectionType) || const DeepCollectionEquality().equals(other.collectionType, collectionType)) && + (identical(other.displayOrder, displayOrder) || const DeepCollectionEquality().equals(other.displayOrder, displayOrder)) && + (identical(other.albumId, albumId) || const DeepCollectionEquality().equals(other.albumId, albumId)) && + (identical(other.albumPrimaryImageTag, albumPrimaryImageTag) || const DeepCollectionEquality().equals(other.albumPrimaryImageTag, albumPrimaryImageTag)) && + (identical(other.seriesPrimaryImageTag, seriesPrimaryImageTag) || const DeepCollectionEquality().equals(other.seriesPrimaryImageTag, seriesPrimaryImageTag)) && + (identical(other.albumArtist, albumArtist) || const DeepCollectionEquality().equals(other.albumArtist, albumArtist)) && + (identical(other.albumArtists, albumArtists) || const DeepCollectionEquality().equals(other.albumArtists, albumArtists)) && + (identical(other.seasonName, seasonName) || const DeepCollectionEquality().equals(other.seasonName, seasonName)) && + (identical(other.mediaStreams, mediaStreams) || const DeepCollectionEquality().equals(other.mediaStreams, mediaStreams)) && + (identical(other.videoType, videoType) || const DeepCollectionEquality().equals(other.videoType, videoType)) && + (identical(other.partCount, partCount) || const DeepCollectionEquality().equals(other.partCount, partCount)) && + (identical(other.mediaSourceCount, mediaSourceCount) || const DeepCollectionEquality().equals(other.mediaSourceCount, mediaSourceCount)) && + (identical(other.imageTags, imageTags) || const DeepCollectionEquality().equals(other.imageTags, imageTags)) && + (identical(other.backdropImageTags, backdropImageTags) || const DeepCollectionEquality().equals(other.backdropImageTags, backdropImageTags)) && + (identical(other.screenshotImageTags, screenshotImageTags) || const DeepCollectionEquality().equals(other.screenshotImageTags, screenshotImageTags)) && + (identical(other.parentLogoImageTag, parentLogoImageTag) || const DeepCollectionEquality().equals(other.parentLogoImageTag, parentLogoImageTag)) && + (identical(other.parentArtItemId, parentArtItemId) || const DeepCollectionEquality().equals(other.parentArtItemId, parentArtItemId)) && + (identical(other.parentArtImageTag, parentArtImageTag) || const DeepCollectionEquality().equals(other.parentArtImageTag, parentArtImageTag)) && + (identical(other.seriesThumbImageTag, seriesThumbImageTag) || const DeepCollectionEquality().equals(other.seriesThumbImageTag, seriesThumbImageTag)) && + (identical(other.imageBlurHashes, imageBlurHashes) || const DeepCollectionEquality().equals(other.imageBlurHashes, imageBlurHashes)) && + (identical(other.seriesStudio, seriesStudio) || const DeepCollectionEquality().equals(other.seriesStudio, seriesStudio)) && + (identical(other.parentThumbItemId, parentThumbItemId) || const DeepCollectionEquality().equals(other.parentThumbItemId, parentThumbItemId)) && + (identical(other.parentThumbImageTag, parentThumbImageTag) || const DeepCollectionEquality().equals(other.parentThumbImageTag, parentThumbImageTag)) && + (identical(other.parentPrimaryImageItemId, parentPrimaryImageItemId) || const DeepCollectionEquality().equals(other.parentPrimaryImageItemId, parentPrimaryImageItemId)) && + (identical(other.parentPrimaryImageTag, parentPrimaryImageTag) || const DeepCollectionEquality().equals(other.parentPrimaryImageTag, parentPrimaryImageTag)) && + (identical(other.chapters, chapters) || const DeepCollectionEquality().equals(other.chapters, chapters)) && + (identical(other.trickplay, trickplay) || const DeepCollectionEquality().equals(other.trickplay, trickplay)) && + (identical(other.locationType, locationType) || const DeepCollectionEquality().equals(other.locationType, locationType)) && + (identical(other.isoType, isoType) || const DeepCollectionEquality().equals(other.isoType, isoType)) && + (identical(other.mediaType, mediaType) || const DeepCollectionEquality().equals(other.mediaType, mediaType)) && + (identical(other.endDate, endDate) || const DeepCollectionEquality().equals(other.endDate, endDate)) && + (identical(other.lockedFields, lockedFields) || const DeepCollectionEquality().equals(other.lockedFields, lockedFields)) && + (identical(other.trailerCount, trailerCount) || const DeepCollectionEquality().equals(other.trailerCount, trailerCount)) && + (identical(other.movieCount, movieCount) || const DeepCollectionEquality().equals(other.movieCount, movieCount)) && + (identical(other.seriesCount, seriesCount) || const DeepCollectionEquality().equals(other.seriesCount, seriesCount)) && + (identical(other.programCount, programCount) || const DeepCollectionEquality().equals(other.programCount, programCount)) && + (identical(other.episodeCount, episodeCount) || const DeepCollectionEquality().equals(other.episodeCount, episodeCount)) && + (identical(other.songCount, songCount) || const DeepCollectionEquality().equals(other.songCount, songCount)) && + (identical(other.albumCount, albumCount) || const DeepCollectionEquality().equals(other.albumCount, albumCount)) && + (identical(other.artistCount, artistCount) || const DeepCollectionEquality().equals(other.artistCount, artistCount)) && + (identical(other.musicVideoCount, musicVideoCount) || const DeepCollectionEquality().equals(other.musicVideoCount, musicVideoCount)) && + (identical(other.lockData, lockData) || const DeepCollectionEquality().equals(other.lockData, lockData)) && + (identical(other.width, width) || const DeepCollectionEquality().equals(other.width, width)) && + (identical(other.height, height) || const DeepCollectionEquality().equals(other.height, height)) && + (identical(other.cameraMake, cameraMake) || const DeepCollectionEquality().equals(other.cameraMake, cameraMake)) && + (identical(other.cameraModel, cameraModel) || const DeepCollectionEquality().equals(other.cameraModel, cameraModel)) && + (identical(other.software, software) || const DeepCollectionEquality().equals(other.software, software)) && + (identical(other.exposureTime, exposureTime) || const DeepCollectionEquality().equals(other.exposureTime, exposureTime)) && + (identical(other.focalLength, focalLength) || const DeepCollectionEquality().equals(other.focalLength, focalLength)) && + (identical(other.imageOrientation, imageOrientation) || const DeepCollectionEquality().equals(other.imageOrientation, imageOrientation)) && + (identical(other.aperture, aperture) || const DeepCollectionEquality().equals(other.aperture, aperture)) && + (identical(other.shutterSpeed, shutterSpeed) || const DeepCollectionEquality().equals(other.shutterSpeed, shutterSpeed)) && + (identical(other.latitude, latitude) || const DeepCollectionEquality().equals(other.latitude, latitude)) && + (identical(other.longitude, longitude) || const DeepCollectionEquality().equals(other.longitude, longitude)) && + (identical(other.altitude, altitude) || const DeepCollectionEquality().equals(other.altitude, altitude)) && + (identical(other.isoSpeedRating, isoSpeedRating) || const DeepCollectionEquality().equals(other.isoSpeedRating, isoSpeedRating)) && + (identical(other.seriesTimerId, seriesTimerId) || const DeepCollectionEquality().equals(other.seriesTimerId, seriesTimerId)) && + (identical(other.programId, programId) || const DeepCollectionEquality().equals(other.programId, programId)) && + (identical(other.channelPrimaryImageTag, channelPrimaryImageTag) || const DeepCollectionEquality().equals(other.channelPrimaryImageTag, channelPrimaryImageTag)) && + (identical(other.startDate, startDate) || const DeepCollectionEquality().equals(other.startDate, startDate)) && + (identical(other.completionPercentage, completionPercentage) || const DeepCollectionEquality().equals(other.completionPercentage, completionPercentage)) && + (identical(other.isRepeat, isRepeat) || const DeepCollectionEquality().equals(other.isRepeat, isRepeat)) && + (identical(other.episodeTitle, episodeTitle) || const DeepCollectionEquality().equals(other.episodeTitle, episodeTitle)) && + (identical(other.channelType, channelType) || const DeepCollectionEquality().equals(other.channelType, channelType)) && + (identical(other.audio, audio) || const DeepCollectionEquality().equals(other.audio, audio)) && + (identical(other.isMovie, isMovie) || const DeepCollectionEquality().equals(other.isMovie, isMovie)) && + (identical(other.isSports, isSports) || const DeepCollectionEquality().equals(other.isSports, isSports)) && + (identical(other.isSeries, isSeries) || const DeepCollectionEquality().equals(other.isSeries, isSeries)) && + (identical(other.isLive, isLive) || const DeepCollectionEquality().equals(other.isLive, isLive)) && + (identical(other.isNews, isNews) || const DeepCollectionEquality().equals(other.isNews, isNews)) && + (identical(other.isKids, isKids) || const DeepCollectionEquality().equals(other.isKids, isKids)) && + (identical(other.isPremiere, isPremiere) || const DeepCollectionEquality().equals(other.isPremiere, isPremiere)) && + (identical(other.timerId, timerId) || const DeepCollectionEquality().equals(other.timerId, timerId)) && + (identical(other.normalizationGain, normalizationGain) || const DeepCollectionEquality().equals(other.normalizationGain, normalizationGain)) && + (identical(other.currentProgram, currentProgram) || const DeepCollectionEquality().equals(other.currentProgram, currentProgram))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(originalTitle) ^ + const DeepCollectionEquality().hash(serverId) ^ + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(etag) ^ + const DeepCollectionEquality().hash(sourceType) ^ + const DeepCollectionEquality().hash(playlistItemId) ^ + const DeepCollectionEquality().hash(dateCreated) ^ + const DeepCollectionEquality().hash(dateLastMediaAdded) ^ + const DeepCollectionEquality().hash(extraType) ^ + const DeepCollectionEquality().hash(airsBeforeSeasonNumber) ^ + const DeepCollectionEquality().hash(airsAfterSeasonNumber) ^ + const DeepCollectionEquality().hash(airsBeforeEpisodeNumber) ^ + const DeepCollectionEquality().hash(canDelete) ^ + const DeepCollectionEquality().hash(canDownload) ^ + const DeepCollectionEquality().hash(hasLyrics) ^ + const DeepCollectionEquality().hash(hasSubtitles) ^ + const DeepCollectionEquality().hash(preferredMetadataLanguage) ^ + const DeepCollectionEquality().hash(preferredMetadataCountryCode) ^ + const DeepCollectionEquality().hash(container) ^ + const DeepCollectionEquality().hash(sortName) ^ + const DeepCollectionEquality().hash(forcedSortName) ^ + const DeepCollectionEquality().hash(video3DFormat) ^ + const DeepCollectionEquality().hash(premiereDate) ^ + const DeepCollectionEquality().hash(externalUrls) ^ + const DeepCollectionEquality().hash(mediaSources) ^ + const DeepCollectionEquality().hash(criticRating) ^ + const DeepCollectionEquality().hash(productionLocations) ^ + const DeepCollectionEquality().hash(path) ^ + const DeepCollectionEquality().hash(enableMediaSourceDisplay) ^ + const DeepCollectionEquality().hash(officialRating) ^ + const DeepCollectionEquality().hash(customRating) ^ + const DeepCollectionEquality().hash(channelId) ^ + const DeepCollectionEquality().hash(channelName) ^ + const DeepCollectionEquality().hash(overview) ^ + const DeepCollectionEquality().hash(taglines) ^ + const DeepCollectionEquality().hash(genres) ^ + const DeepCollectionEquality().hash(communityRating) ^ + const DeepCollectionEquality().hash(cumulativeRunTimeTicks) ^ + const DeepCollectionEquality().hash(runTimeTicks) ^ + const DeepCollectionEquality().hash(playAccess) ^ + const DeepCollectionEquality().hash(aspectRatio) ^ + const DeepCollectionEquality().hash(productionYear) ^ + const DeepCollectionEquality().hash(isPlaceHolder) ^ + const DeepCollectionEquality().hash(number) ^ + const DeepCollectionEquality().hash(channelNumber) ^ + const DeepCollectionEquality().hash(indexNumber) ^ + const DeepCollectionEquality().hash(indexNumberEnd) ^ + const DeepCollectionEquality().hash(parentIndexNumber) ^ + const DeepCollectionEquality().hash(remoteTrailers) ^ + const DeepCollectionEquality().hash(providerIds) ^ + const DeepCollectionEquality().hash(isHD) ^ + const DeepCollectionEquality().hash(isFolder) ^ + const DeepCollectionEquality().hash(parentId) ^ + const DeepCollectionEquality().hash(type) ^ + const DeepCollectionEquality().hash(people) ^ + const DeepCollectionEquality().hash(studios) ^ + const DeepCollectionEquality().hash(genreItems) ^ + const DeepCollectionEquality().hash(parentLogoItemId) ^ + const DeepCollectionEquality().hash(parentBackdropItemId) ^ + const DeepCollectionEquality().hash(parentBackdropImageTags) ^ + const DeepCollectionEquality().hash(localTrailerCount) ^ + const DeepCollectionEquality().hash(userData) ^ + const DeepCollectionEquality().hash(recursiveItemCount) ^ + const DeepCollectionEquality().hash(childCount) ^ + const DeepCollectionEquality().hash(seriesName) ^ + const DeepCollectionEquality().hash(seriesId) ^ + const DeepCollectionEquality().hash(seasonId) ^ + const DeepCollectionEquality().hash(specialFeatureCount) ^ + const DeepCollectionEquality().hash(displayPreferencesId) ^ + const DeepCollectionEquality().hash(status) ^ + const DeepCollectionEquality().hash(airTime) ^ + const DeepCollectionEquality().hash(airDays) ^ + const DeepCollectionEquality().hash(tags) ^ + const DeepCollectionEquality().hash(primaryImageAspectRatio) ^ + const DeepCollectionEquality().hash(artists) ^ + const DeepCollectionEquality().hash(artistItems) ^ + const DeepCollectionEquality().hash(album) ^ + const DeepCollectionEquality().hash(collectionType) ^ + const DeepCollectionEquality().hash(displayOrder) ^ + const DeepCollectionEquality().hash(albumId) ^ + const DeepCollectionEquality().hash(albumPrimaryImageTag) ^ + const DeepCollectionEquality().hash(seriesPrimaryImageTag) ^ + const DeepCollectionEquality().hash(albumArtist) ^ + const DeepCollectionEquality().hash(albumArtists) ^ + const DeepCollectionEquality().hash(seasonName) ^ + const DeepCollectionEquality().hash(mediaStreams) ^ + const DeepCollectionEquality().hash(videoType) ^ + const DeepCollectionEquality().hash(partCount) ^ + const DeepCollectionEquality().hash(mediaSourceCount) ^ + const DeepCollectionEquality().hash(imageTags) ^ + const DeepCollectionEquality().hash(backdropImageTags) ^ + const DeepCollectionEquality().hash(screenshotImageTags) ^ + const DeepCollectionEquality().hash(parentLogoImageTag) ^ + const DeepCollectionEquality().hash(parentArtItemId) ^ + const DeepCollectionEquality().hash(parentArtImageTag) ^ + const DeepCollectionEquality().hash(seriesThumbImageTag) ^ + const DeepCollectionEquality().hash(imageBlurHashes) ^ + const DeepCollectionEquality().hash(seriesStudio) ^ + const DeepCollectionEquality().hash(parentThumbItemId) ^ + const DeepCollectionEquality().hash(parentThumbImageTag) ^ + const DeepCollectionEquality().hash(parentPrimaryImageItemId) ^ + const DeepCollectionEquality().hash(parentPrimaryImageTag) ^ + const DeepCollectionEquality().hash(chapters) ^ + const DeepCollectionEquality().hash(trickplay) ^ + const DeepCollectionEquality().hash(locationType) ^ + const DeepCollectionEquality().hash(isoType) ^ + const DeepCollectionEquality().hash(mediaType) ^ + const DeepCollectionEquality().hash(endDate) ^ + const DeepCollectionEquality().hash(lockedFields) ^ + const DeepCollectionEquality().hash(trailerCount) ^ + const DeepCollectionEquality().hash(movieCount) ^ + const DeepCollectionEquality().hash(seriesCount) ^ + const DeepCollectionEquality().hash(programCount) ^ + const DeepCollectionEquality().hash(episodeCount) ^ + const DeepCollectionEquality().hash(songCount) ^ + const DeepCollectionEquality().hash(albumCount) ^ + const DeepCollectionEquality().hash(artistCount) ^ + const DeepCollectionEquality().hash(musicVideoCount) ^ + const DeepCollectionEquality().hash(lockData) ^ + const DeepCollectionEquality().hash(width) ^ + const DeepCollectionEquality().hash(height) ^ + const DeepCollectionEquality().hash(cameraMake) ^ + const DeepCollectionEquality().hash(cameraModel) ^ + const DeepCollectionEquality().hash(software) ^ + const DeepCollectionEquality().hash(exposureTime) ^ + const DeepCollectionEquality().hash(focalLength) ^ + const DeepCollectionEquality().hash(imageOrientation) ^ + const DeepCollectionEquality().hash(aperture) ^ + const DeepCollectionEquality().hash(shutterSpeed) ^ + const DeepCollectionEquality().hash(latitude) ^ + const DeepCollectionEquality().hash(longitude) ^ + const DeepCollectionEquality().hash(altitude) ^ + const DeepCollectionEquality().hash(isoSpeedRating) ^ + const DeepCollectionEquality().hash(seriesTimerId) ^ + const DeepCollectionEquality().hash(programId) ^ + const DeepCollectionEquality().hash(channelPrimaryImageTag) ^ + const DeepCollectionEquality().hash(startDate) ^ + const DeepCollectionEquality().hash(completionPercentage) ^ + const DeepCollectionEquality().hash(isRepeat) ^ + const DeepCollectionEquality().hash(episodeTitle) ^ + const DeepCollectionEquality().hash(channelType) ^ + const DeepCollectionEquality().hash(audio) ^ + const DeepCollectionEquality().hash(isMovie) ^ + const DeepCollectionEquality().hash(isSports) ^ + const DeepCollectionEquality().hash(isSeries) ^ + const DeepCollectionEquality().hash(isLive) ^ + const DeepCollectionEquality().hash(isNews) ^ + const DeepCollectionEquality().hash(isKids) ^ + const DeepCollectionEquality().hash(isPremiere) ^ + const DeepCollectionEquality().hash(timerId) ^ + const DeepCollectionEquality().hash(normalizationGain) ^ + const DeepCollectionEquality().hash(currentProgram) ^ + runtimeType.hashCode; +} + +extension $BaseItemDtoExtension on BaseItemDto { + BaseItemDto copyWith( + {String? name, + String? originalTitle, + String? serverId, + String? id, + String? etag, + String? sourceType, + String? playlistItemId, + DateTime? dateCreated, + DateTime? dateLastMediaAdded, + enums.ExtraType? extraType, + int? airsBeforeSeasonNumber, + int? airsAfterSeasonNumber, + int? airsBeforeEpisodeNumber, + bool? canDelete, + bool? canDownload, + bool? hasLyrics, + bool? hasSubtitles, + String? preferredMetadataLanguage, + String? preferredMetadataCountryCode, + String? container, + String? sortName, + String? forcedSortName, + enums.Video3DFormat? video3DFormat, + DateTime? premiereDate, + List? externalUrls, + List? mediaSources, + double? criticRating, + List? productionLocations, + String? path, + bool? enableMediaSourceDisplay, + String? officialRating, + String? customRating, + String? channelId, + String? channelName, + String? overview, + List? taglines, + List? genres, + double? communityRating, + int? cumulativeRunTimeTicks, + int? runTimeTicks, + enums.PlayAccess? playAccess, + String? aspectRatio, + int? productionYear, + bool? isPlaceHolder, + String? number, + String? channelNumber, + int? indexNumber, + int? indexNumberEnd, + int? parentIndexNumber, + List? remoteTrailers, + Map? providerIds, + bool? isHD, + bool? isFolder, + String? parentId, + enums.BaseItemKind? type, + List? people, + List? studios, + List? genreItems, + String? parentLogoItemId, + String? parentBackdropItemId, + List? parentBackdropImageTags, + int? localTrailerCount, + UserItemDataDto? userData, + int? recursiveItemCount, + int? childCount, + String? seriesName, + String? seriesId, + String? seasonId, + int? specialFeatureCount, + String? displayPreferencesId, + String? status, + String? airTime, + List? airDays, + List? tags, + double? primaryImageAspectRatio, + List? artists, + List? artistItems, + String? album, + enums.CollectionType? collectionType, + String? displayOrder, + String? albumId, + String? albumPrimaryImageTag, + String? seriesPrimaryImageTag, + String? albumArtist, + List? albumArtists, + String? seasonName, + List? mediaStreams, + enums.VideoType? videoType, + int? partCount, + int? mediaSourceCount, + Map? imageTags, + List? backdropImageTags, + List? screenshotImageTags, + String? parentLogoImageTag, + String? parentArtItemId, + String? parentArtImageTag, + String? seriesThumbImageTag, + BaseItemDto$ImageBlurHashes? imageBlurHashes, + String? seriesStudio, + String? parentThumbItemId, + String? parentThumbImageTag, + String? parentPrimaryImageItemId, + String? parentPrimaryImageTag, + List? chapters, + Map? trickplay, + enums.LocationType? locationType, + enums.IsoType? isoType, + enums.MediaType? mediaType, + DateTime? endDate, + List? lockedFields, + int? trailerCount, + int? movieCount, + int? seriesCount, + int? programCount, + int? episodeCount, + int? songCount, + int? albumCount, + int? artistCount, + int? musicVideoCount, + bool? lockData, + int? width, + int? height, + String? cameraMake, + String? cameraModel, + String? software, + double? exposureTime, + double? focalLength, + enums.ImageOrientation? imageOrientation, + double? aperture, + double? shutterSpeed, + double? latitude, + double? longitude, + double? altitude, + int? isoSpeedRating, + String? seriesTimerId, + String? programId, + String? channelPrimaryImageTag, + DateTime? startDate, + double? completionPercentage, + bool? isRepeat, + String? episodeTitle, + enums.ChannelType? channelType, + enums.ProgramAudio? audio, + bool? isMovie, + bool? isSports, + bool? isSeries, + bool? isLive, + bool? isNews, + bool? isKids, + bool? isPremiere, + String? timerId, + double? normalizationGain, + BaseItemDto? currentProgram}) { + return BaseItemDto( + name: name ?? this.name, + originalTitle: originalTitle ?? this.originalTitle, + serverId: serverId ?? this.serverId, + id: id ?? this.id, + etag: etag ?? this.etag, + sourceType: sourceType ?? this.sourceType, + playlistItemId: playlistItemId ?? this.playlistItemId, + dateCreated: dateCreated ?? this.dateCreated, + dateLastMediaAdded: dateLastMediaAdded ?? this.dateLastMediaAdded, + extraType: extraType ?? this.extraType, + airsBeforeSeasonNumber: + airsBeforeSeasonNumber ?? this.airsBeforeSeasonNumber, + airsAfterSeasonNumber: + airsAfterSeasonNumber ?? this.airsAfterSeasonNumber, + airsBeforeEpisodeNumber: + airsBeforeEpisodeNumber ?? this.airsBeforeEpisodeNumber, + canDelete: canDelete ?? this.canDelete, + canDownload: canDownload ?? this.canDownload, + hasLyrics: hasLyrics ?? this.hasLyrics, + hasSubtitles: hasSubtitles ?? this.hasSubtitles, + preferredMetadataLanguage: + preferredMetadataLanguage ?? this.preferredMetadataLanguage, + preferredMetadataCountryCode: + preferredMetadataCountryCode ?? this.preferredMetadataCountryCode, + container: container ?? this.container, + sortName: sortName ?? this.sortName, + forcedSortName: forcedSortName ?? this.forcedSortName, + video3DFormat: video3DFormat ?? this.video3DFormat, + premiereDate: premiereDate ?? this.premiereDate, + externalUrls: externalUrls ?? this.externalUrls, + mediaSources: mediaSources ?? this.mediaSources, + criticRating: criticRating ?? this.criticRating, + productionLocations: productionLocations ?? this.productionLocations, + path: path ?? this.path, + enableMediaSourceDisplay: + enableMediaSourceDisplay ?? this.enableMediaSourceDisplay, + officialRating: officialRating ?? this.officialRating, + customRating: customRating ?? this.customRating, + channelId: channelId ?? this.channelId, + channelName: channelName ?? this.channelName, + overview: overview ?? this.overview, + taglines: taglines ?? this.taglines, + genres: genres ?? this.genres, + communityRating: communityRating ?? this.communityRating, + cumulativeRunTimeTicks: + cumulativeRunTimeTicks ?? this.cumulativeRunTimeTicks, + runTimeTicks: runTimeTicks ?? this.runTimeTicks, + playAccess: playAccess ?? this.playAccess, + aspectRatio: aspectRatio ?? this.aspectRatio, + productionYear: productionYear ?? this.productionYear, + isPlaceHolder: isPlaceHolder ?? this.isPlaceHolder, + number: number ?? this.number, + channelNumber: channelNumber ?? this.channelNumber, + indexNumber: indexNumber ?? this.indexNumber, + indexNumberEnd: indexNumberEnd ?? this.indexNumberEnd, + parentIndexNumber: parentIndexNumber ?? this.parentIndexNumber, + remoteTrailers: remoteTrailers ?? this.remoteTrailers, + providerIds: providerIds ?? this.providerIds, + isHD: isHD ?? this.isHD, + isFolder: isFolder ?? this.isFolder, + parentId: parentId ?? this.parentId, + type: type ?? this.type, + people: people ?? this.people, + studios: studios ?? this.studios, + genreItems: genreItems ?? this.genreItems, + parentLogoItemId: parentLogoItemId ?? this.parentLogoItemId, + parentBackdropItemId: parentBackdropItemId ?? this.parentBackdropItemId, + parentBackdropImageTags: + parentBackdropImageTags ?? this.parentBackdropImageTags, + localTrailerCount: localTrailerCount ?? this.localTrailerCount, + userData: userData ?? this.userData, + recursiveItemCount: recursiveItemCount ?? this.recursiveItemCount, + childCount: childCount ?? this.childCount, + seriesName: seriesName ?? this.seriesName, + seriesId: seriesId ?? this.seriesId, + seasonId: seasonId ?? this.seasonId, + specialFeatureCount: specialFeatureCount ?? this.specialFeatureCount, + displayPreferencesId: displayPreferencesId ?? this.displayPreferencesId, + status: status ?? this.status, + airTime: airTime ?? this.airTime, + airDays: airDays ?? this.airDays, + tags: tags ?? this.tags, + primaryImageAspectRatio: + primaryImageAspectRatio ?? this.primaryImageAspectRatio, + artists: artists ?? this.artists, + artistItems: artistItems ?? this.artistItems, + album: album ?? this.album, + collectionType: collectionType ?? this.collectionType, + displayOrder: displayOrder ?? this.displayOrder, + albumId: albumId ?? this.albumId, + albumPrimaryImageTag: albumPrimaryImageTag ?? this.albumPrimaryImageTag, + seriesPrimaryImageTag: + seriesPrimaryImageTag ?? this.seriesPrimaryImageTag, + albumArtist: albumArtist ?? this.albumArtist, + albumArtists: albumArtists ?? this.albumArtists, + seasonName: seasonName ?? this.seasonName, + mediaStreams: mediaStreams ?? this.mediaStreams, + videoType: videoType ?? this.videoType, + partCount: partCount ?? this.partCount, + mediaSourceCount: mediaSourceCount ?? this.mediaSourceCount, + imageTags: imageTags ?? this.imageTags, + backdropImageTags: backdropImageTags ?? this.backdropImageTags, + screenshotImageTags: screenshotImageTags ?? this.screenshotImageTags, + parentLogoImageTag: parentLogoImageTag ?? this.parentLogoImageTag, + parentArtItemId: parentArtItemId ?? this.parentArtItemId, + parentArtImageTag: parentArtImageTag ?? this.parentArtImageTag, + seriesThumbImageTag: seriesThumbImageTag ?? this.seriesThumbImageTag, + imageBlurHashes: imageBlurHashes ?? this.imageBlurHashes, + seriesStudio: seriesStudio ?? this.seriesStudio, + parentThumbItemId: parentThumbItemId ?? this.parentThumbItemId, + parentThumbImageTag: parentThumbImageTag ?? this.parentThumbImageTag, + parentPrimaryImageItemId: + parentPrimaryImageItemId ?? this.parentPrimaryImageItemId, + parentPrimaryImageTag: + parentPrimaryImageTag ?? this.parentPrimaryImageTag, + chapters: chapters ?? this.chapters, + trickplay: trickplay ?? this.trickplay, + locationType: locationType ?? this.locationType, + isoType: isoType ?? this.isoType, + mediaType: mediaType ?? this.mediaType, + endDate: endDate ?? this.endDate, + lockedFields: lockedFields ?? this.lockedFields, + trailerCount: trailerCount ?? this.trailerCount, + movieCount: movieCount ?? this.movieCount, + seriesCount: seriesCount ?? this.seriesCount, + programCount: programCount ?? this.programCount, + episodeCount: episodeCount ?? this.episodeCount, + songCount: songCount ?? this.songCount, + albumCount: albumCount ?? this.albumCount, + artistCount: artistCount ?? this.artistCount, + musicVideoCount: musicVideoCount ?? this.musicVideoCount, + lockData: lockData ?? this.lockData, + width: width ?? this.width, + height: height ?? this.height, + cameraMake: cameraMake ?? this.cameraMake, + cameraModel: cameraModel ?? this.cameraModel, + software: software ?? this.software, + exposureTime: exposureTime ?? this.exposureTime, + focalLength: focalLength ?? this.focalLength, + imageOrientation: imageOrientation ?? this.imageOrientation, + aperture: aperture ?? this.aperture, + shutterSpeed: shutterSpeed ?? this.shutterSpeed, + latitude: latitude ?? this.latitude, + longitude: longitude ?? this.longitude, + altitude: altitude ?? this.altitude, + isoSpeedRating: isoSpeedRating ?? this.isoSpeedRating, + seriesTimerId: seriesTimerId ?? this.seriesTimerId, + programId: programId ?? this.programId, + channelPrimaryImageTag: + channelPrimaryImageTag ?? this.channelPrimaryImageTag, + startDate: startDate ?? this.startDate, + completionPercentage: completionPercentage ?? this.completionPercentage, + isRepeat: isRepeat ?? this.isRepeat, + episodeTitle: episodeTitle ?? this.episodeTitle, + channelType: channelType ?? this.channelType, + audio: audio ?? this.audio, + isMovie: isMovie ?? this.isMovie, + isSports: isSports ?? this.isSports, + isSeries: isSeries ?? this.isSeries, + isLive: isLive ?? this.isLive, + isNews: isNews ?? this.isNews, + isKids: isKids ?? this.isKids, + isPremiere: isPremiere ?? this.isPremiere, + timerId: timerId ?? this.timerId, + normalizationGain: normalizationGain ?? this.normalizationGain, + currentProgram: currentProgram ?? this.currentProgram); + } + + BaseItemDto copyWithWrapped( + {Wrapped? name, + Wrapped? originalTitle, + Wrapped? serverId, + Wrapped? id, + Wrapped? etag, + Wrapped? sourceType, + Wrapped? playlistItemId, + Wrapped? dateCreated, + Wrapped? dateLastMediaAdded, + Wrapped? extraType, + Wrapped? airsBeforeSeasonNumber, + Wrapped? airsAfterSeasonNumber, + Wrapped? airsBeforeEpisodeNumber, + Wrapped? canDelete, + Wrapped? canDownload, + Wrapped? hasLyrics, + Wrapped? hasSubtitles, + Wrapped? preferredMetadataLanguage, + Wrapped? preferredMetadataCountryCode, + Wrapped? container, + Wrapped? sortName, + Wrapped? forcedSortName, + Wrapped? video3DFormat, + Wrapped? premiereDate, + Wrapped?>? externalUrls, + Wrapped?>? mediaSources, + Wrapped? criticRating, + Wrapped?>? productionLocations, + Wrapped? path, + Wrapped? enableMediaSourceDisplay, + Wrapped? officialRating, + Wrapped? customRating, + Wrapped? channelId, + Wrapped? channelName, + Wrapped? overview, + Wrapped?>? taglines, + Wrapped?>? genres, + Wrapped? communityRating, + Wrapped? cumulativeRunTimeTicks, + Wrapped? runTimeTicks, + Wrapped? playAccess, + Wrapped? aspectRatio, + Wrapped? productionYear, + Wrapped? isPlaceHolder, + Wrapped? number, + Wrapped? channelNumber, + Wrapped? indexNumber, + Wrapped? indexNumberEnd, + Wrapped? parentIndexNumber, + Wrapped?>? remoteTrailers, + Wrapped?>? providerIds, + Wrapped? isHD, + Wrapped? isFolder, + Wrapped? parentId, + Wrapped? type, + Wrapped?>? people, + Wrapped?>? studios, + Wrapped?>? genreItems, + Wrapped? parentLogoItemId, + Wrapped? parentBackdropItemId, + Wrapped?>? parentBackdropImageTags, + Wrapped? localTrailerCount, + Wrapped? userData, + Wrapped? recursiveItemCount, + Wrapped? childCount, + Wrapped? seriesName, + Wrapped? seriesId, + Wrapped? seasonId, + Wrapped? specialFeatureCount, + Wrapped? displayPreferencesId, + Wrapped? status, + Wrapped? airTime, + Wrapped?>? airDays, + Wrapped?>? tags, + Wrapped? primaryImageAspectRatio, + Wrapped?>? artists, + Wrapped?>? artistItems, + Wrapped? album, + Wrapped? collectionType, + Wrapped? displayOrder, + Wrapped? albumId, + Wrapped? albumPrimaryImageTag, + Wrapped? seriesPrimaryImageTag, + Wrapped? albumArtist, + Wrapped?>? albumArtists, + Wrapped? seasonName, + Wrapped?>? mediaStreams, + Wrapped? videoType, + Wrapped? partCount, + Wrapped? mediaSourceCount, + Wrapped?>? imageTags, + Wrapped?>? backdropImageTags, + Wrapped?>? screenshotImageTags, + Wrapped? parentLogoImageTag, + Wrapped? parentArtItemId, + Wrapped? parentArtImageTag, + Wrapped? seriesThumbImageTag, + Wrapped? imageBlurHashes, + Wrapped? seriesStudio, + Wrapped? parentThumbItemId, + Wrapped? parentThumbImageTag, + Wrapped? parentPrimaryImageItemId, + Wrapped? parentPrimaryImageTag, + Wrapped?>? chapters, + Wrapped?>? trickplay, + Wrapped? locationType, + Wrapped? isoType, + Wrapped? mediaType, + Wrapped? endDate, + Wrapped?>? lockedFields, + Wrapped? trailerCount, + Wrapped? movieCount, + Wrapped? seriesCount, + Wrapped? programCount, + Wrapped? episodeCount, + Wrapped? songCount, + Wrapped? albumCount, + Wrapped? artistCount, + Wrapped? musicVideoCount, + Wrapped? lockData, + Wrapped? width, + Wrapped? height, + Wrapped? cameraMake, + Wrapped? cameraModel, + Wrapped? software, + Wrapped? exposureTime, + Wrapped? focalLength, + Wrapped? imageOrientation, + Wrapped? aperture, + Wrapped? shutterSpeed, + Wrapped? latitude, + Wrapped? longitude, + Wrapped? altitude, + Wrapped? isoSpeedRating, + Wrapped? seriesTimerId, + Wrapped? programId, + Wrapped? channelPrimaryImageTag, + Wrapped? startDate, + Wrapped? completionPercentage, + Wrapped? isRepeat, + Wrapped? episodeTitle, + Wrapped? channelType, + Wrapped? audio, + Wrapped? isMovie, + Wrapped? isSports, + Wrapped? isSeries, + Wrapped? isLive, + Wrapped? isNews, + Wrapped? isKids, + Wrapped? isPremiere, + Wrapped? timerId, + Wrapped? normalizationGain, + Wrapped? currentProgram}) { + return BaseItemDto( + name: (name != null ? name.value : this.name), + originalTitle: + (originalTitle != null ? originalTitle.value : this.originalTitle), + serverId: (serverId != null ? serverId.value : this.serverId), + id: (id != null ? id.value : this.id), + etag: (etag != null ? etag.value : this.etag), + sourceType: (sourceType != null ? sourceType.value : this.sourceType), + playlistItemId: (playlistItemId != null + ? playlistItemId.value + : this.playlistItemId), + dateCreated: + (dateCreated != null ? dateCreated.value : this.dateCreated), + dateLastMediaAdded: (dateLastMediaAdded != null + ? dateLastMediaAdded.value + : this.dateLastMediaAdded), + extraType: (extraType != null ? extraType.value : this.extraType), + airsBeforeSeasonNumber: (airsBeforeSeasonNumber != null + ? airsBeforeSeasonNumber.value + : this.airsBeforeSeasonNumber), + airsAfterSeasonNumber: (airsAfterSeasonNumber != null + ? airsAfterSeasonNumber.value + : this.airsAfterSeasonNumber), + airsBeforeEpisodeNumber: (airsBeforeEpisodeNumber != null + ? airsBeforeEpisodeNumber.value + : this.airsBeforeEpisodeNumber), + canDelete: (canDelete != null ? canDelete.value : this.canDelete), + canDownload: + (canDownload != null ? canDownload.value : this.canDownload), + hasLyrics: (hasLyrics != null ? hasLyrics.value : this.hasLyrics), + hasSubtitles: + (hasSubtitles != null ? hasSubtitles.value : this.hasSubtitles), + preferredMetadataLanguage: (preferredMetadataLanguage != null + ? preferredMetadataLanguage.value + : this.preferredMetadataLanguage), + preferredMetadataCountryCode: (preferredMetadataCountryCode != null + ? preferredMetadataCountryCode.value + : this.preferredMetadataCountryCode), + container: (container != null ? container.value : this.container), + sortName: (sortName != null ? sortName.value : this.sortName), + forcedSortName: (forcedSortName != null + ? forcedSortName.value + : this.forcedSortName), + video3DFormat: + (video3DFormat != null ? video3DFormat.value : this.video3DFormat), + premiereDate: + (premiereDate != null ? premiereDate.value : this.premiereDate), + externalUrls: + (externalUrls != null ? externalUrls.value : this.externalUrls), + mediaSources: + (mediaSources != null ? mediaSources.value : this.mediaSources), + criticRating: + (criticRating != null ? criticRating.value : this.criticRating), + productionLocations: (productionLocations != null + ? productionLocations.value + : this.productionLocations), + path: (path != null ? path.value : this.path), + enableMediaSourceDisplay: (enableMediaSourceDisplay != null + ? enableMediaSourceDisplay.value + : this.enableMediaSourceDisplay), + officialRating: (officialRating != null + ? officialRating.value + : this.officialRating), + customRating: + (customRating != null ? customRating.value : this.customRating), + channelId: (channelId != null ? channelId.value : this.channelId), + channelName: + (channelName != null ? channelName.value : this.channelName), + overview: (overview != null ? overview.value : this.overview), + taglines: (taglines != null ? taglines.value : this.taglines), + genres: (genres != null ? genres.value : this.genres), + communityRating: (communityRating != null + ? communityRating.value + : this.communityRating), + cumulativeRunTimeTicks: (cumulativeRunTimeTicks != null + ? cumulativeRunTimeTicks.value + : this.cumulativeRunTimeTicks), + runTimeTicks: + (runTimeTicks != null ? runTimeTicks.value : this.runTimeTicks), + playAccess: (playAccess != null ? playAccess.value : this.playAccess), + aspectRatio: + (aspectRatio != null ? aspectRatio.value : this.aspectRatio), + productionYear: (productionYear != null + ? productionYear.value + : this.productionYear), + isPlaceHolder: + (isPlaceHolder != null ? isPlaceHolder.value : this.isPlaceHolder), + number: (number != null ? number.value : this.number), + channelNumber: + (channelNumber != null ? channelNumber.value : this.channelNumber), + indexNumber: + (indexNumber != null ? indexNumber.value : this.indexNumber), + indexNumberEnd: (indexNumberEnd != null + ? indexNumberEnd.value + : this.indexNumberEnd), + parentIndexNumber: (parentIndexNumber != null + ? parentIndexNumber.value + : this.parentIndexNumber), + remoteTrailers: (remoteTrailers != null + ? remoteTrailers.value + : this.remoteTrailers), + providerIds: + (providerIds != null ? providerIds.value : this.providerIds), + isHD: (isHD != null ? isHD.value : this.isHD), + isFolder: (isFolder != null ? isFolder.value : this.isFolder), + parentId: (parentId != null ? parentId.value : this.parentId), + type: (type != null ? type.value : this.type), + people: (people != null ? people.value : this.people), + studios: (studios != null ? studios.value : this.studios), + genreItems: (genreItems != null ? genreItems.value : this.genreItems), + parentLogoItemId: (parentLogoItemId != null + ? parentLogoItemId.value + : this.parentLogoItemId), + parentBackdropItemId: (parentBackdropItemId != null + ? parentBackdropItemId.value + : this.parentBackdropItemId), + parentBackdropImageTags: (parentBackdropImageTags != null + ? parentBackdropImageTags.value + : this.parentBackdropImageTags), + localTrailerCount: (localTrailerCount != null + ? localTrailerCount.value + : this.localTrailerCount), + userData: (userData != null ? userData.value : this.userData), + recursiveItemCount: (recursiveItemCount != null + ? recursiveItemCount.value + : this.recursiveItemCount), + childCount: (childCount != null ? childCount.value : this.childCount), + seriesName: (seriesName != null ? seriesName.value : this.seriesName), + seriesId: (seriesId != null ? seriesId.value : this.seriesId), + seasonId: (seasonId != null ? seasonId.value : this.seasonId), + specialFeatureCount: (specialFeatureCount != null + ? specialFeatureCount.value + : this.specialFeatureCount), + displayPreferencesId: (displayPreferencesId != null + ? displayPreferencesId.value + : this.displayPreferencesId), + status: (status != null ? status.value : this.status), + airTime: (airTime != null ? airTime.value : this.airTime), + airDays: (airDays != null ? airDays.value : this.airDays), + tags: (tags != null ? tags.value : this.tags), + primaryImageAspectRatio: (primaryImageAspectRatio != null + ? primaryImageAspectRatio.value + : this.primaryImageAspectRatio), + artists: (artists != null ? artists.value : this.artists), + artistItems: + (artistItems != null ? artistItems.value : this.artistItems), + album: (album != null ? album.value : this.album), + collectionType: (collectionType != null + ? collectionType.value + : this.collectionType), + displayOrder: + (displayOrder != null ? displayOrder.value : this.displayOrder), + albumId: (albumId != null ? albumId.value : this.albumId), + albumPrimaryImageTag: (albumPrimaryImageTag != null + ? albumPrimaryImageTag.value + : this.albumPrimaryImageTag), + seriesPrimaryImageTag: (seriesPrimaryImageTag != null + ? seriesPrimaryImageTag.value + : this.seriesPrimaryImageTag), + albumArtist: + (albumArtist != null ? albumArtist.value : this.albumArtist), + albumArtists: + (albumArtists != null ? albumArtists.value : this.albumArtists), + seasonName: (seasonName != null ? seasonName.value : this.seasonName), + mediaStreams: + (mediaStreams != null ? mediaStreams.value : this.mediaStreams), + videoType: (videoType != null ? videoType.value : this.videoType), + partCount: (partCount != null ? partCount.value : this.partCount), + mediaSourceCount: (mediaSourceCount != null + ? mediaSourceCount.value + : this.mediaSourceCount), + imageTags: (imageTags != null ? imageTags.value : this.imageTags), + backdropImageTags: (backdropImageTags != null + ? backdropImageTags.value + : this.backdropImageTags), + screenshotImageTags: (screenshotImageTags != null + ? screenshotImageTags.value + : this.screenshotImageTags), + parentLogoImageTag: (parentLogoImageTag != null + ? parentLogoImageTag.value + : this.parentLogoImageTag), + parentArtItemId: (parentArtItemId != null + ? parentArtItemId.value + : this.parentArtItemId), + parentArtImageTag: (parentArtImageTag != null + ? parentArtImageTag.value + : this.parentArtImageTag), + seriesThumbImageTag: (seriesThumbImageTag != null + ? seriesThumbImageTag.value + : this.seriesThumbImageTag), + imageBlurHashes: (imageBlurHashes != null + ? imageBlurHashes.value + : this.imageBlurHashes), + seriesStudio: + (seriesStudio != null ? seriesStudio.value : this.seriesStudio), + parentThumbItemId: (parentThumbItemId != null ? parentThumbItemId.value : this.parentThumbItemId), + parentThumbImageTag: (parentThumbImageTag != null ? parentThumbImageTag.value : this.parentThumbImageTag), + parentPrimaryImageItemId: (parentPrimaryImageItemId != null ? parentPrimaryImageItemId.value : this.parentPrimaryImageItemId), + parentPrimaryImageTag: (parentPrimaryImageTag != null ? parentPrimaryImageTag.value : this.parentPrimaryImageTag), + chapters: (chapters != null ? chapters.value : this.chapters), + trickplay: (trickplay != null ? trickplay.value : this.trickplay), + locationType: (locationType != null ? locationType.value : this.locationType), + isoType: (isoType != null ? isoType.value : this.isoType), + mediaType: (mediaType != null ? mediaType.value : this.mediaType), + endDate: (endDate != null ? endDate.value : this.endDate), + lockedFields: (lockedFields != null ? lockedFields.value : this.lockedFields), + trailerCount: (trailerCount != null ? trailerCount.value : this.trailerCount), + movieCount: (movieCount != null ? movieCount.value : this.movieCount), + seriesCount: (seriesCount != null ? seriesCount.value : this.seriesCount), + programCount: (programCount != null ? programCount.value : this.programCount), + episodeCount: (episodeCount != null ? episodeCount.value : this.episodeCount), + songCount: (songCount != null ? songCount.value : this.songCount), + albumCount: (albumCount != null ? albumCount.value : this.albumCount), + artistCount: (artistCount != null ? artistCount.value : this.artistCount), + musicVideoCount: (musicVideoCount != null ? musicVideoCount.value : this.musicVideoCount), + lockData: (lockData != null ? lockData.value : this.lockData), + width: (width != null ? width.value : this.width), + height: (height != null ? height.value : this.height), + cameraMake: (cameraMake != null ? cameraMake.value : this.cameraMake), + cameraModel: (cameraModel != null ? cameraModel.value : this.cameraModel), + software: (software != null ? software.value : this.software), + exposureTime: (exposureTime != null ? exposureTime.value : this.exposureTime), + focalLength: (focalLength != null ? focalLength.value : this.focalLength), + imageOrientation: (imageOrientation != null ? imageOrientation.value : this.imageOrientation), + aperture: (aperture != null ? aperture.value : this.aperture), + shutterSpeed: (shutterSpeed != null ? shutterSpeed.value : this.shutterSpeed), + latitude: (latitude != null ? latitude.value : this.latitude), + longitude: (longitude != null ? longitude.value : this.longitude), + altitude: (altitude != null ? altitude.value : this.altitude), + isoSpeedRating: (isoSpeedRating != null ? isoSpeedRating.value : this.isoSpeedRating), + seriesTimerId: (seriesTimerId != null ? seriesTimerId.value : this.seriesTimerId), + programId: (programId != null ? programId.value : this.programId), + channelPrimaryImageTag: (channelPrimaryImageTag != null ? channelPrimaryImageTag.value : this.channelPrimaryImageTag), + startDate: (startDate != null ? startDate.value : this.startDate), + completionPercentage: (completionPercentage != null ? completionPercentage.value : this.completionPercentage), + isRepeat: (isRepeat != null ? isRepeat.value : this.isRepeat), + episodeTitle: (episodeTitle != null ? episodeTitle.value : this.episodeTitle), + channelType: (channelType != null ? channelType.value : this.channelType), + audio: (audio != null ? audio.value : this.audio), + isMovie: (isMovie != null ? isMovie.value : this.isMovie), + isSports: (isSports != null ? isSports.value : this.isSports), + isSeries: (isSeries != null ? isSeries.value : this.isSeries), + isLive: (isLive != null ? isLive.value : this.isLive), + isNews: (isNews != null ? isNews.value : this.isNews), + isKids: (isKids != null ? isKids.value : this.isKids), + isPremiere: (isPremiere != null ? isPremiere.value : this.isPremiere), + timerId: (timerId != null ? timerId.value : this.timerId), + normalizationGain: (normalizationGain != null ? normalizationGain.value : this.normalizationGain), + currentProgram: (currentProgram != null ? currentProgram.value : this.currentProgram)); + } +} + +@JsonSerializable(explicitToJson: true) +class BaseItemDtoQueryResult { + const BaseItemDtoQueryResult({ + this.items, + this.totalRecordCount, + this.startIndex, + }); + + factory BaseItemDtoQueryResult.fromJson(Map json) => + _$BaseItemDtoQueryResultFromJson(json); + + static const toJsonFactory = _$BaseItemDtoQueryResultToJson; + Map toJson() => _$BaseItemDtoQueryResultToJson(this); + + @JsonKey(name: 'Items', includeIfNull: false, defaultValue: []) + final List? items; + @JsonKey(name: 'TotalRecordCount', includeIfNull: false) + final int? totalRecordCount; + @JsonKey(name: 'StartIndex', includeIfNull: false) + final int? startIndex; + static const fromJsonFactory = _$BaseItemDtoQueryResultFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is BaseItemDtoQueryResult && + (identical(other.items, items) || + const DeepCollectionEquality().equals(other.items, items)) && + (identical(other.totalRecordCount, totalRecordCount) || + const DeepCollectionEquality() + .equals(other.totalRecordCount, totalRecordCount)) && + (identical(other.startIndex, startIndex) || + const DeepCollectionEquality() + .equals(other.startIndex, startIndex))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(items) ^ + const DeepCollectionEquality().hash(totalRecordCount) ^ + const DeepCollectionEquality().hash(startIndex) ^ + runtimeType.hashCode; +} + +extension $BaseItemDtoQueryResultExtension on BaseItemDtoQueryResult { + BaseItemDtoQueryResult copyWith( + {List? items, int? totalRecordCount, int? startIndex}) { + return BaseItemDtoQueryResult( + items: items ?? this.items, + totalRecordCount: totalRecordCount ?? this.totalRecordCount, + startIndex: startIndex ?? this.startIndex); + } + + BaseItemDtoQueryResult copyWithWrapped( + {Wrapped?>? items, + Wrapped? totalRecordCount, + Wrapped? startIndex}) { + return BaseItemDtoQueryResult( + items: (items != null ? items.value : this.items), + totalRecordCount: (totalRecordCount != null + ? totalRecordCount.value + : this.totalRecordCount), + startIndex: (startIndex != null ? startIndex.value : this.startIndex)); + } +} + +@JsonSerializable(explicitToJson: true) +class BaseItemPerson { + const BaseItemPerson({ + this.name, + this.id, + this.role, + this.type, + this.primaryImageTag, + this.imageBlurHashes, + }); + + factory BaseItemPerson.fromJson(Map json) => + _$BaseItemPersonFromJson(json); + + static const toJsonFactory = _$BaseItemPersonToJson; + Map toJson() => _$BaseItemPersonToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'Role', includeIfNull: false) + final String? role; + @JsonKey( + name: 'Type', + includeIfNull: false, + toJson: personKindNullableToJson, + fromJson: personKindNullableFromJson, + ) + final enums.PersonKind? type; + @JsonKey(name: 'PrimaryImageTag', includeIfNull: false) + final String? primaryImageTag; + @JsonKey(name: 'ImageBlurHashes', includeIfNull: false) + final BaseItemPerson$ImageBlurHashes? imageBlurHashes; + static const fromJsonFactory = _$BaseItemPersonFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is BaseItemPerson && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.role, role) || + const DeepCollectionEquality().equals(other.role, role)) && + (identical(other.type, type) || + const DeepCollectionEquality().equals(other.type, type)) && + (identical(other.primaryImageTag, primaryImageTag) || + const DeepCollectionEquality() + .equals(other.primaryImageTag, primaryImageTag)) && + (identical(other.imageBlurHashes, imageBlurHashes) || + const DeepCollectionEquality() + .equals(other.imageBlurHashes, imageBlurHashes))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(role) ^ + const DeepCollectionEquality().hash(type) ^ + const DeepCollectionEquality().hash(primaryImageTag) ^ + const DeepCollectionEquality().hash(imageBlurHashes) ^ + runtimeType.hashCode; +} + +extension $BaseItemPersonExtension on BaseItemPerson { + BaseItemPerson copyWith( + {String? name, + String? id, + String? role, + enums.PersonKind? type, + String? primaryImageTag, + BaseItemPerson$ImageBlurHashes? imageBlurHashes}) { + return BaseItemPerson( + name: name ?? this.name, + id: id ?? this.id, + role: role ?? this.role, + type: type ?? this.type, + primaryImageTag: primaryImageTag ?? this.primaryImageTag, + imageBlurHashes: imageBlurHashes ?? this.imageBlurHashes); + } + + BaseItemPerson copyWithWrapped( + {Wrapped? name, + Wrapped? id, + Wrapped? role, + Wrapped? type, + Wrapped? primaryImageTag, + Wrapped? imageBlurHashes}) { + return BaseItemPerson( + name: (name != null ? name.value : this.name), + id: (id != null ? id.value : this.id), + role: (role != null ? role.value : this.role), + type: (type != null ? type.value : this.type), + primaryImageTag: (primaryImageTag != null + ? primaryImageTag.value + : this.primaryImageTag), + imageBlurHashes: (imageBlurHashes != null + ? imageBlurHashes.value + : this.imageBlurHashes)); + } +} + +@JsonSerializable(explicitToJson: true) +class BasePluginConfiguration { + const BasePluginConfiguration(); + + factory BasePluginConfiguration.fromJson(Map json) => + _$BasePluginConfigurationFromJson(json); + + static const toJsonFactory = _$BasePluginConfigurationToJson; + Map toJson() => _$BasePluginConfigurationToJson(this); + + static const fromJsonFactory = _$BasePluginConfigurationFromJson; + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => runtimeType.hashCode; +} + +@JsonSerializable(explicitToJson: true) +class BookInfo { + const BookInfo({ + this.name, + this.originalTitle, + this.path, + this.metadataLanguage, + this.metadataCountryCode, + this.providerIds, + this.year, + this.indexNumber, + this.parentIndexNumber, + this.premiereDate, + this.isAutomated, + this.seriesName, + }); + + factory BookInfo.fromJson(Map json) => + _$BookInfoFromJson(json); + + static const toJsonFactory = _$BookInfoToJson; + Map toJson() => _$BookInfoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'OriginalTitle', includeIfNull: false) + final String? originalTitle; + @JsonKey(name: 'Path', includeIfNull: false) + final String? path; + @JsonKey(name: 'MetadataLanguage', includeIfNull: false) + final String? metadataLanguage; + @JsonKey(name: 'MetadataCountryCode', includeIfNull: false) + final String? metadataCountryCode; + @JsonKey(name: 'ProviderIds', includeIfNull: false) + final Map? providerIds; + @JsonKey(name: 'Year', includeIfNull: false) + final int? year; + @JsonKey(name: 'IndexNumber', includeIfNull: false) + final int? indexNumber; + @JsonKey(name: 'ParentIndexNumber', includeIfNull: false) + final int? parentIndexNumber; + @JsonKey(name: 'PremiereDate', includeIfNull: false) + final DateTime? premiereDate; + @JsonKey(name: 'IsAutomated', includeIfNull: false) + final bool? isAutomated; + @JsonKey(name: 'SeriesName', includeIfNull: false) + final String? seriesName; + static const fromJsonFactory = _$BookInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is BookInfo && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.originalTitle, originalTitle) || + const DeepCollectionEquality() + .equals(other.originalTitle, originalTitle)) && + (identical(other.path, path) || + const DeepCollectionEquality().equals(other.path, path)) && + (identical(other.metadataLanguage, metadataLanguage) || + const DeepCollectionEquality() + .equals(other.metadataLanguage, metadataLanguage)) && + (identical(other.metadataCountryCode, metadataCountryCode) || + const DeepCollectionEquality() + .equals(other.metadataCountryCode, metadataCountryCode)) && + (identical(other.providerIds, providerIds) || + const DeepCollectionEquality() + .equals(other.providerIds, providerIds)) && + (identical(other.year, year) || + const DeepCollectionEquality().equals(other.year, year)) && + (identical(other.indexNumber, indexNumber) || + const DeepCollectionEquality() + .equals(other.indexNumber, indexNumber)) && + (identical(other.parentIndexNumber, parentIndexNumber) || + const DeepCollectionEquality() + .equals(other.parentIndexNumber, parentIndexNumber)) && + (identical(other.premiereDate, premiereDate) || + const DeepCollectionEquality() + .equals(other.premiereDate, premiereDate)) && + (identical(other.isAutomated, isAutomated) || + const DeepCollectionEquality() + .equals(other.isAutomated, isAutomated)) && + (identical(other.seriesName, seriesName) || + const DeepCollectionEquality() + .equals(other.seriesName, seriesName))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(originalTitle) ^ + const DeepCollectionEquality().hash(path) ^ + const DeepCollectionEquality().hash(metadataLanguage) ^ + const DeepCollectionEquality().hash(metadataCountryCode) ^ + const DeepCollectionEquality().hash(providerIds) ^ + const DeepCollectionEquality().hash(year) ^ + const DeepCollectionEquality().hash(indexNumber) ^ + const DeepCollectionEquality().hash(parentIndexNumber) ^ + const DeepCollectionEquality().hash(premiereDate) ^ + const DeepCollectionEquality().hash(isAutomated) ^ + const DeepCollectionEquality().hash(seriesName) ^ + runtimeType.hashCode; +} + +extension $BookInfoExtension on BookInfo { + BookInfo copyWith( + {String? name, + String? originalTitle, + String? path, + String? metadataLanguage, + String? metadataCountryCode, + Map? providerIds, + int? year, + int? indexNumber, + int? parentIndexNumber, + DateTime? premiereDate, + bool? isAutomated, + String? seriesName}) { + return BookInfo( + name: name ?? this.name, + originalTitle: originalTitle ?? this.originalTitle, + path: path ?? this.path, + metadataLanguage: metadataLanguage ?? this.metadataLanguage, + metadataCountryCode: metadataCountryCode ?? this.metadataCountryCode, + providerIds: providerIds ?? this.providerIds, + year: year ?? this.year, + indexNumber: indexNumber ?? this.indexNumber, + parentIndexNumber: parentIndexNumber ?? this.parentIndexNumber, + premiereDate: premiereDate ?? this.premiereDate, + isAutomated: isAutomated ?? this.isAutomated, + seriesName: seriesName ?? this.seriesName); + } + + BookInfo copyWithWrapped( + {Wrapped? name, + Wrapped? originalTitle, + Wrapped? path, + Wrapped? metadataLanguage, + Wrapped? metadataCountryCode, + Wrapped?>? providerIds, + Wrapped? year, + Wrapped? indexNumber, + Wrapped? parentIndexNumber, + Wrapped? premiereDate, + Wrapped? isAutomated, + Wrapped? seriesName}) { + return BookInfo( + name: (name != null ? name.value : this.name), + originalTitle: + (originalTitle != null ? originalTitle.value : this.originalTitle), + path: (path != null ? path.value : this.path), + metadataLanguage: (metadataLanguage != null + ? metadataLanguage.value + : this.metadataLanguage), + metadataCountryCode: (metadataCountryCode != null + ? metadataCountryCode.value + : this.metadataCountryCode), + providerIds: + (providerIds != null ? providerIds.value : this.providerIds), + year: (year != null ? year.value : this.year), + indexNumber: + (indexNumber != null ? indexNumber.value : this.indexNumber), + parentIndexNumber: (parentIndexNumber != null + ? parentIndexNumber.value + : this.parentIndexNumber), + premiereDate: + (premiereDate != null ? premiereDate.value : this.premiereDate), + isAutomated: + (isAutomated != null ? isAutomated.value : this.isAutomated), + seriesName: (seriesName != null ? seriesName.value : this.seriesName)); + } +} + +@JsonSerializable(explicitToJson: true) +class BookInfoRemoteSearchQuery { + const BookInfoRemoteSearchQuery({ + this.searchInfo, + this.itemId, + this.searchProviderName, + this.includeDisabledProviders, + }); + + factory BookInfoRemoteSearchQuery.fromJson(Map json) => + _$BookInfoRemoteSearchQueryFromJson(json); + + static const toJsonFactory = _$BookInfoRemoteSearchQueryToJson; + Map toJson() => _$BookInfoRemoteSearchQueryToJson(this); + + @JsonKey(name: 'SearchInfo', includeIfNull: false) + final BookInfo? searchInfo; + @JsonKey(name: 'ItemId', includeIfNull: false) + final String? itemId; + @JsonKey(name: 'SearchProviderName', includeIfNull: false) + final String? searchProviderName; + @JsonKey(name: 'IncludeDisabledProviders', includeIfNull: false) + final bool? includeDisabledProviders; + static const fromJsonFactory = _$BookInfoRemoteSearchQueryFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is BookInfoRemoteSearchQuery && + (identical(other.searchInfo, searchInfo) || + const DeepCollectionEquality() + .equals(other.searchInfo, searchInfo)) && + (identical(other.itemId, itemId) || + const DeepCollectionEquality().equals(other.itemId, itemId)) && + (identical(other.searchProviderName, searchProviderName) || + const DeepCollectionEquality() + .equals(other.searchProviderName, searchProviderName)) && + (identical( + other.includeDisabledProviders, includeDisabledProviders) || + const DeepCollectionEquality().equals( + other.includeDisabledProviders, includeDisabledProviders))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(searchInfo) ^ + const DeepCollectionEquality().hash(itemId) ^ + const DeepCollectionEquality().hash(searchProviderName) ^ + const DeepCollectionEquality().hash(includeDisabledProviders) ^ + runtimeType.hashCode; +} + +extension $BookInfoRemoteSearchQueryExtension on BookInfoRemoteSearchQuery { + BookInfoRemoteSearchQuery copyWith( + {BookInfo? searchInfo, + String? itemId, + String? searchProviderName, + bool? includeDisabledProviders}) { + return BookInfoRemoteSearchQuery( + searchInfo: searchInfo ?? this.searchInfo, + itemId: itemId ?? this.itemId, + searchProviderName: searchProviderName ?? this.searchProviderName, + includeDisabledProviders: + includeDisabledProviders ?? this.includeDisabledProviders); + } + + BookInfoRemoteSearchQuery copyWithWrapped( + {Wrapped? searchInfo, + Wrapped? itemId, + Wrapped? searchProviderName, + Wrapped? includeDisabledProviders}) { + return BookInfoRemoteSearchQuery( + searchInfo: (searchInfo != null ? searchInfo.value : this.searchInfo), + itemId: (itemId != null ? itemId.value : this.itemId), + searchProviderName: (searchProviderName != null + ? searchProviderName.value + : this.searchProviderName), + includeDisabledProviders: (includeDisabledProviders != null + ? includeDisabledProviders.value + : this.includeDisabledProviders)); + } +} + +@JsonSerializable(explicitToJson: true) +class BoxSetInfo { + const BoxSetInfo({ + this.name, + this.originalTitle, + this.path, + this.metadataLanguage, + this.metadataCountryCode, + this.providerIds, + this.year, + this.indexNumber, + this.parentIndexNumber, + this.premiereDate, + this.isAutomated, + }); + + factory BoxSetInfo.fromJson(Map json) => + _$BoxSetInfoFromJson(json); + + static const toJsonFactory = _$BoxSetInfoToJson; + Map toJson() => _$BoxSetInfoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'OriginalTitle', includeIfNull: false) + final String? originalTitle; + @JsonKey(name: 'Path', includeIfNull: false) + final String? path; + @JsonKey(name: 'MetadataLanguage', includeIfNull: false) + final String? metadataLanguage; + @JsonKey(name: 'MetadataCountryCode', includeIfNull: false) + final String? metadataCountryCode; + @JsonKey(name: 'ProviderIds', includeIfNull: false) + final Map? providerIds; + @JsonKey(name: 'Year', includeIfNull: false) + final int? year; + @JsonKey(name: 'IndexNumber', includeIfNull: false) + final int? indexNumber; + @JsonKey(name: 'ParentIndexNumber', includeIfNull: false) + final int? parentIndexNumber; + @JsonKey(name: 'PremiereDate', includeIfNull: false) + final DateTime? premiereDate; + @JsonKey(name: 'IsAutomated', includeIfNull: false) + final bool? isAutomated; + static const fromJsonFactory = _$BoxSetInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is BoxSetInfo && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.originalTitle, originalTitle) || + const DeepCollectionEquality() + .equals(other.originalTitle, originalTitle)) && + (identical(other.path, path) || + const DeepCollectionEquality().equals(other.path, path)) && + (identical(other.metadataLanguage, metadataLanguage) || + const DeepCollectionEquality() + .equals(other.metadataLanguage, metadataLanguage)) && + (identical(other.metadataCountryCode, metadataCountryCode) || + const DeepCollectionEquality() + .equals(other.metadataCountryCode, metadataCountryCode)) && + (identical(other.providerIds, providerIds) || + const DeepCollectionEquality() + .equals(other.providerIds, providerIds)) && + (identical(other.year, year) || + const DeepCollectionEquality().equals(other.year, year)) && + (identical(other.indexNumber, indexNumber) || + const DeepCollectionEquality() + .equals(other.indexNumber, indexNumber)) && + (identical(other.parentIndexNumber, parentIndexNumber) || + const DeepCollectionEquality() + .equals(other.parentIndexNumber, parentIndexNumber)) && + (identical(other.premiereDate, premiereDate) || + const DeepCollectionEquality() + .equals(other.premiereDate, premiereDate)) && + (identical(other.isAutomated, isAutomated) || + const DeepCollectionEquality() + .equals(other.isAutomated, isAutomated))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(originalTitle) ^ + const DeepCollectionEquality().hash(path) ^ + const DeepCollectionEquality().hash(metadataLanguage) ^ + const DeepCollectionEquality().hash(metadataCountryCode) ^ + const DeepCollectionEquality().hash(providerIds) ^ + const DeepCollectionEquality().hash(year) ^ + const DeepCollectionEquality().hash(indexNumber) ^ + const DeepCollectionEquality().hash(parentIndexNumber) ^ + const DeepCollectionEquality().hash(premiereDate) ^ + const DeepCollectionEquality().hash(isAutomated) ^ + runtimeType.hashCode; +} + +extension $BoxSetInfoExtension on BoxSetInfo { + BoxSetInfo copyWith( + {String? name, + String? originalTitle, + String? path, + String? metadataLanguage, + String? metadataCountryCode, + Map? providerIds, + int? year, + int? indexNumber, + int? parentIndexNumber, + DateTime? premiereDate, + bool? isAutomated}) { + return BoxSetInfo( + name: name ?? this.name, + originalTitle: originalTitle ?? this.originalTitle, + path: path ?? this.path, + metadataLanguage: metadataLanguage ?? this.metadataLanguage, + metadataCountryCode: metadataCountryCode ?? this.metadataCountryCode, + providerIds: providerIds ?? this.providerIds, + year: year ?? this.year, + indexNumber: indexNumber ?? this.indexNumber, + parentIndexNumber: parentIndexNumber ?? this.parentIndexNumber, + premiereDate: premiereDate ?? this.premiereDate, + isAutomated: isAutomated ?? this.isAutomated); + } + + BoxSetInfo copyWithWrapped( + {Wrapped? name, + Wrapped? originalTitle, + Wrapped? path, + Wrapped? metadataLanguage, + Wrapped? metadataCountryCode, + Wrapped?>? providerIds, + Wrapped? year, + Wrapped? indexNumber, + Wrapped? parentIndexNumber, + Wrapped? premiereDate, + Wrapped? isAutomated}) { + return BoxSetInfo( + name: (name != null ? name.value : this.name), + originalTitle: + (originalTitle != null ? originalTitle.value : this.originalTitle), + path: (path != null ? path.value : this.path), + metadataLanguage: (metadataLanguage != null + ? metadataLanguage.value + : this.metadataLanguage), + metadataCountryCode: (metadataCountryCode != null + ? metadataCountryCode.value + : this.metadataCountryCode), + providerIds: + (providerIds != null ? providerIds.value : this.providerIds), + year: (year != null ? year.value : this.year), + indexNumber: + (indexNumber != null ? indexNumber.value : this.indexNumber), + parentIndexNumber: (parentIndexNumber != null + ? parentIndexNumber.value + : this.parentIndexNumber), + premiereDate: + (premiereDate != null ? premiereDate.value : this.premiereDate), + isAutomated: + (isAutomated != null ? isAutomated.value : this.isAutomated)); + } +} + +@JsonSerializable(explicitToJson: true) +class BoxSetInfoRemoteSearchQuery { + const BoxSetInfoRemoteSearchQuery({ + this.searchInfo, + this.itemId, + this.searchProviderName, + this.includeDisabledProviders, + }); + + factory BoxSetInfoRemoteSearchQuery.fromJson(Map json) => + _$BoxSetInfoRemoteSearchQueryFromJson(json); + + static const toJsonFactory = _$BoxSetInfoRemoteSearchQueryToJson; + Map toJson() => _$BoxSetInfoRemoteSearchQueryToJson(this); + + @JsonKey(name: 'SearchInfo', includeIfNull: false) + final BoxSetInfo? searchInfo; + @JsonKey(name: 'ItemId', includeIfNull: false) + final String? itemId; + @JsonKey(name: 'SearchProviderName', includeIfNull: false) + final String? searchProviderName; + @JsonKey(name: 'IncludeDisabledProviders', includeIfNull: false) + final bool? includeDisabledProviders; + static const fromJsonFactory = _$BoxSetInfoRemoteSearchQueryFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is BoxSetInfoRemoteSearchQuery && + (identical(other.searchInfo, searchInfo) || + const DeepCollectionEquality() + .equals(other.searchInfo, searchInfo)) && + (identical(other.itemId, itemId) || + const DeepCollectionEquality().equals(other.itemId, itemId)) && + (identical(other.searchProviderName, searchProviderName) || + const DeepCollectionEquality() + .equals(other.searchProviderName, searchProviderName)) && + (identical( + other.includeDisabledProviders, includeDisabledProviders) || + const DeepCollectionEquality().equals( + other.includeDisabledProviders, includeDisabledProviders))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(searchInfo) ^ + const DeepCollectionEquality().hash(itemId) ^ + const DeepCollectionEquality().hash(searchProviderName) ^ + const DeepCollectionEquality().hash(includeDisabledProviders) ^ + runtimeType.hashCode; +} + +extension $BoxSetInfoRemoteSearchQueryExtension on BoxSetInfoRemoteSearchQuery { + BoxSetInfoRemoteSearchQuery copyWith( + {BoxSetInfo? searchInfo, + String? itemId, + String? searchProviderName, + bool? includeDisabledProviders}) { + return BoxSetInfoRemoteSearchQuery( + searchInfo: searchInfo ?? this.searchInfo, + itemId: itemId ?? this.itemId, + searchProviderName: searchProviderName ?? this.searchProviderName, + includeDisabledProviders: + includeDisabledProviders ?? this.includeDisabledProviders); + } + + BoxSetInfoRemoteSearchQuery copyWithWrapped( + {Wrapped? searchInfo, + Wrapped? itemId, + Wrapped? searchProviderName, + Wrapped? includeDisabledProviders}) { + return BoxSetInfoRemoteSearchQuery( + searchInfo: (searchInfo != null ? searchInfo.value : this.searchInfo), + itemId: (itemId != null ? itemId.value : this.itemId), + searchProviderName: (searchProviderName != null + ? searchProviderName.value + : this.searchProviderName), + includeDisabledProviders: (includeDisabledProviders != null + ? includeDisabledProviders.value + : this.includeDisabledProviders)); + } +} + +@JsonSerializable(explicitToJson: true) +class BrandingOptions { + const BrandingOptions({ + this.loginDisclaimer, + this.customCss, + this.splashscreenEnabled, + }); + + factory BrandingOptions.fromJson(Map json) => + _$BrandingOptionsFromJson(json); + + static const toJsonFactory = _$BrandingOptionsToJson; + Map toJson() => _$BrandingOptionsToJson(this); + + @JsonKey(name: 'LoginDisclaimer', includeIfNull: false) + final String? loginDisclaimer; + @JsonKey(name: 'CustomCss', includeIfNull: false) + final String? customCss; + @JsonKey(name: 'SplashscreenEnabled', includeIfNull: false) + final bool? splashscreenEnabled; + static const fromJsonFactory = _$BrandingOptionsFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is BrandingOptions && + (identical(other.loginDisclaimer, loginDisclaimer) || + const DeepCollectionEquality() + .equals(other.loginDisclaimer, loginDisclaimer)) && + (identical(other.customCss, customCss) || + const DeepCollectionEquality() + .equals(other.customCss, customCss)) && + (identical(other.splashscreenEnabled, splashscreenEnabled) || + const DeepCollectionEquality() + .equals(other.splashscreenEnabled, splashscreenEnabled))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(loginDisclaimer) ^ + const DeepCollectionEquality().hash(customCss) ^ + const DeepCollectionEquality().hash(splashscreenEnabled) ^ + runtimeType.hashCode; +} + +extension $BrandingOptionsExtension on BrandingOptions { + BrandingOptions copyWith( + {String? loginDisclaimer, String? customCss, bool? splashscreenEnabled}) { + return BrandingOptions( + loginDisclaimer: loginDisclaimer ?? this.loginDisclaimer, + customCss: customCss ?? this.customCss, + splashscreenEnabled: splashscreenEnabled ?? this.splashscreenEnabled); + } + + BrandingOptions copyWithWrapped( + {Wrapped? loginDisclaimer, + Wrapped? customCss, + Wrapped? splashscreenEnabled}) { + return BrandingOptions( + loginDisclaimer: (loginDisclaimer != null + ? loginDisclaimer.value + : this.loginDisclaimer), + customCss: (customCss != null ? customCss.value : this.customCss), + splashscreenEnabled: (splashscreenEnabled != null + ? splashscreenEnabled.value + : this.splashscreenEnabled)); + } +} + +@JsonSerializable(explicitToJson: true) +class BufferRequestDto { + const BufferRequestDto({ + this.when, + this.positionTicks, + this.isPlaying, + this.playlistItemId, + }); + + factory BufferRequestDto.fromJson(Map json) => + _$BufferRequestDtoFromJson(json); + + static const toJsonFactory = _$BufferRequestDtoToJson; + Map toJson() => _$BufferRequestDtoToJson(this); + + @JsonKey(name: 'When', includeIfNull: false) + final DateTime? when; + @JsonKey(name: 'PositionTicks', includeIfNull: false) + final int? positionTicks; + @JsonKey(name: 'IsPlaying', includeIfNull: false) + final bool? isPlaying; + @JsonKey(name: 'PlaylistItemId', includeIfNull: false) + final String? playlistItemId; + static const fromJsonFactory = _$BufferRequestDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is BufferRequestDto && + (identical(other.when, when) || + const DeepCollectionEquality().equals(other.when, when)) && + (identical(other.positionTicks, positionTicks) || + const DeepCollectionEquality() + .equals(other.positionTicks, positionTicks)) && + (identical(other.isPlaying, isPlaying) || + const DeepCollectionEquality() + .equals(other.isPlaying, isPlaying)) && + (identical(other.playlistItemId, playlistItemId) || + const DeepCollectionEquality() + .equals(other.playlistItemId, playlistItemId))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(when) ^ + const DeepCollectionEquality().hash(positionTicks) ^ + const DeepCollectionEquality().hash(isPlaying) ^ + const DeepCollectionEquality().hash(playlistItemId) ^ + runtimeType.hashCode; +} + +extension $BufferRequestDtoExtension on BufferRequestDto { + BufferRequestDto copyWith( + {DateTime? when, + int? positionTicks, + bool? isPlaying, + String? playlistItemId}) { + return BufferRequestDto( + when: when ?? this.when, + positionTicks: positionTicks ?? this.positionTicks, + isPlaying: isPlaying ?? this.isPlaying, + playlistItemId: playlistItemId ?? this.playlistItemId); + } + + BufferRequestDto copyWithWrapped( + {Wrapped? when, + Wrapped? positionTicks, + Wrapped? isPlaying, + Wrapped? playlistItemId}) { + return BufferRequestDto( + when: (when != null ? when.value : this.when), + positionTicks: + (positionTicks != null ? positionTicks.value : this.positionTicks), + isPlaying: (isPlaying != null ? isPlaying.value : this.isPlaying), + playlistItemId: (playlistItemId != null + ? playlistItemId.value + : this.playlistItemId)); + } +} + +@JsonSerializable(explicitToJson: true) +class CastReceiverApplication { + const CastReceiverApplication({ + this.id, + this.name, + }); + + factory CastReceiverApplication.fromJson(Map json) => + _$CastReceiverApplicationFromJson(json); + + static const toJsonFactory = _$CastReceiverApplicationToJson; + Map toJson() => _$CastReceiverApplicationToJson(this); + + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + static const fromJsonFactory = _$CastReceiverApplicationFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is CastReceiverApplication && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(name) ^ + runtimeType.hashCode; +} + +extension $CastReceiverApplicationExtension on CastReceiverApplication { + CastReceiverApplication copyWith({String? id, String? name}) { + return CastReceiverApplication(id: id ?? this.id, name: name ?? this.name); + } + + CastReceiverApplication copyWithWrapped( + {Wrapped? id, Wrapped? name}) { + return CastReceiverApplication( + id: (id != null ? id.value : this.id), + name: (name != null ? name.value : this.name)); + } +} + +@JsonSerializable(explicitToJson: true) +class ChannelFeatures { + const ChannelFeatures({ + this.name, + this.id, + this.canSearch, + this.mediaTypes, + this.contentTypes, + this.maxPageSize, + this.autoRefreshLevels, + this.defaultSortFields, + this.supportsSortOrderToggle, + this.supportsLatestMedia, + this.canFilter, + this.supportsContentDownloading, + }); + + factory ChannelFeatures.fromJson(Map json) => + _$ChannelFeaturesFromJson(json); + + static const toJsonFactory = _$ChannelFeaturesToJson; + Map toJson() => _$ChannelFeaturesToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'CanSearch', includeIfNull: false) + final bool? canSearch; + @JsonKey( + name: 'MediaTypes', + includeIfNull: false, + toJson: channelMediaTypeListToJson, + fromJson: channelMediaTypeListFromJson, + ) + final List? mediaTypes; + @JsonKey( + name: 'ContentTypes', + includeIfNull: false, + toJson: channelMediaContentTypeListToJson, + fromJson: channelMediaContentTypeListFromJson, + ) + final List? contentTypes; + @JsonKey(name: 'MaxPageSize', includeIfNull: false) + final int? maxPageSize; + @JsonKey(name: 'AutoRefreshLevels', includeIfNull: false) + final int? autoRefreshLevels; + @JsonKey( + name: 'DefaultSortFields', + includeIfNull: false, + toJson: channelItemSortFieldListToJson, + fromJson: channelItemSortFieldListFromJson, + ) + final List? defaultSortFields; + @JsonKey(name: 'SupportsSortOrderToggle', includeIfNull: false) + final bool? supportsSortOrderToggle; + @JsonKey(name: 'SupportsLatestMedia', includeIfNull: false) + final bool? supportsLatestMedia; + @JsonKey(name: 'CanFilter', includeIfNull: false) + final bool? canFilter; + @JsonKey(name: 'SupportsContentDownloading', includeIfNull: false) + final bool? supportsContentDownloading; + static const fromJsonFactory = _$ChannelFeaturesFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ChannelFeatures && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.canSearch, canSearch) || + const DeepCollectionEquality() + .equals(other.canSearch, canSearch)) && + (identical(other.mediaTypes, mediaTypes) || + const DeepCollectionEquality() + .equals(other.mediaTypes, mediaTypes)) && + (identical(other.contentTypes, contentTypes) || + const DeepCollectionEquality() + .equals(other.contentTypes, contentTypes)) && + (identical(other.maxPageSize, maxPageSize) || + const DeepCollectionEquality() + .equals(other.maxPageSize, maxPageSize)) && + (identical(other.autoRefreshLevels, autoRefreshLevels) || + const DeepCollectionEquality() + .equals(other.autoRefreshLevels, autoRefreshLevels)) && + (identical(other.defaultSortFields, defaultSortFields) || + const DeepCollectionEquality() + .equals(other.defaultSortFields, defaultSortFields)) && + (identical( + other.supportsSortOrderToggle, supportsSortOrderToggle) || + const DeepCollectionEquality().equals( + other.supportsSortOrderToggle, supportsSortOrderToggle)) && + (identical(other.supportsLatestMedia, supportsLatestMedia) || + const DeepCollectionEquality() + .equals(other.supportsLatestMedia, supportsLatestMedia)) && + (identical(other.canFilter, canFilter) || + const DeepCollectionEquality() + .equals(other.canFilter, canFilter)) && + (identical(other.supportsContentDownloading, + supportsContentDownloading) || + const DeepCollectionEquality().equals( + other.supportsContentDownloading, + supportsContentDownloading))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(canSearch) ^ + const DeepCollectionEquality().hash(mediaTypes) ^ + const DeepCollectionEquality().hash(contentTypes) ^ + const DeepCollectionEquality().hash(maxPageSize) ^ + const DeepCollectionEquality().hash(autoRefreshLevels) ^ + const DeepCollectionEquality().hash(defaultSortFields) ^ + const DeepCollectionEquality().hash(supportsSortOrderToggle) ^ + const DeepCollectionEquality().hash(supportsLatestMedia) ^ + const DeepCollectionEquality().hash(canFilter) ^ + const DeepCollectionEquality().hash(supportsContentDownloading) ^ + runtimeType.hashCode; +} + +extension $ChannelFeaturesExtension on ChannelFeatures { + ChannelFeatures copyWith( + {String? name, + String? id, + bool? canSearch, + List? mediaTypes, + List? contentTypes, + int? maxPageSize, + int? autoRefreshLevels, + List? defaultSortFields, + bool? supportsSortOrderToggle, + bool? supportsLatestMedia, + bool? canFilter, + bool? supportsContentDownloading}) { + return ChannelFeatures( + name: name ?? this.name, + id: id ?? this.id, + canSearch: canSearch ?? this.canSearch, + mediaTypes: mediaTypes ?? this.mediaTypes, + contentTypes: contentTypes ?? this.contentTypes, + maxPageSize: maxPageSize ?? this.maxPageSize, + autoRefreshLevels: autoRefreshLevels ?? this.autoRefreshLevels, + defaultSortFields: defaultSortFields ?? this.defaultSortFields, + supportsSortOrderToggle: + supportsSortOrderToggle ?? this.supportsSortOrderToggle, + supportsLatestMedia: supportsLatestMedia ?? this.supportsLatestMedia, + canFilter: canFilter ?? this.canFilter, + supportsContentDownloading: + supportsContentDownloading ?? this.supportsContentDownloading); + } + + ChannelFeatures copyWithWrapped( + {Wrapped? name, + Wrapped? id, + Wrapped? canSearch, + Wrapped?>? mediaTypes, + Wrapped?>? contentTypes, + Wrapped? maxPageSize, + Wrapped? autoRefreshLevels, + Wrapped?>? defaultSortFields, + Wrapped? supportsSortOrderToggle, + Wrapped? supportsLatestMedia, + Wrapped? canFilter, + Wrapped? supportsContentDownloading}) { + return ChannelFeatures( + name: (name != null ? name.value : this.name), + id: (id != null ? id.value : this.id), + canSearch: (canSearch != null ? canSearch.value : this.canSearch), + mediaTypes: (mediaTypes != null ? mediaTypes.value : this.mediaTypes), + contentTypes: + (contentTypes != null ? contentTypes.value : this.contentTypes), + maxPageSize: + (maxPageSize != null ? maxPageSize.value : this.maxPageSize), + autoRefreshLevels: (autoRefreshLevels != null + ? autoRefreshLevels.value + : this.autoRefreshLevels), + defaultSortFields: (defaultSortFields != null + ? defaultSortFields.value + : this.defaultSortFields), + supportsSortOrderToggle: (supportsSortOrderToggle != null + ? supportsSortOrderToggle.value + : this.supportsSortOrderToggle), + supportsLatestMedia: (supportsLatestMedia != null + ? supportsLatestMedia.value + : this.supportsLatestMedia), + canFilter: (canFilter != null ? canFilter.value : this.canFilter), + supportsContentDownloading: (supportsContentDownloading != null + ? supportsContentDownloading.value + : this.supportsContentDownloading)); + } +} + +@JsonSerializable(explicitToJson: true) +class ChannelMappingOptionsDto { + const ChannelMappingOptionsDto({ + this.tunerChannels, + this.providerChannels, + this.mappings, + this.providerName, + }); + + factory ChannelMappingOptionsDto.fromJson(Map json) => + _$ChannelMappingOptionsDtoFromJson(json); + + static const toJsonFactory = _$ChannelMappingOptionsDtoToJson; + Map toJson() => _$ChannelMappingOptionsDtoToJson(this); + + @JsonKey( + name: 'TunerChannels', + includeIfNull: false, + defaultValue: []) + final List? tunerChannels; + @JsonKey( + name: 'ProviderChannels', + includeIfNull: false, + defaultValue: []) + final List? providerChannels; + @JsonKey( + name: 'Mappings', includeIfNull: false, defaultValue: []) + final List? mappings; + @JsonKey(name: 'ProviderName', includeIfNull: false) + final String? providerName; + static const fromJsonFactory = _$ChannelMappingOptionsDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ChannelMappingOptionsDto && + (identical(other.tunerChannels, tunerChannels) || + const DeepCollectionEquality() + .equals(other.tunerChannels, tunerChannels)) && + (identical(other.providerChannels, providerChannels) || + const DeepCollectionEquality() + .equals(other.providerChannels, providerChannels)) && + (identical(other.mappings, mappings) || + const DeepCollectionEquality() + .equals(other.mappings, mappings)) && + (identical(other.providerName, providerName) || + const DeepCollectionEquality() + .equals(other.providerName, providerName))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(tunerChannels) ^ + const DeepCollectionEquality().hash(providerChannels) ^ + const DeepCollectionEquality().hash(mappings) ^ + const DeepCollectionEquality().hash(providerName) ^ + runtimeType.hashCode; +} + +extension $ChannelMappingOptionsDtoExtension on ChannelMappingOptionsDto { + ChannelMappingOptionsDto copyWith( + {List? tunerChannels, + List? providerChannels, + List? mappings, + String? providerName}) { + return ChannelMappingOptionsDto( + tunerChannels: tunerChannels ?? this.tunerChannels, + providerChannels: providerChannels ?? this.providerChannels, + mappings: mappings ?? this.mappings, + providerName: providerName ?? this.providerName); + } + + ChannelMappingOptionsDto copyWithWrapped( + {Wrapped?>? tunerChannels, + Wrapped?>? providerChannels, + Wrapped?>? mappings, + Wrapped? providerName}) { + return ChannelMappingOptionsDto( + tunerChannels: + (tunerChannels != null ? tunerChannels.value : this.tunerChannels), + providerChannels: (providerChannels != null + ? providerChannels.value + : this.providerChannels), + mappings: (mappings != null ? mappings.value : this.mappings), + providerName: + (providerName != null ? providerName.value : this.providerName)); + } +} + +@JsonSerializable(explicitToJson: true) +class ChapterInfo { + const ChapterInfo({ + this.startPositionTicks, + this.name, + this.imagePath, + this.imageDateModified, + this.imageTag, + }); + + factory ChapterInfo.fromJson(Map json) => + _$ChapterInfoFromJson(json); + + static const toJsonFactory = _$ChapterInfoToJson; + Map toJson() => _$ChapterInfoToJson(this); + + @JsonKey(name: 'StartPositionTicks', includeIfNull: false) + final int? startPositionTicks; + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'ImagePath', includeIfNull: false) + final String? imagePath; + @JsonKey(name: 'ImageDateModified', includeIfNull: false) + final DateTime? imageDateModified; + @JsonKey(name: 'ImageTag', includeIfNull: false) + final String? imageTag; + static const fromJsonFactory = _$ChapterInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ChapterInfo && + (identical(other.startPositionTicks, startPositionTicks) || + const DeepCollectionEquality() + .equals(other.startPositionTicks, startPositionTicks)) && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.imagePath, imagePath) || + const DeepCollectionEquality() + .equals(other.imagePath, imagePath)) && + (identical(other.imageDateModified, imageDateModified) || + const DeepCollectionEquality() + .equals(other.imageDateModified, imageDateModified)) && + (identical(other.imageTag, imageTag) || + const DeepCollectionEquality() + .equals(other.imageTag, imageTag))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(startPositionTicks) ^ + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(imagePath) ^ + const DeepCollectionEquality().hash(imageDateModified) ^ + const DeepCollectionEquality().hash(imageTag) ^ + runtimeType.hashCode; +} + +extension $ChapterInfoExtension on ChapterInfo { + ChapterInfo copyWith( + {int? startPositionTicks, + String? name, + String? imagePath, + DateTime? imageDateModified, + String? imageTag}) { + return ChapterInfo( + startPositionTicks: startPositionTicks ?? this.startPositionTicks, + name: name ?? this.name, + imagePath: imagePath ?? this.imagePath, + imageDateModified: imageDateModified ?? this.imageDateModified, + imageTag: imageTag ?? this.imageTag); + } + + ChapterInfo copyWithWrapped( + {Wrapped? startPositionTicks, + Wrapped? name, + Wrapped? imagePath, + Wrapped? imageDateModified, + Wrapped? imageTag}) { + return ChapterInfo( + startPositionTicks: (startPositionTicks != null + ? startPositionTicks.value + : this.startPositionTicks), + name: (name != null ? name.value : this.name), + imagePath: (imagePath != null ? imagePath.value : this.imagePath), + imageDateModified: (imageDateModified != null + ? imageDateModified.value + : this.imageDateModified), + imageTag: (imageTag != null ? imageTag.value : this.imageTag)); + } +} + +@JsonSerializable(explicitToJson: true) +class ClientCapabilities { + const ClientCapabilities({ + this.playableMediaTypes, + this.supportedCommands, + this.supportsMediaControl, + this.supportsPersistentIdentifier, + this.deviceProfile, + this.appStoreUrl, + this.iconUrl, + this.supportsContentUploading, + this.supportsSync, + }); + + factory ClientCapabilities.fromJson(Map json) => + _$ClientCapabilitiesFromJson(json); + + static const toJsonFactory = _$ClientCapabilitiesToJson; + Map toJson() => _$ClientCapabilitiesToJson(this); + + @JsonKey( + name: 'PlayableMediaTypes', + includeIfNull: false, + toJson: mediaTypeListToJson, + fromJson: mediaTypeListFromJson, + ) + final List? playableMediaTypes; + @JsonKey( + name: 'SupportedCommands', + includeIfNull: false, + toJson: generalCommandTypeListToJson, + fromJson: generalCommandTypeListFromJson, + ) + final List? supportedCommands; + @JsonKey(name: 'SupportsMediaControl', includeIfNull: false) + final bool? supportsMediaControl; + @JsonKey(name: 'SupportsPersistentIdentifier', includeIfNull: false) + final bool? supportsPersistentIdentifier; + @JsonKey(name: 'DeviceProfile', includeIfNull: false) + final DeviceProfile? deviceProfile; + @JsonKey(name: 'AppStoreUrl', includeIfNull: false) + final String? appStoreUrl; + @JsonKey(name: 'IconUrl', includeIfNull: false) + final String? iconUrl; + @JsonKey( + name: 'SupportsContentUploading', + includeIfNull: false, + defaultValue: false) + @deprecated + final bool? supportsContentUploading; + @JsonKey(name: 'SupportsSync', includeIfNull: false, defaultValue: false) + @deprecated + final bool? supportsSync; + static const fromJsonFactory = _$ClientCapabilitiesFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ClientCapabilities && + (identical(other.playableMediaTypes, playableMediaTypes) || + const DeepCollectionEquality() + .equals(other.playableMediaTypes, playableMediaTypes)) && + (identical(other.supportedCommands, supportedCommands) || + const DeepCollectionEquality() + .equals(other.supportedCommands, supportedCommands)) && + (identical(other.supportsMediaControl, supportsMediaControl) || + const DeepCollectionEquality().equals( + other.supportsMediaControl, supportsMediaControl)) && + (identical(other.supportsPersistentIdentifier, + supportsPersistentIdentifier) || + const DeepCollectionEquality().equals( + other.supportsPersistentIdentifier, + supportsPersistentIdentifier)) && + (identical(other.deviceProfile, deviceProfile) || + const DeepCollectionEquality() + .equals(other.deviceProfile, deviceProfile)) && + (identical(other.appStoreUrl, appStoreUrl) || + const DeepCollectionEquality() + .equals(other.appStoreUrl, appStoreUrl)) && + (identical(other.iconUrl, iconUrl) || + const DeepCollectionEquality() + .equals(other.iconUrl, iconUrl)) && + (identical( + other.supportsContentUploading, supportsContentUploading) || + const DeepCollectionEquality().equals( + other.supportsContentUploading, + supportsContentUploading)) && + (identical(other.supportsSync, supportsSync) || + const DeepCollectionEquality() + .equals(other.supportsSync, supportsSync))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(playableMediaTypes) ^ + const DeepCollectionEquality().hash(supportedCommands) ^ + const DeepCollectionEquality().hash(supportsMediaControl) ^ + const DeepCollectionEquality().hash(supportsPersistentIdentifier) ^ + const DeepCollectionEquality().hash(deviceProfile) ^ + const DeepCollectionEquality().hash(appStoreUrl) ^ + const DeepCollectionEquality().hash(iconUrl) ^ + const DeepCollectionEquality().hash(supportsContentUploading) ^ + const DeepCollectionEquality().hash(supportsSync) ^ + runtimeType.hashCode; +} + +extension $ClientCapabilitiesExtension on ClientCapabilities { + ClientCapabilities copyWith( + {List? playableMediaTypes, + List? supportedCommands, + bool? supportsMediaControl, + bool? supportsPersistentIdentifier, + DeviceProfile? deviceProfile, + String? appStoreUrl, + String? iconUrl, + bool? supportsContentUploading, + bool? supportsSync}) { + return ClientCapabilities( + playableMediaTypes: playableMediaTypes ?? this.playableMediaTypes, + supportedCommands: supportedCommands ?? this.supportedCommands, + supportsMediaControl: supportsMediaControl ?? this.supportsMediaControl, + supportsPersistentIdentifier: + supportsPersistentIdentifier ?? this.supportsPersistentIdentifier, + deviceProfile: deviceProfile ?? this.deviceProfile, + appStoreUrl: appStoreUrl ?? this.appStoreUrl, + iconUrl: iconUrl ?? this.iconUrl, + supportsContentUploading: + supportsContentUploading ?? this.supportsContentUploading, + supportsSync: supportsSync ?? this.supportsSync); + } + + ClientCapabilities copyWithWrapped( + {Wrapped?>? playableMediaTypes, + Wrapped?>? supportedCommands, + Wrapped? supportsMediaControl, + Wrapped? supportsPersistentIdentifier, + Wrapped? deviceProfile, + Wrapped? appStoreUrl, + Wrapped? iconUrl, + Wrapped? supportsContentUploading, + Wrapped? supportsSync}) { + return ClientCapabilities( + playableMediaTypes: (playableMediaTypes != null + ? playableMediaTypes.value + : this.playableMediaTypes), + supportedCommands: (supportedCommands != null + ? supportedCommands.value + : this.supportedCommands), + supportsMediaControl: (supportsMediaControl != null + ? supportsMediaControl.value + : this.supportsMediaControl), + supportsPersistentIdentifier: (supportsPersistentIdentifier != null + ? supportsPersistentIdentifier.value + : this.supportsPersistentIdentifier), + deviceProfile: + (deviceProfile != null ? deviceProfile.value : this.deviceProfile), + appStoreUrl: + (appStoreUrl != null ? appStoreUrl.value : this.appStoreUrl), + iconUrl: (iconUrl != null ? iconUrl.value : this.iconUrl), + supportsContentUploading: (supportsContentUploading != null + ? supportsContentUploading.value + : this.supportsContentUploading), + supportsSync: + (supportsSync != null ? supportsSync.value : this.supportsSync)); + } +} + +@JsonSerializable(explicitToJson: true) +class ClientCapabilitiesDto { + const ClientCapabilitiesDto({ + this.playableMediaTypes, + this.supportedCommands, + this.supportsMediaControl, + this.supportsPersistentIdentifier, + this.deviceProfile, + this.appStoreUrl, + this.iconUrl, + this.supportsContentUploading, + this.supportsSync, + }); + + factory ClientCapabilitiesDto.fromJson(Map json) => + _$ClientCapabilitiesDtoFromJson(json); + + static const toJsonFactory = _$ClientCapabilitiesDtoToJson; + Map toJson() => _$ClientCapabilitiesDtoToJson(this); + + @JsonKey( + name: 'PlayableMediaTypes', + includeIfNull: false, + toJson: mediaTypeListToJson, + fromJson: mediaTypeListFromJson, + ) + final List? playableMediaTypes; + @JsonKey( + name: 'SupportedCommands', + includeIfNull: false, + toJson: generalCommandTypeListToJson, + fromJson: generalCommandTypeListFromJson, + ) + final List? supportedCommands; + @JsonKey(name: 'SupportsMediaControl', includeIfNull: false) + final bool? supportsMediaControl; + @JsonKey(name: 'SupportsPersistentIdentifier', includeIfNull: false) + final bool? supportsPersistentIdentifier; + @JsonKey(name: 'DeviceProfile', includeIfNull: false) + final DeviceProfile? deviceProfile; + @JsonKey(name: 'AppStoreUrl', includeIfNull: false) + final String? appStoreUrl; + @JsonKey(name: 'IconUrl', includeIfNull: false) + final String? iconUrl; + @JsonKey( + name: 'SupportsContentUploading', + includeIfNull: false, + defaultValue: false) + @deprecated + final bool? supportsContentUploading; + @JsonKey(name: 'SupportsSync', includeIfNull: false, defaultValue: false) + @deprecated + final bool? supportsSync; + static const fromJsonFactory = _$ClientCapabilitiesDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ClientCapabilitiesDto && + (identical(other.playableMediaTypes, playableMediaTypes) || + const DeepCollectionEquality() + .equals(other.playableMediaTypes, playableMediaTypes)) && + (identical(other.supportedCommands, supportedCommands) || + const DeepCollectionEquality() + .equals(other.supportedCommands, supportedCommands)) && + (identical(other.supportsMediaControl, supportsMediaControl) || + const DeepCollectionEquality().equals( + other.supportsMediaControl, supportsMediaControl)) && + (identical(other.supportsPersistentIdentifier, + supportsPersistentIdentifier) || + const DeepCollectionEquality().equals( + other.supportsPersistentIdentifier, + supportsPersistentIdentifier)) && + (identical(other.deviceProfile, deviceProfile) || + const DeepCollectionEquality() + .equals(other.deviceProfile, deviceProfile)) && + (identical(other.appStoreUrl, appStoreUrl) || + const DeepCollectionEquality() + .equals(other.appStoreUrl, appStoreUrl)) && + (identical(other.iconUrl, iconUrl) || + const DeepCollectionEquality() + .equals(other.iconUrl, iconUrl)) && + (identical( + other.supportsContentUploading, supportsContentUploading) || + const DeepCollectionEquality().equals( + other.supportsContentUploading, + supportsContentUploading)) && + (identical(other.supportsSync, supportsSync) || + const DeepCollectionEquality() + .equals(other.supportsSync, supportsSync))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(playableMediaTypes) ^ + const DeepCollectionEquality().hash(supportedCommands) ^ + const DeepCollectionEquality().hash(supportsMediaControl) ^ + const DeepCollectionEquality().hash(supportsPersistentIdentifier) ^ + const DeepCollectionEquality().hash(deviceProfile) ^ + const DeepCollectionEquality().hash(appStoreUrl) ^ + const DeepCollectionEquality().hash(iconUrl) ^ + const DeepCollectionEquality().hash(supportsContentUploading) ^ + const DeepCollectionEquality().hash(supportsSync) ^ + runtimeType.hashCode; +} + +extension $ClientCapabilitiesDtoExtension on ClientCapabilitiesDto { + ClientCapabilitiesDto copyWith( + {List? playableMediaTypes, + List? supportedCommands, + bool? supportsMediaControl, + bool? supportsPersistentIdentifier, + DeviceProfile? deviceProfile, + String? appStoreUrl, + String? iconUrl, + bool? supportsContentUploading, + bool? supportsSync}) { + return ClientCapabilitiesDto( + playableMediaTypes: playableMediaTypes ?? this.playableMediaTypes, + supportedCommands: supportedCommands ?? this.supportedCommands, + supportsMediaControl: supportsMediaControl ?? this.supportsMediaControl, + supportsPersistentIdentifier: + supportsPersistentIdentifier ?? this.supportsPersistentIdentifier, + deviceProfile: deviceProfile ?? this.deviceProfile, + appStoreUrl: appStoreUrl ?? this.appStoreUrl, + iconUrl: iconUrl ?? this.iconUrl, + supportsContentUploading: + supportsContentUploading ?? this.supportsContentUploading, + supportsSync: supportsSync ?? this.supportsSync); + } + + ClientCapabilitiesDto copyWithWrapped( + {Wrapped?>? playableMediaTypes, + Wrapped?>? supportedCommands, + Wrapped? supportsMediaControl, + Wrapped? supportsPersistentIdentifier, + Wrapped? deviceProfile, + Wrapped? appStoreUrl, + Wrapped? iconUrl, + Wrapped? supportsContentUploading, + Wrapped? supportsSync}) { + return ClientCapabilitiesDto( + playableMediaTypes: (playableMediaTypes != null + ? playableMediaTypes.value + : this.playableMediaTypes), + supportedCommands: (supportedCommands != null + ? supportedCommands.value + : this.supportedCommands), + supportsMediaControl: (supportsMediaControl != null + ? supportsMediaControl.value + : this.supportsMediaControl), + supportsPersistentIdentifier: (supportsPersistentIdentifier != null + ? supportsPersistentIdentifier.value + : this.supportsPersistentIdentifier), + deviceProfile: + (deviceProfile != null ? deviceProfile.value : this.deviceProfile), + appStoreUrl: + (appStoreUrl != null ? appStoreUrl.value : this.appStoreUrl), + iconUrl: (iconUrl != null ? iconUrl.value : this.iconUrl), + supportsContentUploading: (supportsContentUploading != null + ? supportsContentUploading.value + : this.supportsContentUploading), + supportsSync: + (supportsSync != null ? supportsSync.value : this.supportsSync)); + } +} + +@JsonSerializable(explicitToJson: true) +class ClientLogDocumentResponseDto { + const ClientLogDocumentResponseDto({ + this.fileName, + }); + + factory ClientLogDocumentResponseDto.fromJson(Map json) => + _$ClientLogDocumentResponseDtoFromJson(json); + + static const toJsonFactory = _$ClientLogDocumentResponseDtoToJson; + Map toJson() => _$ClientLogDocumentResponseDtoToJson(this); + + @JsonKey(name: 'FileName', includeIfNull: false) + final String? fileName; + static const fromJsonFactory = _$ClientLogDocumentResponseDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ClientLogDocumentResponseDto && + (identical(other.fileName, fileName) || + const DeepCollectionEquality() + .equals(other.fileName, fileName))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(fileName) ^ runtimeType.hashCode; +} + +extension $ClientLogDocumentResponseDtoExtension + on ClientLogDocumentResponseDto { + ClientLogDocumentResponseDto copyWith({String? fileName}) { + return ClientLogDocumentResponseDto(fileName: fileName ?? this.fileName); + } + + ClientLogDocumentResponseDto copyWithWrapped({Wrapped? fileName}) { + return ClientLogDocumentResponseDto( + fileName: (fileName != null ? fileName.value : this.fileName)); + } +} + +@JsonSerializable(explicitToJson: true) +class CodecProfile { + const CodecProfile({ + this.type, + this.conditions, + this.applyConditions, + this.codec, + this.container, + }); + + factory CodecProfile.fromJson(Map json) => + _$CodecProfileFromJson(json); + + static const toJsonFactory = _$CodecProfileToJson; + Map toJson() => _$CodecProfileToJson(this); + + @JsonKey( + name: 'Type', + includeIfNull: false, + toJson: codecTypeNullableToJson, + fromJson: codecTypeNullableFromJson, + ) + final enums.CodecType? type; + @JsonKey( + name: 'Conditions', + includeIfNull: false, + defaultValue: []) + final List? conditions; + @JsonKey( + name: 'ApplyConditions', + includeIfNull: false, + defaultValue: []) + final List? applyConditions; + @JsonKey(name: 'Codec', includeIfNull: false) + final String? codec; + @JsonKey(name: 'Container', includeIfNull: false) + final String? container; + static const fromJsonFactory = _$CodecProfileFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is CodecProfile && + (identical(other.type, type) || + const DeepCollectionEquality().equals(other.type, type)) && + (identical(other.conditions, conditions) || + const DeepCollectionEquality() + .equals(other.conditions, conditions)) && + (identical(other.applyConditions, applyConditions) || + const DeepCollectionEquality() + .equals(other.applyConditions, applyConditions)) && + (identical(other.codec, codec) || + const DeepCollectionEquality().equals(other.codec, codec)) && + (identical(other.container, container) || + const DeepCollectionEquality() + .equals(other.container, container))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(type) ^ + const DeepCollectionEquality().hash(conditions) ^ + const DeepCollectionEquality().hash(applyConditions) ^ + const DeepCollectionEquality().hash(codec) ^ + const DeepCollectionEquality().hash(container) ^ + runtimeType.hashCode; +} + +extension $CodecProfileExtension on CodecProfile { + CodecProfile copyWith( + {enums.CodecType? type, + List? conditions, + List? applyConditions, + String? codec, + String? container}) { + return CodecProfile( + type: type ?? this.type, + conditions: conditions ?? this.conditions, + applyConditions: applyConditions ?? this.applyConditions, + codec: codec ?? this.codec, + container: container ?? this.container); + } + + CodecProfile copyWithWrapped( + {Wrapped? type, + Wrapped?>? conditions, + Wrapped?>? applyConditions, + Wrapped? codec, + Wrapped? container}) { + return CodecProfile( + type: (type != null ? type.value : this.type), + conditions: (conditions != null ? conditions.value : this.conditions), + applyConditions: (applyConditions != null + ? applyConditions.value + : this.applyConditions), + codec: (codec != null ? codec.value : this.codec), + container: (container != null ? container.value : this.container)); + } +} + +@JsonSerializable(explicitToJson: true) +class CollectionCreationResult { + const CollectionCreationResult({ + this.id, + }); + + factory CollectionCreationResult.fromJson(Map json) => + _$CollectionCreationResultFromJson(json); + + static const toJsonFactory = _$CollectionCreationResultToJson; + Map toJson() => _$CollectionCreationResultToJson(this); + + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + static const fromJsonFactory = _$CollectionCreationResultFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is CollectionCreationResult && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(id) ^ runtimeType.hashCode; +} + +extension $CollectionCreationResultExtension on CollectionCreationResult { + CollectionCreationResult copyWith({String? id}) { + return CollectionCreationResult(id: id ?? this.id); + } + + CollectionCreationResult copyWithWrapped({Wrapped? id}) { + return CollectionCreationResult(id: (id != null ? id.value : this.id)); + } +} + +@JsonSerializable(explicitToJson: true) +class ConfigImageTypes { + const ConfigImageTypes({ + this.backdropSizes, + this.baseUrl, + this.logoSizes, + this.posterSizes, + this.profileSizes, + this.secureBaseUrl, + this.stillSizes, + }); + + factory ConfigImageTypes.fromJson(Map json) => + _$ConfigImageTypesFromJson(json); + + static const toJsonFactory = _$ConfigImageTypesToJson; + Map toJson() => _$ConfigImageTypesToJson(this); + + @JsonKey( + name: 'BackdropSizes', includeIfNull: false, defaultValue: []) + final List? backdropSizes; + @JsonKey(name: 'BaseUrl', includeIfNull: false) + final String? baseUrl; + @JsonKey(name: 'LogoSizes', includeIfNull: false, defaultValue: []) + final List? logoSizes; + @JsonKey(name: 'PosterSizes', includeIfNull: false, defaultValue: []) + final List? posterSizes; + @JsonKey(name: 'ProfileSizes', includeIfNull: false, defaultValue: []) + final List? profileSizes; + @JsonKey(name: 'SecureBaseUrl', includeIfNull: false) + final String? secureBaseUrl; + @JsonKey(name: 'StillSizes', includeIfNull: false, defaultValue: []) + final List? stillSizes; + static const fromJsonFactory = _$ConfigImageTypesFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ConfigImageTypes && + (identical(other.backdropSizes, backdropSizes) || + const DeepCollectionEquality() + .equals(other.backdropSizes, backdropSizes)) && + (identical(other.baseUrl, baseUrl) || + const DeepCollectionEquality() + .equals(other.baseUrl, baseUrl)) && + (identical(other.logoSizes, logoSizes) || + const DeepCollectionEquality() + .equals(other.logoSizes, logoSizes)) && + (identical(other.posterSizes, posterSizes) || + const DeepCollectionEquality() + .equals(other.posterSizes, posterSizes)) && + (identical(other.profileSizes, profileSizes) || + const DeepCollectionEquality() + .equals(other.profileSizes, profileSizes)) && + (identical(other.secureBaseUrl, secureBaseUrl) || + const DeepCollectionEquality() + .equals(other.secureBaseUrl, secureBaseUrl)) && + (identical(other.stillSizes, stillSizes) || + const DeepCollectionEquality() + .equals(other.stillSizes, stillSizes))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(backdropSizes) ^ + const DeepCollectionEquality().hash(baseUrl) ^ + const DeepCollectionEquality().hash(logoSizes) ^ + const DeepCollectionEquality().hash(posterSizes) ^ + const DeepCollectionEquality().hash(profileSizes) ^ + const DeepCollectionEquality().hash(secureBaseUrl) ^ + const DeepCollectionEquality().hash(stillSizes) ^ + runtimeType.hashCode; +} + +extension $ConfigImageTypesExtension on ConfigImageTypes { + ConfigImageTypes copyWith( + {List? backdropSizes, + String? baseUrl, + List? logoSizes, + List? posterSizes, + List? profileSizes, + String? secureBaseUrl, + List? stillSizes}) { + return ConfigImageTypes( + backdropSizes: backdropSizes ?? this.backdropSizes, + baseUrl: baseUrl ?? this.baseUrl, + logoSizes: logoSizes ?? this.logoSizes, + posterSizes: posterSizes ?? this.posterSizes, + profileSizes: profileSizes ?? this.profileSizes, + secureBaseUrl: secureBaseUrl ?? this.secureBaseUrl, + stillSizes: stillSizes ?? this.stillSizes); + } + + ConfigImageTypes copyWithWrapped( + {Wrapped?>? backdropSizes, + Wrapped? baseUrl, + Wrapped?>? logoSizes, + Wrapped?>? posterSizes, + Wrapped?>? profileSizes, + Wrapped? secureBaseUrl, + Wrapped?>? stillSizes}) { + return ConfigImageTypes( + backdropSizes: + (backdropSizes != null ? backdropSizes.value : this.backdropSizes), + baseUrl: (baseUrl != null ? baseUrl.value : this.baseUrl), + logoSizes: (logoSizes != null ? logoSizes.value : this.logoSizes), + posterSizes: + (posterSizes != null ? posterSizes.value : this.posterSizes), + profileSizes: + (profileSizes != null ? profileSizes.value : this.profileSizes), + secureBaseUrl: + (secureBaseUrl != null ? secureBaseUrl.value : this.secureBaseUrl), + stillSizes: (stillSizes != null ? stillSizes.value : this.stillSizes)); + } +} + +@JsonSerializable(explicitToJson: true) +class ConfigurationPageInfo { + const ConfigurationPageInfo({ + this.name, + this.enableInMainMenu, + this.menuSection, + this.menuIcon, + this.displayName, + this.pluginId, + }); + + factory ConfigurationPageInfo.fromJson(Map json) => + _$ConfigurationPageInfoFromJson(json); + + static const toJsonFactory = _$ConfigurationPageInfoToJson; + Map toJson() => _$ConfigurationPageInfoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'EnableInMainMenu', includeIfNull: false) + final bool? enableInMainMenu; + @JsonKey(name: 'MenuSection', includeIfNull: false) + final String? menuSection; + @JsonKey(name: 'MenuIcon', includeIfNull: false) + final String? menuIcon; + @JsonKey(name: 'DisplayName', includeIfNull: false) + final String? displayName; + @JsonKey(name: 'PluginId', includeIfNull: false) + final String? pluginId; + static const fromJsonFactory = _$ConfigurationPageInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ConfigurationPageInfo && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.enableInMainMenu, enableInMainMenu) || + const DeepCollectionEquality() + .equals(other.enableInMainMenu, enableInMainMenu)) && + (identical(other.menuSection, menuSection) || + const DeepCollectionEquality() + .equals(other.menuSection, menuSection)) && + (identical(other.menuIcon, menuIcon) || + const DeepCollectionEquality() + .equals(other.menuIcon, menuIcon)) && + (identical(other.displayName, displayName) || + const DeepCollectionEquality() + .equals(other.displayName, displayName)) && + (identical(other.pluginId, pluginId) || + const DeepCollectionEquality() + .equals(other.pluginId, pluginId))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(enableInMainMenu) ^ + const DeepCollectionEquality().hash(menuSection) ^ + const DeepCollectionEquality().hash(menuIcon) ^ + const DeepCollectionEquality().hash(displayName) ^ + const DeepCollectionEquality().hash(pluginId) ^ + runtimeType.hashCode; +} + +extension $ConfigurationPageInfoExtension on ConfigurationPageInfo { + ConfigurationPageInfo copyWith( + {String? name, + bool? enableInMainMenu, + String? menuSection, + String? menuIcon, + String? displayName, + String? pluginId}) { + return ConfigurationPageInfo( + name: name ?? this.name, + enableInMainMenu: enableInMainMenu ?? this.enableInMainMenu, + menuSection: menuSection ?? this.menuSection, + menuIcon: menuIcon ?? this.menuIcon, + displayName: displayName ?? this.displayName, + pluginId: pluginId ?? this.pluginId); + } + + ConfigurationPageInfo copyWithWrapped( + {Wrapped? name, + Wrapped? enableInMainMenu, + Wrapped? menuSection, + Wrapped? menuIcon, + Wrapped? displayName, + Wrapped? pluginId}) { + return ConfigurationPageInfo( + name: (name != null ? name.value : this.name), + enableInMainMenu: (enableInMainMenu != null + ? enableInMainMenu.value + : this.enableInMainMenu), + menuSection: + (menuSection != null ? menuSection.value : this.menuSection), + menuIcon: (menuIcon != null ? menuIcon.value : this.menuIcon), + displayName: + (displayName != null ? displayName.value : this.displayName), + pluginId: (pluginId != null ? pluginId.value : this.pluginId)); + } +} + +@JsonSerializable(explicitToJson: true) +class ContainerProfile { + const ContainerProfile({ + this.type, + this.conditions, + this.container, + }); + + factory ContainerProfile.fromJson(Map json) => + _$ContainerProfileFromJson(json); + + static const toJsonFactory = _$ContainerProfileToJson; + Map toJson() => _$ContainerProfileToJson(this); + + @JsonKey( + name: 'Type', + includeIfNull: false, + toJson: dlnaProfileTypeNullableToJson, + fromJson: dlnaProfileTypeNullableFromJson, + ) + final enums.DlnaProfileType? type; + @JsonKey( + name: 'Conditions', + includeIfNull: false, + defaultValue: []) + final List? conditions; + @JsonKey(name: 'Container', includeIfNull: false) + final String? container; + static const fromJsonFactory = _$ContainerProfileFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ContainerProfile && + (identical(other.type, type) || + const DeepCollectionEquality().equals(other.type, type)) && + (identical(other.conditions, conditions) || + const DeepCollectionEquality() + .equals(other.conditions, conditions)) && + (identical(other.container, container) || + const DeepCollectionEquality() + .equals(other.container, container))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(type) ^ + const DeepCollectionEquality().hash(conditions) ^ + const DeepCollectionEquality().hash(container) ^ + runtimeType.hashCode; +} + +extension $ContainerProfileExtension on ContainerProfile { + ContainerProfile copyWith( + {enums.DlnaProfileType? type, + List? conditions, + String? container}) { + return ContainerProfile( + type: type ?? this.type, + conditions: conditions ?? this.conditions, + container: container ?? this.container); + } + + ContainerProfile copyWithWrapped( + {Wrapped? type, + Wrapped?>? conditions, + Wrapped? container}) { + return ContainerProfile( + type: (type != null ? type.value : this.type), + conditions: (conditions != null ? conditions.value : this.conditions), + container: (container != null ? container.value : this.container)); + } +} + +@JsonSerializable(explicitToJson: true) +class CountryInfo { + const CountryInfo({ + this.name, + this.displayName, + this.twoLetterISORegionName, + this.threeLetterISORegionName, + }); + + factory CountryInfo.fromJson(Map json) => + _$CountryInfoFromJson(json); + + static const toJsonFactory = _$CountryInfoToJson; + Map toJson() => _$CountryInfoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'DisplayName', includeIfNull: false) + final String? displayName; + @JsonKey(name: 'TwoLetterISORegionName', includeIfNull: false) + final String? twoLetterISORegionName; + @JsonKey(name: 'ThreeLetterISORegionName', includeIfNull: false) + final String? threeLetterISORegionName; + static const fromJsonFactory = _$CountryInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is CountryInfo && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.displayName, displayName) || + const DeepCollectionEquality() + .equals(other.displayName, displayName)) && + (identical(other.twoLetterISORegionName, twoLetterISORegionName) || + const DeepCollectionEquality().equals( + other.twoLetterISORegionName, twoLetterISORegionName)) && + (identical( + other.threeLetterISORegionName, threeLetterISORegionName) || + const DeepCollectionEquality().equals( + other.threeLetterISORegionName, threeLetterISORegionName))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(displayName) ^ + const DeepCollectionEquality().hash(twoLetterISORegionName) ^ + const DeepCollectionEquality().hash(threeLetterISORegionName) ^ + runtimeType.hashCode; +} + +extension $CountryInfoExtension on CountryInfo { + CountryInfo copyWith( + {String? name, + String? displayName, + String? twoLetterISORegionName, + String? threeLetterISORegionName}) { + return CountryInfo( + name: name ?? this.name, + displayName: displayName ?? this.displayName, + twoLetterISORegionName: + twoLetterISORegionName ?? this.twoLetterISORegionName, + threeLetterISORegionName: + threeLetterISORegionName ?? this.threeLetterISORegionName); + } + + CountryInfo copyWithWrapped( + {Wrapped? name, + Wrapped? displayName, + Wrapped? twoLetterISORegionName, + Wrapped? threeLetterISORegionName}) { + return CountryInfo( + name: (name != null ? name.value : this.name), + displayName: + (displayName != null ? displayName.value : this.displayName), + twoLetterISORegionName: (twoLetterISORegionName != null + ? twoLetterISORegionName.value + : this.twoLetterISORegionName), + threeLetterISORegionName: (threeLetterISORegionName != null + ? threeLetterISORegionName.value + : this.threeLetterISORegionName)); + } +} + +@JsonSerializable(explicitToJson: true) +class CreatePlaylistDto { + const CreatePlaylistDto({ + this.name, + this.ids, + this.userId, + this.mediaType, + this.users, + this.isPublic, + }); + + factory CreatePlaylistDto.fromJson(Map json) => + _$CreatePlaylistDtoFromJson(json); + + static const toJsonFactory = _$CreatePlaylistDtoToJson; + Map toJson() => _$CreatePlaylistDtoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'Ids', includeIfNull: false, defaultValue: []) + final List? ids; + @JsonKey(name: 'UserId', includeIfNull: false) + final String? userId; + @JsonKey( + name: 'MediaType', + includeIfNull: false, + toJson: mediaTypeNullableToJson, + fromJson: mediaTypeNullableFromJson, + ) + final enums.MediaType? mediaType; + @JsonKey( + name: 'Users', + includeIfNull: false, + defaultValue: []) + final List? users; + @JsonKey(name: 'IsPublic', includeIfNull: false) + final bool? isPublic; + static const fromJsonFactory = _$CreatePlaylistDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is CreatePlaylistDto && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.ids, ids) || + const DeepCollectionEquality().equals(other.ids, ids)) && + (identical(other.userId, userId) || + const DeepCollectionEquality().equals(other.userId, userId)) && + (identical(other.mediaType, mediaType) || + const DeepCollectionEquality() + .equals(other.mediaType, mediaType)) && + (identical(other.users, users) || + const DeepCollectionEquality().equals(other.users, users)) && + (identical(other.isPublic, isPublic) || + const DeepCollectionEquality() + .equals(other.isPublic, isPublic))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(ids) ^ + const DeepCollectionEquality().hash(userId) ^ + const DeepCollectionEquality().hash(mediaType) ^ + const DeepCollectionEquality().hash(users) ^ + const DeepCollectionEquality().hash(isPublic) ^ + runtimeType.hashCode; +} + +extension $CreatePlaylistDtoExtension on CreatePlaylistDto { + CreatePlaylistDto copyWith( + {String? name, + List? ids, + String? userId, + enums.MediaType? mediaType, + List? users, + bool? isPublic}) { + return CreatePlaylistDto( + name: name ?? this.name, + ids: ids ?? this.ids, + userId: userId ?? this.userId, + mediaType: mediaType ?? this.mediaType, + users: users ?? this.users, + isPublic: isPublic ?? this.isPublic); + } + + CreatePlaylistDto copyWithWrapped( + {Wrapped? name, + Wrapped?>? ids, + Wrapped? userId, + Wrapped? mediaType, + Wrapped?>? users, + Wrapped? isPublic}) { + return CreatePlaylistDto( + name: (name != null ? name.value : this.name), + ids: (ids != null ? ids.value : this.ids), + userId: (userId != null ? userId.value : this.userId), + mediaType: (mediaType != null ? mediaType.value : this.mediaType), + users: (users != null ? users.value : this.users), + isPublic: (isPublic != null ? isPublic.value : this.isPublic)); + } +} + +@JsonSerializable(explicitToJson: true) +class CreateUserByName { + const CreateUserByName({ + required this.name, + this.password, + }); + + factory CreateUserByName.fromJson(Map json) => + _$CreateUserByNameFromJson(json); + + static const toJsonFactory = _$CreateUserByNameToJson; + Map toJson() => _$CreateUserByNameToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String name; + @JsonKey(name: 'Password', includeIfNull: false) + final String? password; + static const fromJsonFactory = _$CreateUserByNameFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is CreateUserByName && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.password, password) || + const DeepCollectionEquality() + .equals(other.password, password))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(password) ^ + runtimeType.hashCode; +} + +extension $CreateUserByNameExtension on CreateUserByName { + CreateUserByName copyWith({String? name, String? password}) { + return CreateUserByName( + name: name ?? this.name, password: password ?? this.password); + } + + CreateUserByName copyWithWrapped( + {Wrapped? name, Wrapped? password}) { + return CreateUserByName( + name: (name != null ? name.value : this.name), + password: (password != null ? password.value : this.password)); + } +} + +@JsonSerializable(explicitToJson: true) +class CultureDto { + const CultureDto({ + this.name, + this.displayName, + this.twoLetterISOLanguageName, + this.threeLetterISOLanguageName, + this.threeLetterISOLanguageNames, + }); + + factory CultureDto.fromJson(Map json) => + _$CultureDtoFromJson(json); + + static const toJsonFactory = _$CultureDtoToJson; + Map toJson() => _$CultureDtoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'DisplayName', includeIfNull: false) + final String? displayName; + @JsonKey(name: 'TwoLetterISOLanguageName', includeIfNull: false) + final String? twoLetterISOLanguageName; + @JsonKey(name: 'ThreeLetterISOLanguageName', includeIfNull: false) + final String? threeLetterISOLanguageName; + @JsonKey( + name: 'ThreeLetterISOLanguageNames', + includeIfNull: false, + defaultValue: []) + final List? threeLetterISOLanguageNames; + static const fromJsonFactory = _$CultureDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is CultureDto && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.displayName, displayName) || + const DeepCollectionEquality() + .equals(other.displayName, displayName)) && + (identical( + other.twoLetterISOLanguageName, twoLetterISOLanguageName) || + const DeepCollectionEquality().equals( + other.twoLetterISOLanguageName, + twoLetterISOLanguageName)) && + (identical(other.threeLetterISOLanguageName, + threeLetterISOLanguageName) || + const DeepCollectionEquality().equals( + other.threeLetterISOLanguageName, + threeLetterISOLanguageName)) && + (identical(other.threeLetterISOLanguageNames, + threeLetterISOLanguageNames) || + const DeepCollectionEquality().equals( + other.threeLetterISOLanguageNames, + threeLetterISOLanguageNames))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(displayName) ^ + const DeepCollectionEquality().hash(twoLetterISOLanguageName) ^ + const DeepCollectionEquality().hash(threeLetterISOLanguageName) ^ + const DeepCollectionEquality().hash(threeLetterISOLanguageNames) ^ + runtimeType.hashCode; +} + +extension $CultureDtoExtension on CultureDto { + CultureDto copyWith( + {String? name, + String? displayName, + String? twoLetterISOLanguageName, + String? threeLetterISOLanguageName, + List? threeLetterISOLanguageNames}) { + return CultureDto( + name: name ?? this.name, + displayName: displayName ?? this.displayName, + twoLetterISOLanguageName: + twoLetterISOLanguageName ?? this.twoLetterISOLanguageName, + threeLetterISOLanguageName: + threeLetterISOLanguageName ?? this.threeLetterISOLanguageName, + threeLetterISOLanguageNames: + threeLetterISOLanguageNames ?? this.threeLetterISOLanguageNames); + } + + CultureDto copyWithWrapped( + {Wrapped? name, + Wrapped? displayName, + Wrapped? twoLetterISOLanguageName, + Wrapped? threeLetterISOLanguageName, + Wrapped?>? threeLetterISOLanguageNames}) { + return CultureDto( + name: (name != null ? name.value : this.name), + displayName: + (displayName != null ? displayName.value : this.displayName), + twoLetterISOLanguageName: (twoLetterISOLanguageName != null + ? twoLetterISOLanguageName.value + : this.twoLetterISOLanguageName), + threeLetterISOLanguageName: (threeLetterISOLanguageName != null + ? threeLetterISOLanguageName.value + : this.threeLetterISOLanguageName), + threeLetterISOLanguageNames: (threeLetterISOLanguageNames != null + ? threeLetterISOLanguageNames.value + : this.threeLetterISOLanguageNames)); + } +} + +@JsonSerializable(explicitToJson: true) +class CustomQueryData { + const CustomQueryData({ + this.customQueryString, + this.replaceUserId, + }); + + factory CustomQueryData.fromJson(Map json) => + _$CustomQueryDataFromJson(json); + + static const toJsonFactory = _$CustomQueryDataToJson; + Map toJson() => _$CustomQueryDataToJson(this); + + @JsonKey(name: 'CustomQueryString', includeIfNull: false) + final String? customQueryString; + @JsonKey(name: 'ReplaceUserId', includeIfNull: false) + final bool? replaceUserId; + static const fromJsonFactory = _$CustomQueryDataFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is CustomQueryData && + (identical(other.customQueryString, customQueryString) || + const DeepCollectionEquality() + .equals(other.customQueryString, customQueryString)) && + (identical(other.replaceUserId, replaceUserId) || + const DeepCollectionEquality() + .equals(other.replaceUserId, replaceUserId))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(customQueryString) ^ + const DeepCollectionEquality().hash(replaceUserId) ^ + runtimeType.hashCode; +} + +extension $CustomQueryDataExtension on CustomQueryData { + CustomQueryData copyWith({String? customQueryString, bool? replaceUserId}) { + return CustomQueryData( + customQueryString: customQueryString ?? this.customQueryString, + replaceUserId: replaceUserId ?? this.replaceUserId); + } + + CustomQueryData copyWithWrapped( + {Wrapped? customQueryString, Wrapped? replaceUserId}) { + return CustomQueryData( + customQueryString: (customQueryString != null + ? customQueryString.value + : this.customQueryString), + replaceUserId: + (replaceUserId != null ? replaceUserId.value : this.replaceUserId)); + } +} + +@JsonSerializable(explicitToJson: true) +class DefaultDirectoryBrowserInfoDto { + const DefaultDirectoryBrowserInfoDto({ + this.path, + }); + + factory DefaultDirectoryBrowserInfoDto.fromJson(Map json) => + _$DefaultDirectoryBrowserInfoDtoFromJson(json); + + static const toJsonFactory = _$DefaultDirectoryBrowserInfoDtoToJson; + Map toJson() => _$DefaultDirectoryBrowserInfoDtoToJson(this); + + @JsonKey(name: 'Path', includeIfNull: false) + final String? path; + static const fromJsonFactory = _$DefaultDirectoryBrowserInfoDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is DefaultDirectoryBrowserInfoDto && + (identical(other.path, path) || + const DeepCollectionEquality().equals(other.path, path))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(path) ^ runtimeType.hashCode; +} + +extension $DefaultDirectoryBrowserInfoDtoExtension + on DefaultDirectoryBrowserInfoDto { + DefaultDirectoryBrowserInfoDto copyWith({String? path}) { + return DefaultDirectoryBrowserInfoDto(path: path ?? this.path); + } + + DefaultDirectoryBrowserInfoDto copyWithWrapped({Wrapped? path}) { + return DefaultDirectoryBrowserInfoDto( + path: (path != null ? path.value : this.path)); + } +} + +@JsonSerializable(explicitToJson: true) +class DeviceInfo { + const DeviceInfo({ + this.name, + this.customName, + this.accessToken, + this.id, + this.lastUserName, + this.appName, + this.appVersion, + this.lastUserId, + this.dateLastActivity, + this.capabilities, + this.iconUrl, + }); + + factory DeviceInfo.fromJson(Map json) => + _$DeviceInfoFromJson(json); + + static const toJsonFactory = _$DeviceInfoToJson; + Map toJson() => _$DeviceInfoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'CustomName', includeIfNull: false) + final String? customName; + @JsonKey(name: 'AccessToken', includeIfNull: false) + final String? accessToken; + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'LastUserName', includeIfNull: false) + final String? lastUserName; + @JsonKey(name: 'AppName', includeIfNull: false) + final String? appName; + @JsonKey(name: 'AppVersion', includeIfNull: false) + final String? appVersion; + @JsonKey(name: 'LastUserId', includeIfNull: false) + final String? lastUserId; + @JsonKey(name: 'DateLastActivity', includeIfNull: false) + final DateTime? dateLastActivity; + @JsonKey(name: 'Capabilities', includeIfNull: false) + final ClientCapabilities? capabilities; + @JsonKey(name: 'IconUrl', includeIfNull: false) + final String? iconUrl; + static const fromJsonFactory = _$DeviceInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is DeviceInfo && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.customName, customName) || + const DeepCollectionEquality() + .equals(other.customName, customName)) && + (identical(other.accessToken, accessToken) || + const DeepCollectionEquality() + .equals(other.accessToken, accessToken)) && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.lastUserName, lastUserName) || + const DeepCollectionEquality() + .equals(other.lastUserName, lastUserName)) && + (identical(other.appName, appName) || + const DeepCollectionEquality() + .equals(other.appName, appName)) && + (identical(other.appVersion, appVersion) || + const DeepCollectionEquality() + .equals(other.appVersion, appVersion)) && + (identical(other.lastUserId, lastUserId) || + const DeepCollectionEquality() + .equals(other.lastUserId, lastUserId)) && + (identical(other.dateLastActivity, dateLastActivity) || + const DeepCollectionEquality() + .equals(other.dateLastActivity, dateLastActivity)) && + (identical(other.capabilities, capabilities) || + const DeepCollectionEquality() + .equals(other.capabilities, capabilities)) && + (identical(other.iconUrl, iconUrl) || + const DeepCollectionEquality().equals(other.iconUrl, iconUrl))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(customName) ^ + const DeepCollectionEquality().hash(accessToken) ^ + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(lastUserName) ^ + const DeepCollectionEquality().hash(appName) ^ + const DeepCollectionEquality().hash(appVersion) ^ + const DeepCollectionEquality().hash(lastUserId) ^ + const DeepCollectionEquality().hash(dateLastActivity) ^ + const DeepCollectionEquality().hash(capabilities) ^ + const DeepCollectionEquality().hash(iconUrl) ^ + runtimeType.hashCode; +} + +extension $DeviceInfoExtension on DeviceInfo { + DeviceInfo copyWith( + {String? name, + String? customName, + String? accessToken, + String? id, + String? lastUserName, + String? appName, + String? appVersion, + String? lastUserId, + DateTime? dateLastActivity, + ClientCapabilities? capabilities, + String? iconUrl}) { + return DeviceInfo( + name: name ?? this.name, + customName: customName ?? this.customName, + accessToken: accessToken ?? this.accessToken, + id: id ?? this.id, + lastUserName: lastUserName ?? this.lastUserName, + appName: appName ?? this.appName, + appVersion: appVersion ?? this.appVersion, + lastUserId: lastUserId ?? this.lastUserId, + dateLastActivity: dateLastActivity ?? this.dateLastActivity, + capabilities: capabilities ?? this.capabilities, + iconUrl: iconUrl ?? this.iconUrl); + } + + DeviceInfo copyWithWrapped( + {Wrapped? name, + Wrapped? customName, + Wrapped? accessToken, + Wrapped? id, + Wrapped? lastUserName, + Wrapped? appName, + Wrapped? appVersion, + Wrapped? lastUserId, + Wrapped? dateLastActivity, + Wrapped? capabilities, + Wrapped? iconUrl}) { + return DeviceInfo( + name: (name != null ? name.value : this.name), + customName: (customName != null ? customName.value : this.customName), + accessToken: + (accessToken != null ? accessToken.value : this.accessToken), + id: (id != null ? id.value : this.id), + lastUserName: + (lastUserName != null ? lastUserName.value : this.lastUserName), + appName: (appName != null ? appName.value : this.appName), + appVersion: (appVersion != null ? appVersion.value : this.appVersion), + lastUserId: (lastUserId != null ? lastUserId.value : this.lastUserId), + dateLastActivity: (dateLastActivity != null + ? dateLastActivity.value + : this.dateLastActivity), + capabilities: + (capabilities != null ? capabilities.value : this.capabilities), + iconUrl: (iconUrl != null ? iconUrl.value : this.iconUrl)); + } +} + +@JsonSerializable(explicitToJson: true) +class DeviceInfoQueryResult { + const DeviceInfoQueryResult({ + this.items, + this.totalRecordCount, + this.startIndex, + }); + + factory DeviceInfoQueryResult.fromJson(Map json) => + _$DeviceInfoQueryResultFromJson(json); + + static const toJsonFactory = _$DeviceInfoQueryResultToJson; + Map toJson() => _$DeviceInfoQueryResultToJson(this); + + @JsonKey(name: 'Items', includeIfNull: false, defaultValue: []) + final List? items; + @JsonKey(name: 'TotalRecordCount', includeIfNull: false) + final int? totalRecordCount; + @JsonKey(name: 'StartIndex', includeIfNull: false) + final int? startIndex; + static const fromJsonFactory = _$DeviceInfoQueryResultFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is DeviceInfoQueryResult && + (identical(other.items, items) || + const DeepCollectionEquality().equals(other.items, items)) && + (identical(other.totalRecordCount, totalRecordCount) || + const DeepCollectionEquality() + .equals(other.totalRecordCount, totalRecordCount)) && + (identical(other.startIndex, startIndex) || + const DeepCollectionEquality() + .equals(other.startIndex, startIndex))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(items) ^ + const DeepCollectionEquality().hash(totalRecordCount) ^ + const DeepCollectionEquality().hash(startIndex) ^ + runtimeType.hashCode; +} + +extension $DeviceInfoQueryResultExtension on DeviceInfoQueryResult { + DeviceInfoQueryResult copyWith( + {List? items, int? totalRecordCount, int? startIndex}) { + return DeviceInfoQueryResult( + items: items ?? this.items, + totalRecordCount: totalRecordCount ?? this.totalRecordCount, + startIndex: startIndex ?? this.startIndex); + } + + DeviceInfoQueryResult copyWithWrapped( + {Wrapped?>? items, + Wrapped? totalRecordCount, + Wrapped? startIndex}) { + return DeviceInfoQueryResult( + items: (items != null ? items.value : this.items), + totalRecordCount: (totalRecordCount != null + ? totalRecordCount.value + : this.totalRecordCount), + startIndex: (startIndex != null ? startIndex.value : this.startIndex)); + } +} + +@JsonSerializable(explicitToJson: true) +class DeviceOptions { + const DeviceOptions({ + this.id, + this.deviceId, + this.customName, + }); + + factory DeviceOptions.fromJson(Map json) => + _$DeviceOptionsFromJson(json); + + static const toJsonFactory = _$DeviceOptionsToJson; + Map toJson() => _$DeviceOptionsToJson(this); + + @JsonKey(name: 'Id', includeIfNull: false) + final int? id; + @JsonKey(name: 'DeviceId', includeIfNull: false) + final String? deviceId; + @JsonKey(name: 'CustomName', includeIfNull: false) + final String? customName; + static const fromJsonFactory = _$DeviceOptionsFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is DeviceOptions && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.deviceId, deviceId) || + const DeepCollectionEquality() + .equals(other.deviceId, deviceId)) && + (identical(other.customName, customName) || + const DeepCollectionEquality() + .equals(other.customName, customName))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(deviceId) ^ + const DeepCollectionEquality().hash(customName) ^ + runtimeType.hashCode; +} + +extension $DeviceOptionsExtension on DeviceOptions { + DeviceOptions copyWith({int? id, String? deviceId, String? customName}) { + return DeviceOptions( + id: id ?? this.id, + deviceId: deviceId ?? this.deviceId, + customName: customName ?? this.customName); + } + + DeviceOptions copyWithWrapped( + {Wrapped? id, + Wrapped? deviceId, + Wrapped? customName}) { + return DeviceOptions( + id: (id != null ? id.value : this.id), + deviceId: (deviceId != null ? deviceId.value : this.deviceId), + customName: (customName != null ? customName.value : this.customName)); + } +} + +@JsonSerializable(explicitToJson: true) +class DeviceOptionsDto { + const DeviceOptionsDto({ + this.id, + this.deviceId, + this.customName, + }); + + factory DeviceOptionsDto.fromJson(Map json) => + _$DeviceOptionsDtoFromJson(json); + + static const toJsonFactory = _$DeviceOptionsDtoToJson; + Map toJson() => _$DeviceOptionsDtoToJson(this); + + @JsonKey(name: 'Id', includeIfNull: false) + final int? id; + @JsonKey(name: 'DeviceId', includeIfNull: false) + final String? deviceId; + @JsonKey(name: 'CustomName', includeIfNull: false) + final String? customName; + static const fromJsonFactory = _$DeviceOptionsDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is DeviceOptionsDto && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.deviceId, deviceId) || + const DeepCollectionEquality() + .equals(other.deviceId, deviceId)) && + (identical(other.customName, customName) || + const DeepCollectionEquality() + .equals(other.customName, customName))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(deviceId) ^ + const DeepCollectionEquality().hash(customName) ^ + runtimeType.hashCode; +} + +extension $DeviceOptionsDtoExtension on DeviceOptionsDto { + DeviceOptionsDto copyWith({int? id, String? deviceId, String? customName}) { + return DeviceOptionsDto( + id: id ?? this.id, + deviceId: deviceId ?? this.deviceId, + customName: customName ?? this.customName); + } + + DeviceOptionsDto copyWithWrapped( + {Wrapped? id, + Wrapped? deviceId, + Wrapped? customName}) { + return DeviceOptionsDto( + id: (id != null ? id.value : this.id), + deviceId: (deviceId != null ? deviceId.value : this.deviceId), + customName: (customName != null ? customName.value : this.customName)); + } +} + +@JsonSerializable(explicitToJson: true) +class DeviceProfile { + const DeviceProfile({ + this.name, + this.id, + this.maxStreamingBitrate, + this.maxStaticBitrate, + this.musicStreamingTranscodingBitrate, + this.maxStaticMusicBitrate, + this.directPlayProfiles, + this.transcodingProfiles, + this.containerProfiles, + this.codecProfiles, + this.subtitleProfiles, + }); + + factory DeviceProfile.fromJson(Map json) => + _$DeviceProfileFromJson(json); + + static const toJsonFactory = _$DeviceProfileToJson; + Map toJson() => _$DeviceProfileToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'MaxStreamingBitrate', includeIfNull: false) + final int? maxStreamingBitrate; + @JsonKey(name: 'MaxStaticBitrate', includeIfNull: false) + final int? maxStaticBitrate; + @JsonKey(name: 'MusicStreamingTranscodingBitrate', includeIfNull: false) + final int? musicStreamingTranscodingBitrate; + @JsonKey(name: 'MaxStaticMusicBitrate', includeIfNull: false) + final int? maxStaticMusicBitrate; + @JsonKey( + name: 'DirectPlayProfiles', + includeIfNull: false, + defaultValue: []) + final List? directPlayProfiles; + @JsonKey( + name: 'TranscodingProfiles', + includeIfNull: false, + defaultValue: []) + final List? transcodingProfiles; + @JsonKey( + name: 'ContainerProfiles', + includeIfNull: false, + defaultValue: []) + final List? containerProfiles; + @JsonKey( + name: 'CodecProfiles', + includeIfNull: false, + defaultValue: []) + final List? codecProfiles; + @JsonKey( + name: 'SubtitleProfiles', + includeIfNull: false, + defaultValue: []) + final List? subtitleProfiles; + static const fromJsonFactory = _$DeviceProfileFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is DeviceProfile && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.maxStreamingBitrate, maxStreamingBitrate) || + const DeepCollectionEquality() + .equals(other.maxStreamingBitrate, maxStreamingBitrate)) && + (identical(other.maxStaticBitrate, maxStaticBitrate) || + const DeepCollectionEquality() + .equals(other.maxStaticBitrate, maxStaticBitrate)) && + (identical(other.musicStreamingTranscodingBitrate, + musicStreamingTranscodingBitrate) || + const DeepCollectionEquality().equals( + other.musicStreamingTranscodingBitrate, + musicStreamingTranscodingBitrate)) && + (identical(other.maxStaticMusicBitrate, maxStaticMusicBitrate) || + const DeepCollectionEquality().equals( + other.maxStaticMusicBitrate, maxStaticMusicBitrate)) && + (identical(other.directPlayProfiles, directPlayProfiles) || + const DeepCollectionEquality() + .equals(other.directPlayProfiles, directPlayProfiles)) && + (identical(other.transcodingProfiles, transcodingProfiles) || + const DeepCollectionEquality() + .equals(other.transcodingProfiles, transcodingProfiles)) && + (identical(other.containerProfiles, containerProfiles) || + const DeepCollectionEquality() + .equals(other.containerProfiles, containerProfiles)) && + (identical(other.codecProfiles, codecProfiles) || + const DeepCollectionEquality() + .equals(other.codecProfiles, codecProfiles)) && + (identical(other.subtitleProfiles, subtitleProfiles) || + const DeepCollectionEquality() + .equals(other.subtitleProfiles, subtitleProfiles))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(maxStreamingBitrate) ^ + const DeepCollectionEquality().hash(maxStaticBitrate) ^ + const DeepCollectionEquality().hash(musicStreamingTranscodingBitrate) ^ + const DeepCollectionEquality().hash(maxStaticMusicBitrate) ^ + const DeepCollectionEquality().hash(directPlayProfiles) ^ + const DeepCollectionEquality().hash(transcodingProfiles) ^ + const DeepCollectionEquality().hash(containerProfiles) ^ + const DeepCollectionEquality().hash(codecProfiles) ^ + const DeepCollectionEquality().hash(subtitleProfiles) ^ + runtimeType.hashCode; +} + +extension $DeviceProfileExtension on DeviceProfile { + DeviceProfile copyWith( + {String? name, + String? id, + int? maxStreamingBitrate, + int? maxStaticBitrate, + int? musicStreamingTranscodingBitrate, + int? maxStaticMusicBitrate, + List? directPlayProfiles, + List? transcodingProfiles, + List? containerProfiles, + List? codecProfiles, + List? subtitleProfiles}) { + return DeviceProfile( + name: name ?? this.name, + id: id ?? this.id, + maxStreamingBitrate: maxStreamingBitrate ?? this.maxStreamingBitrate, + maxStaticBitrate: maxStaticBitrate ?? this.maxStaticBitrate, + musicStreamingTranscodingBitrate: musicStreamingTranscodingBitrate ?? + this.musicStreamingTranscodingBitrate, + maxStaticMusicBitrate: + maxStaticMusicBitrate ?? this.maxStaticMusicBitrate, + directPlayProfiles: directPlayProfiles ?? this.directPlayProfiles, + transcodingProfiles: transcodingProfiles ?? this.transcodingProfiles, + containerProfiles: containerProfiles ?? this.containerProfiles, + codecProfiles: codecProfiles ?? this.codecProfiles, + subtitleProfiles: subtitleProfiles ?? this.subtitleProfiles); + } + + DeviceProfile copyWithWrapped( + {Wrapped? name, + Wrapped? id, + Wrapped? maxStreamingBitrate, + Wrapped? maxStaticBitrate, + Wrapped? musicStreamingTranscodingBitrate, + Wrapped? maxStaticMusicBitrate, + Wrapped?>? directPlayProfiles, + Wrapped?>? transcodingProfiles, + Wrapped?>? containerProfiles, + Wrapped?>? codecProfiles, + Wrapped?>? subtitleProfiles}) { + return DeviceProfile( + name: (name != null ? name.value : this.name), + id: (id != null ? id.value : this.id), + maxStreamingBitrate: (maxStreamingBitrate != null + ? maxStreamingBitrate.value + : this.maxStreamingBitrate), + maxStaticBitrate: (maxStaticBitrate != null + ? maxStaticBitrate.value + : this.maxStaticBitrate), + musicStreamingTranscodingBitrate: + (musicStreamingTranscodingBitrate != null + ? musicStreamingTranscodingBitrate.value + : this.musicStreamingTranscodingBitrate), + maxStaticMusicBitrate: (maxStaticMusicBitrate != null + ? maxStaticMusicBitrate.value + : this.maxStaticMusicBitrate), + directPlayProfiles: (directPlayProfiles != null + ? directPlayProfiles.value + : this.directPlayProfiles), + transcodingProfiles: (transcodingProfiles != null + ? transcodingProfiles.value + : this.transcodingProfiles), + containerProfiles: (containerProfiles != null + ? containerProfiles.value + : this.containerProfiles), + codecProfiles: + (codecProfiles != null ? codecProfiles.value : this.codecProfiles), + subtitleProfiles: (subtitleProfiles != null + ? subtitleProfiles.value + : this.subtitleProfiles)); + } +} + +@JsonSerializable(explicitToJson: true) +class DirectPlayProfile { + const DirectPlayProfile({ + this.container, + this.audioCodec, + this.videoCodec, + this.type, + }); + + factory DirectPlayProfile.fromJson(Map json) => + _$DirectPlayProfileFromJson(json); + + static const toJsonFactory = _$DirectPlayProfileToJson; + Map toJson() => _$DirectPlayProfileToJson(this); + + @JsonKey(name: 'Container', includeIfNull: false) + final String? container; + @JsonKey(name: 'AudioCodec', includeIfNull: false) + final String? audioCodec; + @JsonKey(name: 'VideoCodec', includeIfNull: false) + final String? videoCodec; + @JsonKey( + name: 'Type', + includeIfNull: false, + toJson: dlnaProfileTypeNullableToJson, + fromJson: dlnaProfileTypeNullableFromJson, + ) + final enums.DlnaProfileType? type; + static const fromJsonFactory = _$DirectPlayProfileFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is DirectPlayProfile && + (identical(other.container, container) || + const DeepCollectionEquality() + .equals(other.container, container)) && + (identical(other.audioCodec, audioCodec) || + const DeepCollectionEquality() + .equals(other.audioCodec, audioCodec)) && + (identical(other.videoCodec, videoCodec) || + const DeepCollectionEquality() + .equals(other.videoCodec, videoCodec)) && + (identical(other.type, type) || + const DeepCollectionEquality().equals(other.type, type))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(container) ^ + const DeepCollectionEquality().hash(audioCodec) ^ + const DeepCollectionEquality().hash(videoCodec) ^ + const DeepCollectionEquality().hash(type) ^ + runtimeType.hashCode; +} + +extension $DirectPlayProfileExtension on DirectPlayProfile { + DirectPlayProfile copyWith( + {String? container, + String? audioCodec, + String? videoCodec, + enums.DlnaProfileType? type}) { + return DirectPlayProfile( + container: container ?? this.container, + audioCodec: audioCodec ?? this.audioCodec, + videoCodec: videoCodec ?? this.videoCodec, + type: type ?? this.type); + } + + DirectPlayProfile copyWithWrapped( + {Wrapped? container, + Wrapped? audioCodec, + Wrapped? videoCodec, + Wrapped? type}) { + return DirectPlayProfile( + container: (container != null ? container.value : this.container), + audioCodec: (audioCodec != null ? audioCodec.value : this.audioCodec), + videoCodec: (videoCodec != null ? videoCodec.value : this.videoCodec), + type: (type != null ? type.value : this.type)); + } +} + +@JsonSerializable(explicitToJson: true) +class DisplayPreferencesDto { + const DisplayPreferencesDto({ + this.id, + this.viewType, + this.sortBy, + this.indexBy, + this.rememberIndexing, + this.primaryImageHeight, + this.primaryImageWidth, + this.customPrefs, + this.scrollDirection, + this.showBackdrop, + this.rememberSorting, + this.sortOrder, + this.showSidebar, + this.$Client, + }); + + factory DisplayPreferencesDto.fromJson(Map json) => + _$DisplayPreferencesDtoFromJson(json); + + static const toJsonFactory = _$DisplayPreferencesDtoToJson; + Map toJson() => _$DisplayPreferencesDtoToJson(this); + + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'ViewType', includeIfNull: false) + final String? viewType; + @JsonKey(name: 'SortBy', includeIfNull: false) + final String? sortBy; + @JsonKey(name: 'IndexBy', includeIfNull: false) + final String? indexBy; + @JsonKey(name: 'RememberIndexing', includeIfNull: false) + final bool? rememberIndexing; + @JsonKey(name: 'PrimaryImageHeight', includeIfNull: false) + final int? primaryImageHeight; + @JsonKey(name: 'PrimaryImageWidth', includeIfNull: false) + final int? primaryImageWidth; + @JsonKey(name: 'CustomPrefs', includeIfNull: false) + final Map? customPrefs; + @JsonKey( + name: 'ScrollDirection', + includeIfNull: false, + toJson: scrollDirectionNullableToJson, + fromJson: scrollDirectionNullableFromJson, + ) + final enums.ScrollDirection? scrollDirection; + @JsonKey(name: 'ShowBackdrop', includeIfNull: false) + final bool? showBackdrop; + @JsonKey(name: 'RememberSorting', includeIfNull: false) + final bool? rememberSorting; + @JsonKey( + name: 'SortOrder', + includeIfNull: false, + toJson: sortOrderNullableToJson, + fromJson: sortOrderNullableFromJson, + ) + final enums.SortOrder? sortOrder; + @JsonKey(name: 'ShowSidebar', includeIfNull: false) + final bool? showSidebar; + @JsonKey(name: 'Client', includeIfNull: false) + final String? $Client; + static const fromJsonFactory = _$DisplayPreferencesDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is DisplayPreferencesDto && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.viewType, viewType) || + const DeepCollectionEquality() + .equals(other.viewType, viewType)) && + (identical(other.sortBy, sortBy) || + const DeepCollectionEquality().equals(other.sortBy, sortBy)) && + (identical(other.indexBy, indexBy) || + const DeepCollectionEquality() + .equals(other.indexBy, indexBy)) && + (identical(other.rememberIndexing, rememberIndexing) || + const DeepCollectionEquality() + .equals(other.rememberIndexing, rememberIndexing)) && + (identical(other.primaryImageHeight, primaryImageHeight) || + const DeepCollectionEquality() + .equals(other.primaryImageHeight, primaryImageHeight)) && + (identical(other.primaryImageWidth, primaryImageWidth) || + const DeepCollectionEquality() + .equals(other.primaryImageWidth, primaryImageWidth)) && + (identical(other.customPrefs, customPrefs) || + const DeepCollectionEquality() + .equals(other.customPrefs, customPrefs)) && + (identical(other.scrollDirection, scrollDirection) || + const DeepCollectionEquality() + .equals(other.scrollDirection, scrollDirection)) && + (identical(other.showBackdrop, showBackdrop) || + const DeepCollectionEquality() + .equals(other.showBackdrop, showBackdrop)) && + (identical(other.rememberSorting, rememberSorting) || + const DeepCollectionEquality() + .equals(other.rememberSorting, rememberSorting)) && + (identical(other.sortOrder, sortOrder) || + const DeepCollectionEquality() + .equals(other.sortOrder, sortOrder)) && + (identical(other.showSidebar, showSidebar) || + const DeepCollectionEquality() + .equals(other.showSidebar, showSidebar)) && + (identical(other.$Client, $Client) || + const DeepCollectionEquality().equals(other.$Client, $Client))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(viewType) ^ + const DeepCollectionEquality().hash(sortBy) ^ + const DeepCollectionEquality().hash(indexBy) ^ + const DeepCollectionEquality().hash(rememberIndexing) ^ + const DeepCollectionEquality().hash(primaryImageHeight) ^ + const DeepCollectionEquality().hash(primaryImageWidth) ^ + const DeepCollectionEquality().hash(customPrefs) ^ + const DeepCollectionEquality().hash(scrollDirection) ^ + const DeepCollectionEquality().hash(showBackdrop) ^ + const DeepCollectionEquality().hash(rememberSorting) ^ + const DeepCollectionEquality().hash(sortOrder) ^ + const DeepCollectionEquality().hash(showSidebar) ^ + const DeepCollectionEquality().hash($Client) ^ + runtimeType.hashCode; +} + +extension $DisplayPreferencesDtoExtension on DisplayPreferencesDto { + DisplayPreferencesDto copyWith( + {String? id, + String? viewType, + String? sortBy, + String? indexBy, + bool? rememberIndexing, + int? primaryImageHeight, + int? primaryImageWidth, + Map? customPrefs, + enums.ScrollDirection? scrollDirection, + bool? showBackdrop, + bool? rememberSorting, + enums.SortOrder? sortOrder, + bool? showSidebar, + String? $Client}) { + return DisplayPreferencesDto( + id: id ?? this.id, + viewType: viewType ?? this.viewType, + sortBy: sortBy ?? this.sortBy, + indexBy: indexBy ?? this.indexBy, + rememberIndexing: rememberIndexing ?? this.rememberIndexing, + primaryImageHeight: primaryImageHeight ?? this.primaryImageHeight, + primaryImageWidth: primaryImageWidth ?? this.primaryImageWidth, + customPrefs: customPrefs ?? this.customPrefs, + scrollDirection: scrollDirection ?? this.scrollDirection, + showBackdrop: showBackdrop ?? this.showBackdrop, + rememberSorting: rememberSorting ?? this.rememberSorting, + sortOrder: sortOrder ?? this.sortOrder, + showSidebar: showSidebar ?? this.showSidebar, + $Client: $Client ?? this.$Client); + } + + DisplayPreferencesDto copyWithWrapped( + {Wrapped? id, + Wrapped? viewType, + Wrapped? sortBy, + Wrapped? indexBy, + Wrapped? rememberIndexing, + Wrapped? primaryImageHeight, + Wrapped? primaryImageWidth, + Wrapped?>? customPrefs, + Wrapped? scrollDirection, + Wrapped? showBackdrop, + Wrapped? rememberSorting, + Wrapped? sortOrder, + Wrapped? showSidebar, + Wrapped? $Client}) { + return DisplayPreferencesDto( + id: (id != null ? id.value : this.id), + viewType: (viewType != null ? viewType.value : this.viewType), + sortBy: (sortBy != null ? sortBy.value : this.sortBy), + indexBy: (indexBy != null ? indexBy.value : this.indexBy), + rememberIndexing: (rememberIndexing != null + ? rememberIndexing.value + : this.rememberIndexing), + primaryImageHeight: (primaryImageHeight != null + ? primaryImageHeight.value + : this.primaryImageHeight), + primaryImageWidth: (primaryImageWidth != null + ? primaryImageWidth.value + : this.primaryImageWidth), + customPrefs: + (customPrefs != null ? customPrefs.value : this.customPrefs), + scrollDirection: (scrollDirection != null + ? scrollDirection.value + : this.scrollDirection), + showBackdrop: + (showBackdrop != null ? showBackdrop.value : this.showBackdrop), + rememberSorting: (rememberSorting != null + ? rememberSorting.value + : this.rememberSorting), + sortOrder: (sortOrder != null ? sortOrder.value : this.sortOrder), + showSidebar: + (showSidebar != null ? showSidebar.value : this.showSidebar), + $Client: ($Client != null ? $Client.value : this.$Client)); + } +} + +@JsonSerializable(explicitToJson: true) +class EncodingOptions { + const EncodingOptions({ + this.encodingThreadCount, + this.transcodingTempPath, + this.fallbackFontPath, + this.enableFallbackFont, + this.enableAudioVbr, + this.downMixAudioBoost, + this.downMixStereoAlgorithm, + this.maxMuxingQueueSize, + this.enableThrottling, + this.throttleDelaySeconds, + this.enableSegmentDeletion, + this.segmentKeepSeconds, + this.hardwareAccelerationType, + this.encoderAppPath, + this.encoderAppPathDisplay, + this.vaapiDevice, + this.enableTonemapping, + this.enableVppTonemapping, + this.enableVideoToolboxTonemapping, + this.tonemappingAlgorithm, + this.tonemappingMode, + this.tonemappingRange, + this.tonemappingDesat, + this.tonemappingPeak, + this.tonemappingParam, + this.vppTonemappingBrightness, + this.vppTonemappingContrast, + this.h264Crf, + this.h265Crf, + this.encoderPreset, + this.deinterlaceDoubleRate, + this.deinterlaceMethod, + this.enableDecodingColorDepth10Hevc, + this.enableDecodingColorDepth10Vp9, + this.enableEnhancedNvdecDecoder, + this.preferSystemNativeHwDecoder, + this.enableIntelLowPowerH264HwEncoder, + this.enableIntelLowPowerHevcHwEncoder, + this.enableHardwareEncoding, + this.allowHevcEncoding, + this.allowAv1Encoding, + this.enableSubtitleExtraction, + this.hardwareDecodingCodecs, + this.allowOnDemandMetadataBasedKeyframeExtractionForExtensions, + }); + + factory EncodingOptions.fromJson(Map json) => + _$EncodingOptionsFromJson(json); + + static const toJsonFactory = _$EncodingOptionsToJson; + Map toJson() => _$EncodingOptionsToJson(this); + + @JsonKey(name: 'EncodingThreadCount', includeIfNull: false) + final int? encodingThreadCount; + @JsonKey(name: 'TranscodingTempPath', includeIfNull: false) + final String? transcodingTempPath; + @JsonKey(name: 'FallbackFontPath', includeIfNull: false) + final String? fallbackFontPath; + @JsonKey(name: 'EnableFallbackFont', includeIfNull: false) + final bool? enableFallbackFont; + @JsonKey(name: 'EnableAudioVbr', includeIfNull: false) + final bool? enableAudioVbr; + @JsonKey(name: 'DownMixAudioBoost', includeIfNull: false) + final double? downMixAudioBoost; + @JsonKey( + name: 'DownMixStereoAlgorithm', + includeIfNull: false, + toJson: downMixStereoAlgorithmsNullableToJson, + fromJson: downMixStereoAlgorithmsNullableFromJson, + ) + final enums.DownMixStereoAlgorithms? downMixStereoAlgorithm; + @JsonKey(name: 'MaxMuxingQueueSize', includeIfNull: false) + final int? maxMuxingQueueSize; + @JsonKey(name: 'EnableThrottling', includeIfNull: false) + final bool? enableThrottling; + @JsonKey(name: 'ThrottleDelaySeconds', includeIfNull: false) + final int? throttleDelaySeconds; + @JsonKey(name: 'EnableSegmentDeletion', includeIfNull: false) + final bool? enableSegmentDeletion; + @JsonKey(name: 'SegmentKeepSeconds', includeIfNull: false) + final int? segmentKeepSeconds; + @JsonKey(name: 'HardwareAccelerationType', includeIfNull: false) + final String? hardwareAccelerationType; + @JsonKey(name: 'EncoderAppPath', includeIfNull: false) + final String? encoderAppPath; + @JsonKey(name: 'EncoderAppPathDisplay', includeIfNull: false) + final String? encoderAppPathDisplay; + @JsonKey(name: 'VaapiDevice', includeIfNull: false) + final String? vaapiDevice; + @JsonKey(name: 'EnableTonemapping', includeIfNull: false) + final bool? enableTonemapping; + @JsonKey(name: 'EnableVppTonemapping', includeIfNull: false) + final bool? enableVppTonemapping; + @JsonKey(name: 'EnableVideoToolboxTonemapping', includeIfNull: false) + final bool? enableVideoToolboxTonemapping; + @JsonKey(name: 'TonemappingAlgorithm', includeIfNull: false) + final String? tonemappingAlgorithm; + @JsonKey(name: 'TonemappingMode', includeIfNull: false) + final String? tonemappingMode; + @JsonKey(name: 'TonemappingRange', includeIfNull: false) + final String? tonemappingRange; + @JsonKey(name: 'TonemappingDesat', includeIfNull: false) + final double? tonemappingDesat; + @JsonKey(name: 'TonemappingPeak', includeIfNull: false) + final double? tonemappingPeak; + @JsonKey(name: 'TonemappingParam', includeIfNull: false) + final double? tonemappingParam; + @JsonKey(name: 'VppTonemappingBrightness', includeIfNull: false) + final double? vppTonemappingBrightness; + @JsonKey(name: 'VppTonemappingContrast', includeIfNull: false) + final double? vppTonemappingContrast; + @JsonKey(name: 'H264Crf', includeIfNull: false) + final int? h264Crf; + @JsonKey(name: 'H265Crf', includeIfNull: false) + final int? h265Crf; + @JsonKey(name: 'EncoderPreset', includeIfNull: false) + final String? encoderPreset; + @JsonKey(name: 'DeinterlaceDoubleRate', includeIfNull: false) + final bool? deinterlaceDoubleRate; + @JsonKey(name: 'DeinterlaceMethod', includeIfNull: false) + final String? deinterlaceMethod; + @JsonKey(name: 'EnableDecodingColorDepth10Hevc', includeIfNull: false) + final bool? enableDecodingColorDepth10Hevc; + @JsonKey(name: 'EnableDecodingColorDepth10Vp9', includeIfNull: false) + final bool? enableDecodingColorDepth10Vp9; + @JsonKey(name: 'EnableEnhancedNvdecDecoder', includeIfNull: false) + final bool? enableEnhancedNvdecDecoder; + @JsonKey(name: 'PreferSystemNativeHwDecoder', includeIfNull: false) + final bool? preferSystemNativeHwDecoder; + @JsonKey(name: 'EnableIntelLowPowerH264HwEncoder', includeIfNull: false) + final bool? enableIntelLowPowerH264HwEncoder; + @JsonKey(name: 'EnableIntelLowPowerHevcHwEncoder', includeIfNull: false) + final bool? enableIntelLowPowerHevcHwEncoder; + @JsonKey(name: 'EnableHardwareEncoding', includeIfNull: false) + final bool? enableHardwareEncoding; + @JsonKey(name: 'AllowHevcEncoding', includeIfNull: false) + final bool? allowHevcEncoding; + @JsonKey(name: 'AllowAv1Encoding', includeIfNull: false) + final bool? allowAv1Encoding; + @JsonKey(name: 'EnableSubtitleExtraction', includeIfNull: false) + final bool? enableSubtitleExtraction; + @JsonKey( + name: 'HardwareDecodingCodecs', + includeIfNull: false, + defaultValue: []) + final List? hardwareDecodingCodecs; + @JsonKey( + name: 'AllowOnDemandMetadataBasedKeyframeExtractionForExtensions', + includeIfNull: false, + defaultValue: []) + final List? allowOnDemandMetadataBasedKeyframeExtractionForExtensions; + static const fromJsonFactory = _$EncodingOptionsFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is EncodingOptions && + (identical(other.encodingThreadCount, encodingThreadCount) || + const DeepCollectionEquality() + .equals(other.encodingThreadCount, encodingThreadCount)) && + (identical(other.transcodingTempPath, transcodingTempPath) || + const DeepCollectionEquality() + .equals(other.transcodingTempPath, transcodingTempPath)) && + (identical(other.fallbackFontPath, fallbackFontPath) || + const DeepCollectionEquality() + .equals(other.fallbackFontPath, fallbackFontPath)) && + (identical(other.enableFallbackFont, enableFallbackFont) || + const DeepCollectionEquality() + .equals(other.enableFallbackFont, enableFallbackFont)) && + (identical(other.enableAudioVbr, enableAudioVbr) || + const DeepCollectionEquality() + .equals(other.enableAudioVbr, enableAudioVbr)) && + (identical(other.downMixAudioBoost, downMixAudioBoost) || + const DeepCollectionEquality() + .equals(other.downMixAudioBoost, downMixAudioBoost)) && + (identical(other.downMixStereoAlgorithm, downMixStereoAlgorithm) || + const DeepCollectionEquality().equals( + other.downMixStereoAlgorithm, downMixStereoAlgorithm)) && + (identical(other.maxMuxingQueueSize, maxMuxingQueueSize) || + const DeepCollectionEquality() + .equals(other.maxMuxingQueueSize, maxMuxingQueueSize)) && + (identical(other.enableThrottling, enableThrottling) || + const DeepCollectionEquality() + .equals(other.enableThrottling, enableThrottling)) && + (identical(other.throttleDelaySeconds, throttleDelaySeconds) || + const DeepCollectionEquality().equals( + other.throttleDelaySeconds, throttleDelaySeconds)) && + (identical(other.enableSegmentDeletion, enableSegmentDeletion) || + const DeepCollectionEquality().equals( + other.enableSegmentDeletion, enableSegmentDeletion)) && + (identical(other.segmentKeepSeconds, segmentKeepSeconds) || + const DeepCollectionEquality() + .equals(other.segmentKeepSeconds, segmentKeepSeconds)) && + (identical(other.hardwareAccelerationType, hardwareAccelerationType) || + const DeepCollectionEquality().equals( + other.hardwareAccelerationType, + hardwareAccelerationType)) && + (identical(other.encoderAppPath, encoderAppPath) || + const DeepCollectionEquality() + .equals(other.encoderAppPath, encoderAppPath)) && + (identical(other.encoderAppPathDisplay, encoderAppPathDisplay) || + const DeepCollectionEquality().equals( + other.encoderAppPathDisplay, encoderAppPathDisplay)) && + (identical(other.vaapiDevice, vaapiDevice) || + const DeepCollectionEquality() + .equals(other.vaapiDevice, vaapiDevice)) && + (identical(other.enableTonemapping, enableTonemapping) || + const DeepCollectionEquality() + .equals(other.enableTonemapping, enableTonemapping)) && + (identical(other.enableVppTonemapping, enableVppTonemapping) || + const DeepCollectionEquality().equals( + other.enableVppTonemapping, enableVppTonemapping)) && + (identical(other.enableVideoToolboxTonemapping, enableVideoToolboxTonemapping) || + const DeepCollectionEquality() + .equals(other.enableVideoToolboxTonemapping, enableVideoToolboxTonemapping)) && + (identical(other.tonemappingAlgorithm, tonemappingAlgorithm) || const DeepCollectionEquality().equals(other.tonemappingAlgorithm, tonemappingAlgorithm)) && + (identical(other.tonemappingMode, tonemappingMode) || const DeepCollectionEquality().equals(other.tonemappingMode, tonemappingMode)) && + (identical(other.tonemappingRange, tonemappingRange) || const DeepCollectionEquality().equals(other.tonemappingRange, tonemappingRange)) && + (identical(other.tonemappingDesat, tonemappingDesat) || const DeepCollectionEquality().equals(other.tonemappingDesat, tonemappingDesat)) && + (identical(other.tonemappingPeak, tonemappingPeak) || const DeepCollectionEquality().equals(other.tonemappingPeak, tonemappingPeak)) && + (identical(other.tonemappingParam, tonemappingParam) || const DeepCollectionEquality().equals(other.tonemappingParam, tonemappingParam)) && + (identical(other.vppTonemappingBrightness, vppTonemappingBrightness) || const DeepCollectionEquality().equals(other.vppTonemappingBrightness, vppTonemappingBrightness)) && + (identical(other.vppTonemappingContrast, vppTonemappingContrast) || const DeepCollectionEquality().equals(other.vppTonemappingContrast, vppTonemappingContrast)) && + (identical(other.h264Crf, h264Crf) || const DeepCollectionEquality().equals(other.h264Crf, h264Crf)) && + (identical(other.h265Crf, h265Crf) || const DeepCollectionEquality().equals(other.h265Crf, h265Crf)) && + (identical(other.encoderPreset, encoderPreset) || const DeepCollectionEquality().equals(other.encoderPreset, encoderPreset)) && + (identical(other.deinterlaceDoubleRate, deinterlaceDoubleRate) || const DeepCollectionEquality().equals(other.deinterlaceDoubleRate, deinterlaceDoubleRate)) && + (identical(other.deinterlaceMethod, deinterlaceMethod) || const DeepCollectionEquality().equals(other.deinterlaceMethod, deinterlaceMethod)) && + (identical(other.enableDecodingColorDepth10Hevc, enableDecodingColorDepth10Hevc) || const DeepCollectionEquality().equals(other.enableDecodingColorDepth10Hevc, enableDecodingColorDepth10Hevc)) && + (identical(other.enableDecodingColorDepth10Vp9, enableDecodingColorDepth10Vp9) || const DeepCollectionEquality().equals(other.enableDecodingColorDepth10Vp9, enableDecodingColorDepth10Vp9)) && + (identical(other.enableEnhancedNvdecDecoder, enableEnhancedNvdecDecoder) || const DeepCollectionEquality().equals(other.enableEnhancedNvdecDecoder, enableEnhancedNvdecDecoder)) && + (identical(other.preferSystemNativeHwDecoder, preferSystemNativeHwDecoder) || const DeepCollectionEquality().equals(other.preferSystemNativeHwDecoder, preferSystemNativeHwDecoder)) && + (identical(other.enableIntelLowPowerH264HwEncoder, enableIntelLowPowerH264HwEncoder) || const DeepCollectionEquality().equals(other.enableIntelLowPowerH264HwEncoder, enableIntelLowPowerH264HwEncoder)) && + (identical(other.enableIntelLowPowerHevcHwEncoder, enableIntelLowPowerHevcHwEncoder) || const DeepCollectionEquality().equals(other.enableIntelLowPowerHevcHwEncoder, enableIntelLowPowerHevcHwEncoder)) && + (identical(other.enableHardwareEncoding, enableHardwareEncoding) || const DeepCollectionEquality().equals(other.enableHardwareEncoding, enableHardwareEncoding)) && + (identical(other.allowHevcEncoding, allowHevcEncoding) || const DeepCollectionEquality().equals(other.allowHevcEncoding, allowHevcEncoding)) && + (identical(other.allowAv1Encoding, allowAv1Encoding) || const DeepCollectionEquality().equals(other.allowAv1Encoding, allowAv1Encoding)) && + (identical(other.enableSubtitleExtraction, enableSubtitleExtraction) || const DeepCollectionEquality().equals(other.enableSubtitleExtraction, enableSubtitleExtraction)) && + (identical(other.hardwareDecodingCodecs, hardwareDecodingCodecs) || const DeepCollectionEquality().equals(other.hardwareDecodingCodecs, hardwareDecodingCodecs)) && + (identical(other.allowOnDemandMetadataBasedKeyframeExtractionForExtensions, allowOnDemandMetadataBasedKeyframeExtractionForExtensions) || const DeepCollectionEquality().equals(other.allowOnDemandMetadataBasedKeyframeExtractionForExtensions, allowOnDemandMetadataBasedKeyframeExtractionForExtensions))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(encodingThreadCount) ^ + const DeepCollectionEquality().hash(transcodingTempPath) ^ + const DeepCollectionEquality().hash(fallbackFontPath) ^ + const DeepCollectionEquality().hash(enableFallbackFont) ^ + const DeepCollectionEquality().hash(enableAudioVbr) ^ + const DeepCollectionEquality().hash(downMixAudioBoost) ^ + const DeepCollectionEquality().hash(downMixStereoAlgorithm) ^ + const DeepCollectionEquality().hash(maxMuxingQueueSize) ^ + const DeepCollectionEquality().hash(enableThrottling) ^ + const DeepCollectionEquality().hash(throttleDelaySeconds) ^ + const DeepCollectionEquality().hash(enableSegmentDeletion) ^ + const DeepCollectionEquality().hash(segmentKeepSeconds) ^ + const DeepCollectionEquality().hash(hardwareAccelerationType) ^ + const DeepCollectionEquality().hash(encoderAppPath) ^ + const DeepCollectionEquality().hash(encoderAppPathDisplay) ^ + const DeepCollectionEquality().hash(vaapiDevice) ^ + const DeepCollectionEquality().hash(enableTonemapping) ^ + const DeepCollectionEquality().hash(enableVppTonemapping) ^ + const DeepCollectionEquality().hash(enableVideoToolboxTonemapping) ^ + const DeepCollectionEquality().hash(tonemappingAlgorithm) ^ + const DeepCollectionEquality().hash(tonemappingMode) ^ + const DeepCollectionEquality().hash(tonemappingRange) ^ + const DeepCollectionEquality().hash(tonemappingDesat) ^ + const DeepCollectionEquality().hash(tonemappingPeak) ^ + const DeepCollectionEquality().hash(tonemappingParam) ^ + const DeepCollectionEquality().hash(vppTonemappingBrightness) ^ + const DeepCollectionEquality().hash(vppTonemappingContrast) ^ + const DeepCollectionEquality().hash(h264Crf) ^ + const DeepCollectionEquality().hash(h265Crf) ^ + const DeepCollectionEquality().hash(encoderPreset) ^ + const DeepCollectionEquality().hash(deinterlaceDoubleRate) ^ + const DeepCollectionEquality().hash(deinterlaceMethod) ^ + const DeepCollectionEquality().hash(enableDecodingColorDepth10Hevc) ^ + const DeepCollectionEquality().hash(enableDecodingColorDepth10Vp9) ^ + const DeepCollectionEquality().hash(enableEnhancedNvdecDecoder) ^ + const DeepCollectionEquality().hash(preferSystemNativeHwDecoder) ^ + const DeepCollectionEquality().hash(enableIntelLowPowerH264HwEncoder) ^ + const DeepCollectionEquality().hash(enableIntelLowPowerHevcHwEncoder) ^ + const DeepCollectionEquality().hash(enableHardwareEncoding) ^ + const DeepCollectionEquality().hash(allowHevcEncoding) ^ + const DeepCollectionEquality().hash(allowAv1Encoding) ^ + const DeepCollectionEquality().hash(enableSubtitleExtraction) ^ + const DeepCollectionEquality().hash(hardwareDecodingCodecs) ^ + const DeepCollectionEquality() + .hash(allowOnDemandMetadataBasedKeyframeExtractionForExtensions) ^ + runtimeType.hashCode; +} + +extension $EncodingOptionsExtension on EncodingOptions { + EncodingOptions copyWith( + {int? encodingThreadCount, + String? transcodingTempPath, + String? fallbackFontPath, + bool? enableFallbackFont, + bool? enableAudioVbr, + double? downMixAudioBoost, + enums.DownMixStereoAlgorithms? downMixStereoAlgorithm, + int? maxMuxingQueueSize, + bool? enableThrottling, + int? throttleDelaySeconds, + bool? enableSegmentDeletion, + int? segmentKeepSeconds, + String? hardwareAccelerationType, + String? encoderAppPath, + String? encoderAppPathDisplay, + String? vaapiDevice, + bool? enableTonemapping, + bool? enableVppTonemapping, + bool? enableVideoToolboxTonemapping, + String? tonemappingAlgorithm, + String? tonemappingMode, + String? tonemappingRange, + double? tonemappingDesat, + double? tonemappingPeak, + double? tonemappingParam, + double? vppTonemappingBrightness, + double? vppTonemappingContrast, + int? h264Crf, + int? h265Crf, + String? encoderPreset, + bool? deinterlaceDoubleRate, + String? deinterlaceMethod, + bool? enableDecodingColorDepth10Hevc, + bool? enableDecodingColorDepth10Vp9, + bool? enableEnhancedNvdecDecoder, + bool? preferSystemNativeHwDecoder, + bool? enableIntelLowPowerH264HwEncoder, + bool? enableIntelLowPowerHevcHwEncoder, + bool? enableHardwareEncoding, + bool? allowHevcEncoding, + bool? allowAv1Encoding, + bool? enableSubtitleExtraction, + List? hardwareDecodingCodecs, + List? + allowOnDemandMetadataBasedKeyframeExtractionForExtensions}) { + return EncodingOptions( + encodingThreadCount: encodingThreadCount ?? this.encodingThreadCount, + transcodingTempPath: transcodingTempPath ?? this.transcodingTempPath, + fallbackFontPath: fallbackFontPath ?? this.fallbackFontPath, + enableFallbackFont: enableFallbackFont ?? this.enableFallbackFont, + enableAudioVbr: enableAudioVbr ?? this.enableAudioVbr, + downMixAudioBoost: downMixAudioBoost ?? this.downMixAudioBoost, + downMixStereoAlgorithm: + downMixStereoAlgorithm ?? this.downMixStereoAlgorithm, + maxMuxingQueueSize: maxMuxingQueueSize ?? this.maxMuxingQueueSize, + enableThrottling: enableThrottling ?? this.enableThrottling, + throttleDelaySeconds: throttleDelaySeconds ?? this.throttleDelaySeconds, + enableSegmentDeletion: + enableSegmentDeletion ?? this.enableSegmentDeletion, + segmentKeepSeconds: segmentKeepSeconds ?? this.segmentKeepSeconds, + hardwareAccelerationType: + hardwareAccelerationType ?? this.hardwareAccelerationType, + encoderAppPath: encoderAppPath ?? this.encoderAppPath, + encoderAppPathDisplay: + encoderAppPathDisplay ?? this.encoderAppPathDisplay, + vaapiDevice: vaapiDevice ?? this.vaapiDevice, + enableTonemapping: enableTonemapping ?? this.enableTonemapping, + enableVppTonemapping: enableVppTonemapping ?? this.enableVppTonemapping, + enableVideoToolboxTonemapping: + enableVideoToolboxTonemapping ?? this.enableVideoToolboxTonemapping, + tonemappingAlgorithm: tonemappingAlgorithm ?? this.tonemappingAlgorithm, + tonemappingMode: tonemappingMode ?? this.tonemappingMode, + tonemappingRange: tonemappingRange ?? this.tonemappingRange, + tonemappingDesat: tonemappingDesat ?? this.tonemappingDesat, + tonemappingPeak: tonemappingPeak ?? this.tonemappingPeak, + tonemappingParam: tonemappingParam ?? this.tonemappingParam, + vppTonemappingBrightness: + vppTonemappingBrightness ?? this.vppTonemappingBrightness, + vppTonemappingContrast: + vppTonemappingContrast ?? this.vppTonemappingContrast, + h264Crf: h264Crf ?? this.h264Crf, + h265Crf: h265Crf ?? this.h265Crf, + encoderPreset: encoderPreset ?? this.encoderPreset, + deinterlaceDoubleRate: + deinterlaceDoubleRate ?? this.deinterlaceDoubleRate, + deinterlaceMethod: deinterlaceMethod ?? this.deinterlaceMethod, + enableDecodingColorDepth10Hevc: enableDecodingColorDepth10Hevc ?? + this.enableDecodingColorDepth10Hevc, + enableDecodingColorDepth10Vp9: + enableDecodingColorDepth10Vp9 ?? this.enableDecodingColorDepth10Vp9, + enableEnhancedNvdecDecoder: + enableEnhancedNvdecDecoder ?? this.enableEnhancedNvdecDecoder, + preferSystemNativeHwDecoder: + preferSystemNativeHwDecoder ?? this.preferSystemNativeHwDecoder, + enableIntelLowPowerH264HwEncoder: enableIntelLowPowerH264HwEncoder ?? + this.enableIntelLowPowerH264HwEncoder, + enableIntelLowPowerHevcHwEncoder: enableIntelLowPowerHevcHwEncoder ?? + this.enableIntelLowPowerHevcHwEncoder, + enableHardwareEncoding: + enableHardwareEncoding ?? this.enableHardwareEncoding, + allowHevcEncoding: allowHevcEncoding ?? this.allowHevcEncoding, + allowAv1Encoding: allowAv1Encoding ?? this.allowAv1Encoding, + enableSubtitleExtraction: + enableSubtitleExtraction ?? this.enableSubtitleExtraction, + hardwareDecodingCodecs: + hardwareDecodingCodecs ?? this.hardwareDecodingCodecs, + allowOnDemandMetadataBasedKeyframeExtractionForExtensions: + allowOnDemandMetadataBasedKeyframeExtractionForExtensions ?? + this.allowOnDemandMetadataBasedKeyframeExtractionForExtensions); + } + + EncodingOptions copyWithWrapped( + {Wrapped? encodingThreadCount, + Wrapped? transcodingTempPath, + Wrapped? fallbackFontPath, + Wrapped? enableFallbackFont, + Wrapped? enableAudioVbr, + Wrapped? downMixAudioBoost, + Wrapped? downMixStereoAlgorithm, + Wrapped? maxMuxingQueueSize, + Wrapped? enableThrottling, + Wrapped? throttleDelaySeconds, + Wrapped? enableSegmentDeletion, + Wrapped? segmentKeepSeconds, + Wrapped? hardwareAccelerationType, + Wrapped? encoderAppPath, + Wrapped? encoderAppPathDisplay, + Wrapped? vaapiDevice, + Wrapped? enableTonemapping, + Wrapped? enableVppTonemapping, + Wrapped? enableVideoToolboxTonemapping, + Wrapped? tonemappingAlgorithm, + Wrapped? tonemappingMode, + Wrapped? tonemappingRange, + Wrapped? tonemappingDesat, + Wrapped? tonemappingPeak, + Wrapped? tonemappingParam, + Wrapped? vppTonemappingBrightness, + Wrapped? vppTonemappingContrast, + Wrapped? h264Crf, + Wrapped? h265Crf, + Wrapped? encoderPreset, + Wrapped? deinterlaceDoubleRate, + Wrapped? deinterlaceMethod, + Wrapped? enableDecodingColorDepth10Hevc, + Wrapped? enableDecodingColorDepth10Vp9, + Wrapped? enableEnhancedNvdecDecoder, + Wrapped? preferSystemNativeHwDecoder, + Wrapped? enableIntelLowPowerH264HwEncoder, + Wrapped? enableIntelLowPowerHevcHwEncoder, + Wrapped? enableHardwareEncoding, + Wrapped? allowHevcEncoding, + Wrapped? allowAv1Encoding, + Wrapped? enableSubtitleExtraction, + Wrapped?>? hardwareDecodingCodecs, + Wrapped?>? + allowOnDemandMetadataBasedKeyframeExtractionForExtensions}) { + return EncodingOptions( + encodingThreadCount: (encodingThreadCount != null + ? encodingThreadCount.value + : this.encodingThreadCount), + transcodingTempPath: (transcodingTempPath != null + ? transcodingTempPath.value + : this.transcodingTempPath), + fallbackFontPath: (fallbackFontPath != null + ? fallbackFontPath.value + : this.fallbackFontPath), + enableFallbackFont: (enableFallbackFont != null + ? enableFallbackFont.value + : this.enableFallbackFont), + enableAudioVbr: (enableAudioVbr != null + ? enableAudioVbr.value + : this.enableAudioVbr), + downMixAudioBoost: (downMixAudioBoost != null + ? downMixAudioBoost.value + : this.downMixAudioBoost), + downMixStereoAlgorithm: (downMixStereoAlgorithm != null + ? downMixStereoAlgorithm.value + : this.downMixStereoAlgorithm), + maxMuxingQueueSize: (maxMuxingQueueSize != null + ? maxMuxingQueueSize.value + : this.maxMuxingQueueSize), + enableThrottling: (enableThrottling != null + ? enableThrottling.value + : this.enableThrottling), + throttleDelaySeconds: (throttleDelaySeconds != null + ? throttleDelaySeconds.value + : this.throttleDelaySeconds), + enableSegmentDeletion: (enableSegmentDeletion != null + ? enableSegmentDeletion.value + : this.enableSegmentDeletion), + segmentKeepSeconds: (segmentKeepSeconds != null + ? segmentKeepSeconds.value + : this.segmentKeepSeconds), + hardwareAccelerationType: (hardwareAccelerationType != null + ? hardwareAccelerationType.value + : this.hardwareAccelerationType), + encoderAppPath: (encoderAppPath != null + ? encoderAppPath.value + : this.encoderAppPath), + encoderAppPathDisplay: (encoderAppPathDisplay != null + ? encoderAppPathDisplay.value + : this.encoderAppPathDisplay), + vaapiDevice: + (vaapiDevice != null ? vaapiDevice.value : this.vaapiDevice), + enableTonemapping: (enableTonemapping != null + ? enableTonemapping.value + : this.enableTonemapping), + enableVppTonemapping: (enableVppTonemapping != null + ? enableVppTonemapping.value + : this.enableVppTonemapping), + enableVideoToolboxTonemapping: (enableVideoToolboxTonemapping != null + ? enableVideoToolboxTonemapping.value + : this.enableVideoToolboxTonemapping), + tonemappingAlgorithm: (tonemappingAlgorithm != null + ? tonemappingAlgorithm.value + : this.tonemappingAlgorithm), + tonemappingMode: (tonemappingMode != null + ? tonemappingMode.value + : this.tonemappingMode), + tonemappingRange: (tonemappingRange != null + ? tonemappingRange.value + : this.tonemappingRange), + tonemappingDesat: (tonemappingDesat != null + ? tonemappingDesat.value + : this.tonemappingDesat), + tonemappingPeak: (tonemappingPeak != null + ? tonemappingPeak.value + : this.tonemappingPeak), + tonemappingParam: (tonemappingParam != null + ? tonemappingParam.value + : this.tonemappingParam), + vppTonemappingBrightness: (vppTonemappingBrightness != null + ? vppTonemappingBrightness.value + : this.vppTonemappingBrightness), + vppTonemappingContrast: (vppTonemappingContrast != null + ? vppTonemappingContrast.value + : this.vppTonemappingContrast), + h264Crf: (h264Crf != null ? h264Crf.value : this.h264Crf), + h265Crf: (h265Crf != null ? h265Crf.value : this.h265Crf), + encoderPreset: + (encoderPreset != null ? encoderPreset.value : this.encoderPreset), + deinterlaceDoubleRate: (deinterlaceDoubleRate != null + ? deinterlaceDoubleRate.value + : this.deinterlaceDoubleRate), + deinterlaceMethod: (deinterlaceMethod != null + ? deinterlaceMethod.value + : this.deinterlaceMethod), + enableDecodingColorDepth10Hevc: (enableDecodingColorDepth10Hevc != null + ? enableDecodingColorDepth10Hevc.value + : this.enableDecodingColorDepth10Hevc), + enableDecodingColorDepth10Vp9: (enableDecodingColorDepth10Vp9 != null + ? enableDecodingColorDepth10Vp9.value + : this.enableDecodingColorDepth10Vp9), + enableEnhancedNvdecDecoder: (enableEnhancedNvdecDecoder != null + ? enableEnhancedNvdecDecoder.value + : this.enableEnhancedNvdecDecoder), + preferSystemNativeHwDecoder: (preferSystemNativeHwDecoder != null + ? preferSystemNativeHwDecoder.value + : this.preferSystemNativeHwDecoder), + enableIntelLowPowerH264HwEncoder: + (enableIntelLowPowerH264HwEncoder != null + ? enableIntelLowPowerH264HwEncoder.value + : this.enableIntelLowPowerH264HwEncoder), + enableIntelLowPowerHevcHwEncoder: + (enableIntelLowPowerHevcHwEncoder != null + ? enableIntelLowPowerHevcHwEncoder.value + : this.enableIntelLowPowerHevcHwEncoder), + enableHardwareEncoding: (enableHardwareEncoding != null + ? enableHardwareEncoding.value + : this.enableHardwareEncoding), + allowHevcEncoding: (allowHevcEncoding != null + ? allowHevcEncoding.value + : this.allowHevcEncoding), + allowAv1Encoding: (allowAv1Encoding != null + ? allowAv1Encoding.value + : this.allowAv1Encoding), + enableSubtitleExtraction: (enableSubtitleExtraction != null + ? enableSubtitleExtraction.value + : this.enableSubtitleExtraction), + hardwareDecodingCodecs: (hardwareDecodingCodecs != null + ? hardwareDecodingCodecs.value + : this.hardwareDecodingCodecs), + allowOnDemandMetadataBasedKeyframeExtractionForExtensions: + (allowOnDemandMetadataBasedKeyframeExtractionForExtensions != null + ? allowOnDemandMetadataBasedKeyframeExtractionForExtensions + .value + : this + .allowOnDemandMetadataBasedKeyframeExtractionForExtensions)); + } +} + +@JsonSerializable(explicitToJson: true) +class EndPointInfo { + const EndPointInfo({ + this.isLocal, + this.isInNetwork, + }); + + factory EndPointInfo.fromJson(Map json) => + _$EndPointInfoFromJson(json); + + static const toJsonFactory = _$EndPointInfoToJson; + Map toJson() => _$EndPointInfoToJson(this); + + @JsonKey(name: 'IsLocal', includeIfNull: false) + final bool? isLocal; + @JsonKey(name: 'IsInNetwork', includeIfNull: false) + final bool? isInNetwork; + static const fromJsonFactory = _$EndPointInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is EndPointInfo && + (identical(other.isLocal, isLocal) || + const DeepCollectionEquality() + .equals(other.isLocal, isLocal)) && + (identical(other.isInNetwork, isInNetwork) || + const DeepCollectionEquality() + .equals(other.isInNetwork, isInNetwork))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(isLocal) ^ + const DeepCollectionEquality().hash(isInNetwork) ^ + runtimeType.hashCode; +} + +extension $EndPointInfoExtension on EndPointInfo { + EndPointInfo copyWith({bool? isLocal, bool? isInNetwork}) { + return EndPointInfo( + isLocal: isLocal ?? this.isLocal, + isInNetwork: isInNetwork ?? this.isInNetwork); + } + + EndPointInfo copyWithWrapped( + {Wrapped? isLocal, Wrapped? isInNetwork}) { + return EndPointInfo( + isLocal: (isLocal != null ? isLocal.value : this.isLocal), + isInNetwork: + (isInNetwork != null ? isInNetwork.value : this.isInNetwork)); + } +} + +@JsonSerializable(explicitToJson: true) +class EpisodeVisualization { + const EpisodeVisualization({ + this.id, + this.name, + }); + + factory EpisodeVisualization.fromJson(Map json) => + _$EpisodeVisualizationFromJson(json); + + static const toJsonFactory = _$EpisodeVisualizationToJson; + Map toJson() => _$EpisodeVisualizationToJson(this); + + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + static const fromJsonFactory = _$EpisodeVisualizationFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is EpisodeVisualization && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(name) ^ + runtimeType.hashCode; +} + +extension $EpisodeVisualizationExtension on EpisodeVisualization { + EpisodeVisualization copyWith({String? id, String? name}) { + return EpisodeVisualization(id: id ?? this.id, name: name ?? this.name); + } + + EpisodeVisualization copyWithWrapped( + {Wrapped? id, Wrapped? name}) { + return EpisodeVisualization( + id: (id != null ? id.value : this.id), + name: (name != null ? name.value : this.name)); + } +} + +@JsonSerializable(explicitToJson: true) +class ExternalIdInfo { + const ExternalIdInfo({ + this.name, + this.key, + this.type, + this.urlFormatString, + }); + + factory ExternalIdInfo.fromJson(Map json) => + _$ExternalIdInfoFromJson(json); + + static const toJsonFactory = _$ExternalIdInfoToJson; + Map toJson() => _$ExternalIdInfoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'Key', includeIfNull: false) + final String? key; + @JsonKey( + name: 'Type', + includeIfNull: false, + toJson: externalIdMediaTypeNullableToJson, + fromJson: externalIdMediaTypeNullableFromJson, + ) + final enums.ExternalIdMediaType? type; + @JsonKey(name: 'UrlFormatString', includeIfNull: false) + final String? urlFormatString; + static const fromJsonFactory = _$ExternalIdInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ExternalIdInfo && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.key, key) || + const DeepCollectionEquality().equals(other.key, key)) && + (identical(other.type, type) || + const DeepCollectionEquality().equals(other.type, type)) && + (identical(other.urlFormatString, urlFormatString) || + const DeepCollectionEquality() + .equals(other.urlFormatString, urlFormatString))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(key) ^ + const DeepCollectionEquality().hash(type) ^ + const DeepCollectionEquality().hash(urlFormatString) ^ + runtimeType.hashCode; +} + +extension $ExternalIdInfoExtension on ExternalIdInfo { + ExternalIdInfo copyWith( + {String? name, + String? key, + enums.ExternalIdMediaType? type, + String? urlFormatString}) { + return ExternalIdInfo( + name: name ?? this.name, + key: key ?? this.key, + type: type ?? this.type, + urlFormatString: urlFormatString ?? this.urlFormatString); + } + + ExternalIdInfo copyWithWrapped( + {Wrapped? name, + Wrapped? key, + Wrapped? type, + Wrapped? urlFormatString}) { + return ExternalIdInfo( + name: (name != null ? name.value : this.name), + key: (key != null ? key.value : this.key), + type: (type != null ? type.value : this.type), + urlFormatString: (urlFormatString != null + ? urlFormatString.value + : this.urlFormatString)); + } +} + +@JsonSerializable(explicitToJson: true) +class ExternalUrl { + const ExternalUrl({ + this.name, + this.url, + }); + + factory ExternalUrl.fromJson(Map json) => + _$ExternalUrlFromJson(json); + + static const toJsonFactory = _$ExternalUrlToJson; + Map toJson() => _$ExternalUrlToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'Url', includeIfNull: false) + final String? url; + static const fromJsonFactory = _$ExternalUrlFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ExternalUrl && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.url, url) || + const DeepCollectionEquality().equals(other.url, url))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(url) ^ + runtimeType.hashCode; +} + +extension $ExternalUrlExtension on ExternalUrl { + ExternalUrl copyWith({String? name, String? url}) { + return ExternalUrl(name: name ?? this.name, url: url ?? this.url); + } + + ExternalUrl copyWithWrapped({Wrapped? name, Wrapped? url}) { + return ExternalUrl( + name: (name != null ? name.value : this.name), + url: (url != null ? url.value : this.url)); + } +} + +@JsonSerializable(explicitToJson: true) +class FileSystemEntryInfo { + const FileSystemEntryInfo({ + this.name, + this.path, + this.type, + }); + + factory FileSystemEntryInfo.fromJson(Map json) => + _$FileSystemEntryInfoFromJson(json); + + static const toJsonFactory = _$FileSystemEntryInfoToJson; + Map toJson() => _$FileSystemEntryInfoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'Path', includeIfNull: false) + final String? path; + @JsonKey( + name: 'Type', + includeIfNull: false, + toJson: fileSystemEntryTypeNullableToJson, + fromJson: fileSystemEntryTypeNullableFromJson, + ) + final enums.FileSystemEntryType? type; + static const fromJsonFactory = _$FileSystemEntryInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is FileSystemEntryInfo && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.path, path) || + const DeepCollectionEquality().equals(other.path, path)) && + (identical(other.type, type) || + const DeepCollectionEquality().equals(other.type, type))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(path) ^ + const DeepCollectionEquality().hash(type) ^ + runtimeType.hashCode; +} + +extension $FileSystemEntryInfoExtension on FileSystemEntryInfo { + FileSystemEntryInfo copyWith( + {String? name, String? path, enums.FileSystemEntryType? type}) { + return FileSystemEntryInfo( + name: name ?? this.name, + path: path ?? this.path, + type: type ?? this.type); + } + + FileSystemEntryInfo copyWithWrapped( + {Wrapped? name, + Wrapped? path, + Wrapped? type}) { + return FileSystemEntryInfo( + name: (name != null ? name.value : this.name), + path: (path != null ? path.value : this.path), + type: (type != null ? type.value : this.type)); + } +} + +@JsonSerializable(explicitToJson: true) +class FontFile { + const FontFile({ + this.name, + this.size, + this.dateCreated, + this.dateModified, + }); + + factory FontFile.fromJson(Map json) => + _$FontFileFromJson(json); + + static const toJsonFactory = _$FontFileToJson; + Map toJson() => _$FontFileToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'Size', includeIfNull: false) + final int? size; + @JsonKey(name: 'DateCreated', includeIfNull: false) + final DateTime? dateCreated; + @JsonKey(name: 'DateModified', includeIfNull: false) + final DateTime? dateModified; + static const fromJsonFactory = _$FontFileFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is FontFile && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.size, size) || + const DeepCollectionEquality().equals(other.size, size)) && + (identical(other.dateCreated, dateCreated) || + const DeepCollectionEquality() + .equals(other.dateCreated, dateCreated)) && + (identical(other.dateModified, dateModified) || + const DeepCollectionEquality() + .equals(other.dateModified, dateModified))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(size) ^ + const DeepCollectionEquality().hash(dateCreated) ^ + const DeepCollectionEquality().hash(dateModified) ^ + runtimeType.hashCode; +} + +extension $FontFileExtension on FontFile { + FontFile copyWith( + {String? name, + int? size, + DateTime? dateCreated, + DateTime? dateModified}) { + return FontFile( + name: name ?? this.name, + size: size ?? this.size, + dateCreated: dateCreated ?? this.dateCreated, + dateModified: dateModified ?? this.dateModified); + } + + FontFile copyWithWrapped( + {Wrapped? name, + Wrapped? size, + Wrapped? dateCreated, + Wrapped? dateModified}) { + return FontFile( + name: (name != null ? name.value : this.name), + size: (size != null ? size.value : this.size), + dateCreated: + (dateCreated != null ? dateCreated.value : this.dateCreated), + dateModified: + (dateModified != null ? dateModified.value : this.dateModified)); + } +} + +@JsonSerializable(explicitToJson: true) +class ForceKeepAliveMessage { + const ForceKeepAliveMessage({ + this.data, + this.messageId, + this.messageType, + }); + + factory ForceKeepAliveMessage.fromJson(Map json) => + _$ForceKeepAliveMessageFromJson(json); + + static const toJsonFactory = _$ForceKeepAliveMessageToJson; + Map toJson() => _$ForceKeepAliveMessageToJson(this); + + @JsonKey(name: 'Data', includeIfNull: false) + final int? data; + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.forcekeepalive); + + static const fromJsonFactory = _$ForceKeepAliveMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ForceKeepAliveMessage && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data)) && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(data) ^ + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $ForceKeepAliveMessageExtension on ForceKeepAliveMessage { + ForceKeepAliveMessage copyWith( + {int? data, String? messageId, enums.SessionMessageType? messageType}) { + return ForceKeepAliveMessage( + data: data ?? this.data, + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + ForceKeepAliveMessage copyWithWrapped( + {Wrapped? data, + Wrapped? messageId, + Wrapped? messageType}) { + return ForceKeepAliveMessage( + data: (data != null ? data.value : this.data), + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class ForgotPasswordDto { + const ForgotPasswordDto({ + required this.enteredUsername, + }); + + factory ForgotPasswordDto.fromJson(Map json) => + _$ForgotPasswordDtoFromJson(json); + + static const toJsonFactory = _$ForgotPasswordDtoToJson; + Map toJson() => _$ForgotPasswordDtoToJson(this); + + @JsonKey(name: 'EnteredUsername', includeIfNull: false) + final String enteredUsername; + static const fromJsonFactory = _$ForgotPasswordDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ForgotPasswordDto && + (identical(other.enteredUsername, enteredUsername) || + const DeepCollectionEquality() + .equals(other.enteredUsername, enteredUsername))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(enteredUsername) ^ + runtimeType.hashCode; +} + +extension $ForgotPasswordDtoExtension on ForgotPasswordDto { + ForgotPasswordDto copyWith({String? enteredUsername}) { + return ForgotPasswordDto( + enteredUsername: enteredUsername ?? this.enteredUsername); + } + + ForgotPasswordDto copyWithWrapped({Wrapped? enteredUsername}) { + return ForgotPasswordDto( + enteredUsername: (enteredUsername != null + ? enteredUsername.value + : this.enteredUsername)); + } +} + +@JsonSerializable(explicitToJson: true) +class ForgotPasswordPinDto { + const ForgotPasswordPinDto({ + required this.pin, + }); + + factory ForgotPasswordPinDto.fromJson(Map json) => + _$ForgotPasswordPinDtoFromJson(json); + + static const toJsonFactory = _$ForgotPasswordPinDtoToJson; + Map toJson() => _$ForgotPasswordPinDtoToJson(this); + + @JsonKey(name: 'Pin', includeIfNull: false) + final String pin; + static const fromJsonFactory = _$ForgotPasswordPinDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ForgotPasswordPinDto && + (identical(other.pin, pin) || + const DeepCollectionEquality().equals(other.pin, pin))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(pin) ^ runtimeType.hashCode; +} + +extension $ForgotPasswordPinDtoExtension on ForgotPasswordPinDto { + ForgotPasswordPinDto copyWith({String? pin}) { + return ForgotPasswordPinDto(pin: pin ?? this.pin); + } + + ForgotPasswordPinDto copyWithWrapped({Wrapped? pin}) { + return ForgotPasswordPinDto(pin: (pin != null ? pin.value : this.pin)); + } +} + +@JsonSerializable(explicitToJson: true) +class ForgotPasswordResult { + const ForgotPasswordResult({ + this.action, + this.pinFile, + this.pinExpirationDate, + }); + + factory ForgotPasswordResult.fromJson(Map json) => + _$ForgotPasswordResultFromJson(json); + + static const toJsonFactory = _$ForgotPasswordResultToJson; + Map toJson() => _$ForgotPasswordResultToJson(this); + + @JsonKey( + name: 'Action', + includeIfNull: false, + toJson: forgotPasswordActionNullableToJson, + fromJson: forgotPasswordActionNullableFromJson, + ) + final enums.ForgotPasswordAction? action; + @JsonKey(name: 'PinFile', includeIfNull: false) + final String? pinFile; + @JsonKey(name: 'PinExpirationDate', includeIfNull: false) + final DateTime? pinExpirationDate; + static const fromJsonFactory = _$ForgotPasswordResultFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ForgotPasswordResult && + (identical(other.action, action) || + const DeepCollectionEquality().equals(other.action, action)) && + (identical(other.pinFile, pinFile) || + const DeepCollectionEquality() + .equals(other.pinFile, pinFile)) && + (identical(other.pinExpirationDate, pinExpirationDate) || + const DeepCollectionEquality() + .equals(other.pinExpirationDate, pinExpirationDate))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(action) ^ + const DeepCollectionEquality().hash(pinFile) ^ + const DeepCollectionEquality().hash(pinExpirationDate) ^ + runtimeType.hashCode; +} + +extension $ForgotPasswordResultExtension on ForgotPasswordResult { + ForgotPasswordResult copyWith( + {enums.ForgotPasswordAction? action, + String? pinFile, + DateTime? pinExpirationDate}) { + return ForgotPasswordResult( + action: action ?? this.action, + pinFile: pinFile ?? this.pinFile, + pinExpirationDate: pinExpirationDate ?? this.pinExpirationDate); + } + + ForgotPasswordResult copyWithWrapped( + {Wrapped? action, + Wrapped? pinFile, + Wrapped? pinExpirationDate}) { + return ForgotPasswordResult( + action: (action != null ? action.value : this.action), + pinFile: (pinFile != null ? pinFile.value : this.pinFile), + pinExpirationDate: (pinExpirationDate != null + ? pinExpirationDate.value + : this.pinExpirationDate)); + } +} + +@JsonSerializable(explicitToJson: true) +class GeneralCommand { + const GeneralCommand({ + this.name, + this.controllingUserId, + this.arguments, + }); + + factory GeneralCommand.fromJson(Map json) => + _$GeneralCommandFromJson(json); + + static const toJsonFactory = _$GeneralCommandToJson; + Map toJson() => _$GeneralCommandToJson(this); + + @JsonKey( + name: 'Name', + includeIfNull: false, + toJson: generalCommandTypeNullableToJson, + fromJson: generalCommandTypeNullableFromJson, + ) + final enums.GeneralCommandType? name; + @JsonKey(name: 'ControllingUserId', includeIfNull: false) + final String? controllingUserId; + @JsonKey(name: 'Arguments', includeIfNull: false) + final Map? arguments; + static const fromJsonFactory = _$GeneralCommandFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is GeneralCommand && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.controllingUserId, controllingUserId) || + const DeepCollectionEquality() + .equals(other.controllingUserId, controllingUserId)) && + (identical(other.arguments, arguments) || + const DeepCollectionEquality() + .equals(other.arguments, arguments))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(controllingUserId) ^ + const DeepCollectionEquality().hash(arguments) ^ + runtimeType.hashCode; +} + +extension $GeneralCommandExtension on GeneralCommand { + GeneralCommand copyWith( + {enums.GeneralCommandType? name, + String? controllingUserId, + Map? arguments}) { + return GeneralCommand( + name: name ?? this.name, + controllingUserId: controllingUserId ?? this.controllingUserId, + arguments: arguments ?? this.arguments); + } + + GeneralCommand copyWithWrapped( + {Wrapped? name, + Wrapped? controllingUserId, + Wrapped?>? arguments}) { + return GeneralCommand( + name: (name != null ? name.value : this.name), + controllingUserId: (controllingUserId != null + ? controllingUserId.value + : this.controllingUserId), + arguments: (arguments != null ? arguments.value : this.arguments)); + } +} + +@JsonSerializable(explicitToJson: true) +class GeneralCommandMessage { + const GeneralCommandMessage({ + this.data, + this.messageId, + this.messageType, + }); + + factory GeneralCommandMessage.fromJson(Map json) => + _$GeneralCommandMessageFromJson(json); + + static const toJsonFactory = _$GeneralCommandMessageToJson; + Map toJson() => _$GeneralCommandMessageToJson(this); + + @JsonKey(name: 'Data', includeIfNull: false) + final GeneralCommand? data; + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.generalcommand); + + static const fromJsonFactory = _$GeneralCommandMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is GeneralCommandMessage && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data)) && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(data) ^ + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $GeneralCommandMessageExtension on GeneralCommandMessage { + GeneralCommandMessage copyWith( + {GeneralCommand? data, + String? messageId, + enums.SessionMessageType? messageType}) { + return GeneralCommandMessage( + data: data ?? this.data, + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + GeneralCommandMessage copyWithWrapped( + {Wrapped? data, + Wrapped? messageId, + Wrapped? messageType}) { + return GeneralCommandMessage( + data: (data != null ? data.value : this.data), + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class GetProgramsDto { + const GetProgramsDto({ + this.channelIds, + this.userId, + this.minStartDate, + this.hasAired, + this.isAiring, + this.maxStartDate, + this.minEndDate, + this.maxEndDate, + this.isMovie, + this.isSeries, + this.isNews, + this.isKids, + this.isSports, + this.startIndex, + this.limit, + this.sortBy, + this.sortOrder, + this.genres, + this.genreIds, + this.enableImages, + this.enableTotalRecordCount, + this.imageTypeLimit, + this.enableImageTypes, + this.enableUserData, + this.seriesTimerId, + this.librarySeriesId, + this.fields, + }); + + factory GetProgramsDto.fromJson(Map json) => + _$GetProgramsDtoFromJson(json); + + static const toJsonFactory = _$GetProgramsDtoToJson; + Map toJson() => _$GetProgramsDtoToJson(this); + + @JsonKey(name: 'ChannelIds', includeIfNull: false, defaultValue: []) + final List? channelIds; + @JsonKey(name: 'UserId', includeIfNull: false) + final String? userId; + @JsonKey(name: 'MinStartDate', includeIfNull: false) + final DateTime? minStartDate; + @JsonKey(name: 'HasAired', includeIfNull: false) + final bool? hasAired; + @JsonKey(name: 'IsAiring', includeIfNull: false) + final bool? isAiring; + @JsonKey(name: 'MaxStartDate', includeIfNull: false) + final DateTime? maxStartDate; + @JsonKey(name: 'MinEndDate', includeIfNull: false) + final DateTime? minEndDate; + @JsonKey(name: 'MaxEndDate', includeIfNull: false) + final DateTime? maxEndDate; + @JsonKey(name: 'IsMovie', includeIfNull: false) + final bool? isMovie; + @JsonKey(name: 'IsSeries', includeIfNull: false) + final bool? isSeries; + @JsonKey(name: 'IsNews', includeIfNull: false) + final bool? isNews; + @JsonKey(name: 'IsKids', includeIfNull: false) + final bool? isKids; + @JsonKey(name: 'IsSports', includeIfNull: false) + final bool? isSports; + @JsonKey(name: 'StartIndex', includeIfNull: false) + final int? startIndex; + @JsonKey(name: 'Limit', includeIfNull: false) + final int? limit; + @JsonKey( + name: 'SortBy', + includeIfNull: false, + toJson: itemSortByListToJson, + fromJson: itemSortByListFromJson, + ) + final List? sortBy; + @JsonKey( + name: 'SortOrder', + includeIfNull: false, + toJson: sortOrderListToJson, + fromJson: sortOrderListFromJson, + ) + final List? sortOrder; + @JsonKey(name: 'Genres', includeIfNull: false, defaultValue: []) + final List? genres; + @JsonKey(name: 'GenreIds', includeIfNull: false, defaultValue: []) + final List? genreIds; + @JsonKey(name: 'EnableImages', includeIfNull: false) + final bool? enableImages; + @JsonKey(name: 'EnableTotalRecordCount', includeIfNull: false) + final bool? enableTotalRecordCount; + @JsonKey(name: 'ImageTypeLimit', includeIfNull: false) + final int? imageTypeLimit; + @JsonKey( + name: 'EnableImageTypes', + includeIfNull: false, + toJson: imageTypeListToJson, + fromJson: imageTypeListFromJson, + ) + final List? enableImageTypes; + @JsonKey(name: 'EnableUserData', includeIfNull: false) + final bool? enableUserData; + @JsonKey(name: 'SeriesTimerId', includeIfNull: false) + final String? seriesTimerId; + @JsonKey(name: 'LibrarySeriesId', includeIfNull: false) + final String? librarySeriesId; + @JsonKey( + name: 'Fields', + includeIfNull: false, + toJson: itemFieldsListToJson, + fromJson: itemFieldsListFromJson, + ) + final List? fields; + static const fromJsonFactory = _$GetProgramsDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is GetProgramsDto && + (identical(other.channelIds, channelIds) || + const DeepCollectionEquality() + .equals(other.channelIds, channelIds)) && + (identical(other.userId, userId) || + const DeepCollectionEquality().equals(other.userId, userId)) && + (identical(other.minStartDate, minStartDate) || + const DeepCollectionEquality() + .equals(other.minStartDate, minStartDate)) && + (identical(other.hasAired, hasAired) || + const DeepCollectionEquality() + .equals(other.hasAired, hasAired)) && + (identical(other.isAiring, isAiring) || + const DeepCollectionEquality() + .equals(other.isAiring, isAiring)) && + (identical(other.maxStartDate, maxStartDate) || + const DeepCollectionEquality() + .equals(other.maxStartDate, maxStartDate)) && + (identical(other.minEndDate, minEndDate) || + const DeepCollectionEquality() + .equals(other.minEndDate, minEndDate)) && + (identical(other.maxEndDate, maxEndDate) || + const DeepCollectionEquality() + .equals(other.maxEndDate, maxEndDate)) && + (identical(other.isMovie, isMovie) || + const DeepCollectionEquality() + .equals(other.isMovie, isMovie)) && + (identical(other.isSeries, isSeries) || + const DeepCollectionEquality() + .equals(other.isSeries, isSeries)) && + (identical(other.isNews, isNews) || + const DeepCollectionEquality().equals(other.isNews, isNews)) && + (identical(other.isKids, isKids) || + const DeepCollectionEquality().equals(other.isKids, isKids)) && + (identical(other.isSports, isSports) || + const DeepCollectionEquality() + .equals(other.isSports, isSports)) && + (identical(other.startIndex, startIndex) || + const DeepCollectionEquality() + .equals(other.startIndex, startIndex)) && + (identical(other.limit, limit) || + const DeepCollectionEquality().equals(other.limit, limit)) && + (identical(other.sortBy, sortBy) || + const DeepCollectionEquality().equals(other.sortBy, sortBy)) && + (identical(other.sortOrder, sortOrder) || + const DeepCollectionEquality() + .equals(other.sortOrder, sortOrder)) && + (identical(other.genres, genres) || + const DeepCollectionEquality().equals(other.genres, genres)) && + (identical(other.genreIds, genreIds) || + const DeepCollectionEquality() + .equals(other.genreIds, genreIds)) && + (identical(other.enableImages, enableImages) || + const DeepCollectionEquality() + .equals(other.enableImages, enableImages)) && + (identical(other.enableTotalRecordCount, enableTotalRecordCount) || + const DeepCollectionEquality().equals( + other.enableTotalRecordCount, enableTotalRecordCount)) && + (identical(other.imageTypeLimit, imageTypeLimit) || + const DeepCollectionEquality() + .equals(other.imageTypeLimit, imageTypeLimit)) && + (identical(other.enableImageTypes, enableImageTypes) || + const DeepCollectionEquality() + .equals(other.enableImageTypes, enableImageTypes)) && + (identical(other.enableUserData, enableUserData) || + const DeepCollectionEquality() + .equals(other.enableUserData, enableUserData)) && + (identical(other.seriesTimerId, seriesTimerId) || + const DeepCollectionEquality().equals(other.seriesTimerId, seriesTimerId)) && + (identical(other.librarySeriesId, librarySeriesId) || const DeepCollectionEquality().equals(other.librarySeriesId, librarySeriesId)) && + (identical(other.fields, fields) || const DeepCollectionEquality().equals(other.fields, fields))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(channelIds) ^ + const DeepCollectionEquality().hash(userId) ^ + const DeepCollectionEquality().hash(minStartDate) ^ + const DeepCollectionEquality().hash(hasAired) ^ + const DeepCollectionEquality().hash(isAiring) ^ + const DeepCollectionEquality().hash(maxStartDate) ^ + const DeepCollectionEquality().hash(minEndDate) ^ + const DeepCollectionEquality().hash(maxEndDate) ^ + const DeepCollectionEquality().hash(isMovie) ^ + const DeepCollectionEquality().hash(isSeries) ^ + const DeepCollectionEquality().hash(isNews) ^ + const DeepCollectionEquality().hash(isKids) ^ + const DeepCollectionEquality().hash(isSports) ^ + const DeepCollectionEquality().hash(startIndex) ^ + const DeepCollectionEquality().hash(limit) ^ + const DeepCollectionEquality().hash(sortBy) ^ + const DeepCollectionEquality().hash(sortOrder) ^ + const DeepCollectionEquality().hash(genres) ^ + const DeepCollectionEquality().hash(genreIds) ^ + const DeepCollectionEquality().hash(enableImages) ^ + const DeepCollectionEquality().hash(enableTotalRecordCount) ^ + const DeepCollectionEquality().hash(imageTypeLimit) ^ + const DeepCollectionEquality().hash(enableImageTypes) ^ + const DeepCollectionEquality().hash(enableUserData) ^ + const DeepCollectionEquality().hash(seriesTimerId) ^ + const DeepCollectionEquality().hash(librarySeriesId) ^ + const DeepCollectionEquality().hash(fields) ^ + runtimeType.hashCode; +} + +extension $GetProgramsDtoExtension on GetProgramsDto { + GetProgramsDto copyWith( + {List? channelIds, + String? userId, + DateTime? minStartDate, + bool? hasAired, + bool? isAiring, + DateTime? maxStartDate, + DateTime? minEndDate, + DateTime? maxEndDate, + bool? isMovie, + bool? isSeries, + bool? isNews, + bool? isKids, + bool? isSports, + int? startIndex, + int? limit, + List? sortBy, + List? sortOrder, + List? genres, + List? genreIds, + bool? enableImages, + bool? enableTotalRecordCount, + int? imageTypeLimit, + List? enableImageTypes, + bool? enableUserData, + String? seriesTimerId, + String? librarySeriesId, + List? fields}) { + return GetProgramsDto( + channelIds: channelIds ?? this.channelIds, + userId: userId ?? this.userId, + minStartDate: minStartDate ?? this.minStartDate, + hasAired: hasAired ?? this.hasAired, + isAiring: isAiring ?? this.isAiring, + maxStartDate: maxStartDate ?? this.maxStartDate, + minEndDate: minEndDate ?? this.minEndDate, + maxEndDate: maxEndDate ?? this.maxEndDate, + isMovie: isMovie ?? this.isMovie, + isSeries: isSeries ?? this.isSeries, + isNews: isNews ?? this.isNews, + isKids: isKids ?? this.isKids, + isSports: isSports ?? this.isSports, + startIndex: startIndex ?? this.startIndex, + limit: limit ?? this.limit, + sortBy: sortBy ?? this.sortBy, + sortOrder: sortOrder ?? this.sortOrder, + genres: genres ?? this.genres, + genreIds: genreIds ?? this.genreIds, + enableImages: enableImages ?? this.enableImages, + enableTotalRecordCount: + enableTotalRecordCount ?? this.enableTotalRecordCount, + imageTypeLimit: imageTypeLimit ?? this.imageTypeLimit, + enableImageTypes: enableImageTypes ?? this.enableImageTypes, + enableUserData: enableUserData ?? this.enableUserData, + seriesTimerId: seriesTimerId ?? this.seriesTimerId, + librarySeriesId: librarySeriesId ?? this.librarySeriesId, + fields: fields ?? this.fields); + } + + GetProgramsDto copyWithWrapped( + {Wrapped?>? channelIds, + Wrapped? userId, + Wrapped? minStartDate, + Wrapped? hasAired, + Wrapped? isAiring, + Wrapped? maxStartDate, + Wrapped? minEndDate, + Wrapped? maxEndDate, + Wrapped? isMovie, + Wrapped? isSeries, + Wrapped? isNews, + Wrapped? isKids, + Wrapped? isSports, + Wrapped? startIndex, + Wrapped? limit, + Wrapped?>? sortBy, + Wrapped?>? sortOrder, + Wrapped?>? genres, + Wrapped?>? genreIds, + Wrapped? enableImages, + Wrapped? enableTotalRecordCount, + Wrapped? imageTypeLimit, + Wrapped?>? enableImageTypes, + Wrapped? enableUserData, + Wrapped? seriesTimerId, + Wrapped? librarySeriesId, + Wrapped?>? fields}) { + return GetProgramsDto( + channelIds: (channelIds != null ? channelIds.value : this.channelIds), + userId: (userId != null ? userId.value : this.userId), + minStartDate: + (minStartDate != null ? minStartDate.value : this.minStartDate), + hasAired: (hasAired != null ? hasAired.value : this.hasAired), + isAiring: (isAiring != null ? isAiring.value : this.isAiring), + maxStartDate: + (maxStartDate != null ? maxStartDate.value : this.maxStartDate), + minEndDate: (minEndDate != null ? minEndDate.value : this.minEndDate), + maxEndDate: (maxEndDate != null ? maxEndDate.value : this.maxEndDate), + isMovie: (isMovie != null ? isMovie.value : this.isMovie), + isSeries: (isSeries != null ? isSeries.value : this.isSeries), + isNews: (isNews != null ? isNews.value : this.isNews), + isKids: (isKids != null ? isKids.value : this.isKids), + isSports: (isSports != null ? isSports.value : this.isSports), + startIndex: (startIndex != null ? startIndex.value : this.startIndex), + limit: (limit != null ? limit.value : this.limit), + sortBy: (sortBy != null ? sortBy.value : this.sortBy), + sortOrder: (sortOrder != null ? sortOrder.value : this.sortOrder), + genres: (genres != null ? genres.value : this.genres), + genreIds: (genreIds != null ? genreIds.value : this.genreIds), + enableImages: + (enableImages != null ? enableImages.value : this.enableImages), + enableTotalRecordCount: (enableTotalRecordCount != null + ? enableTotalRecordCount.value + : this.enableTotalRecordCount), + imageTypeLimit: (imageTypeLimit != null + ? imageTypeLimit.value + : this.imageTypeLimit), + enableImageTypes: (enableImageTypes != null + ? enableImageTypes.value + : this.enableImageTypes), + enableUserData: (enableUserData != null + ? enableUserData.value + : this.enableUserData), + seriesTimerId: + (seriesTimerId != null ? seriesTimerId.value : this.seriesTimerId), + librarySeriesId: (librarySeriesId != null + ? librarySeriesId.value + : this.librarySeriesId), + fields: (fields != null ? fields.value : this.fields)); + } +} + +@JsonSerializable(explicitToJson: true) +class GroupInfoDto { + const GroupInfoDto({ + this.groupId, + this.groupName, + this.state, + this.participants, + this.lastUpdatedAt, + }); + + factory GroupInfoDto.fromJson(Map json) => + _$GroupInfoDtoFromJson(json); + + static const toJsonFactory = _$GroupInfoDtoToJson; + Map toJson() => _$GroupInfoDtoToJson(this); + + @JsonKey(name: 'GroupId', includeIfNull: false) + final String? groupId; + @JsonKey(name: 'GroupName', includeIfNull: false) + final String? groupName; + @JsonKey( + name: 'State', + includeIfNull: false, + toJson: groupStateTypeNullableToJson, + fromJson: groupStateTypeNullableFromJson, + ) + final enums.GroupStateType? state; + @JsonKey(name: 'Participants', includeIfNull: false, defaultValue: []) + final List? participants; + @JsonKey(name: 'LastUpdatedAt', includeIfNull: false) + final DateTime? lastUpdatedAt; + static const fromJsonFactory = _$GroupInfoDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is GroupInfoDto && + (identical(other.groupId, groupId) || + const DeepCollectionEquality() + .equals(other.groupId, groupId)) && + (identical(other.groupName, groupName) || + const DeepCollectionEquality() + .equals(other.groupName, groupName)) && + (identical(other.state, state) || + const DeepCollectionEquality().equals(other.state, state)) && + (identical(other.participants, participants) || + const DeepCollectionEquality() + .equals(other.participants, participants)) && + (identical(other.lastUpdatedAt, lastUpdatedAt) || + const DeepCollectionEquality() + .equals(other.lastUpdatedAt, lastUpdatedAt))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(groupId) ^ + const DeepCollectionEquality().hash(groupName) ^ + const DeepCollectionEquality().hash(state) ^ + const DeepCollectionEquality().hash(participants) ^ + const DeepCollectionEquality().hash(lastUpdatedAt) ^ + runtimeType.hashCode; +} + +extension $GroupInfoDtoExtension on GroupInfoDto { + GroupInfoDto copyWith( + {String? groupId, + String? groupName, + enums.GroupStateType? state, + List? participants, + DateTime? lastUpdatedAt}) { + return GroupInfoDto( + groupId: groupId ?? this.groupId, + groupName: groupName ?? this.groupName, + state: state ?? this.state, + participants: participants ?? this.participants, + lastUpdatedAt: lastUpdatedAt ?? this.lastUpdatedAt); + } + + GroupInfoDto copyWithWrapped( + {Wrapped? groupId, + Wrapped? groupName, + Wrapped? state, + Wrapped?>? participants, + Wrapped? lastUpdatedAt}) { + return GroupInfoDto( + groupId: (groupId != null ? groupId.value : this.groupId), + groupName: (groupName != null ? groupName.value : this.groupName), + state: (state != null ? state.value : this.state), + participants: + (participants != null ? participants.value : this.participants), + lastUpdatedAt: + (lastUpdatedAt != null ? lastUpdatedAt.value : this.lastUpdatedAt)); + } +} + +@JsonSerializable(explicitToJson: true) +class GroupInfoDtoGroupUpdate { + const GroupInfoDtoGroupUpdate({ + this.groupId, + this.type, + this.data, + }); + + factory GroupInfoDtoGroupUpdate.fromJson(Map json) => + _$GroupInfoDtoGroupUpdateFromJson(json); + + static const toJsonFactory = _$GroupInfoDtoGroupUpdateToJson; + Map toJson() => _$GroupInfoDtoGroupUpdateToJson(this); + + @JsonKey(name: 'GroupId', includeIfNull: false) + final String? groupId; + @JsonKey( + name: 'Type', + includeIfNull: false, + toJson: groupUpdateTypeNullableToJson, + fromJson: groupUpdateTypeNullableFromJson, + ) + final enums.GroupUpdateType? type; + @JsonKey(name: 'Data', includeIfNull: false) + final GroupInfoDto? data; + static const fromJsonFactory = _$GroupInfoDtoGroupUpdateFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is GroupInfoDtoGroupUpdate && + (identical(other.groupId, groupId) || + const DeepCollectionEquality() + .equals(other.groupId, groupId)) && + (identical(other.type, type) || + const DeepCollectionEquality().equals(other.type, type)) && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(groupId) ^ + const DeepCollectionEquality().hash(type) ^ + const DeepCollectionEquality().hash(data) ^ + runtimeType.hashCode; +} + +extension $GroupInfoDtoGroupUpdateExtension on GroupInfoDtoGroupUpdate { + GroupInfoDtoGroupUpdate copyWith( + {String? groupId, enums.GroupUpdateType? type, GroupInfoDto? data}) { + return GroupInfoDtoGroupUpdate( + groupId: groupId ?? this.groupId, + type: type ?? this.type, + data: data ?? this.data); + } + + GroupInfoDtoGroupUpdate copyWithWrapped( + {Wrapped? groupId, + Wrapped? type, + Wrapped? data}) { + return GroupInfoDtoGroupUpdate( + groupId: (groupId != null ? groupId.value : this.groupId), + type: (type != null ? type.value : this.type), + data: (data != null ? data.value : this.data)); + } +} + +@JsonSerializable(explicitToJson: true) +class GroupStateUpdate { + const GroupStateUpdate({ + this.state, + this.reason, + }); + + factory GroupStateUpdate.fromJson(Map json) => + _$GroupStateUpdateFromJson(json); + + static const toJsonFactory = _$GroupStateUpdateToJson; + Map toJson() => _$GroupStateUpdateToJson(this); + + @JsonKey( + name: 'State', + includeIfNull: false, + toJson: groupStateTypeNullableToJson, + fromJson: groupStateTypeNullableFromJson, + ) + final enums.GroupStateType? state; + @JsonKey( + name: 'Reason', + includeIfNull: false, + toJson: playbackRequestTypeNullableToJson, + fromJson: playbackRequestTypeNullableFromJson, + ) + final enums.PlaybackRequestType? reason; + static const fromJsonFactory = _$GroupStateUpdateFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is GroupStateUpdate && + (identical(other.state, state) || + const DeepCollectionEquality().equals(other.state, state)) && + (identical(other.reason, reason) || + const DeepCollectionEquality().equals(other.reason, reason))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(state) ^ + const DeepCollectionEquality().hash(reason) ^ + runtimeType.hashCode; +} + +extension $GroupStateUpdateExtension on GroupStateUpdate { + GroupStateUpdate copyWith( + {enums.GroupStateType? state, enums.PlaybackRequestType? reason}) { + return GroupStateUpdate( + state: state ?? this.state, reason: reason ?? this.reason); + } + + GroupStateUpdate copyWithWrapped( + {Wrapped? state, + Wrapped? reason}) { + return GroupStateUpdate( + state: (state != null ? state.value : this.state), + reason: (reason != null ? reason.value : this.reason)); + } +} + +@JsonSerializable(explicitToJson: true) +class GroupStateUpdateGroupUpdate { + const GroupStateUpdateGroupUpdate({ + this.groupId, + this.type, + this.data, + }); + + factory GroupStateUpdateGroupUpdate.fromJson(Map json) => + _$GroupStateUpdateGroupUpdateFromJson(json); + + static const toJsonFactory = _$GroupStateUpdateGroupUpdateToJson; + Map toJson() => _$GroupStateUpdateGroupUpdateToJson(this); + + @JsonKey(name: 'GroupId', includeIfNull: false) + final String? groupId; + @JsonKey( + name: 'Type', + includeIfNull: false, + toJson: groupUpdateTypeNullableToJson, + fromJson: groupUpdateTypeNullableFromJson, + ) + final enums.GroupUpdateType? type; + @JsonKey(name: 'Data', includeIfNull: false) + final GroupStateUpdate? data; + static const fromJsonFactory = _$GroupStateUpdateGroupUpdateFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is GroupStateUpdateGroupUpdate && + (identical(other.groupId, groupId) || + const DeepCollectionEquality() + .equals(other.groupId, groupId)) && + (identical(other.type, type) || + const DeepCollectionEquality().equals(other.type, type)) && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(groupId) ^ + const DeepCollectionEquality().hash(type) ^ + const DeepCollectionEquality().hash(data) ^ + runtimeType.hashCode; +} + +extension $GroupStateUpdateGroupUpdateExtension on GroupStateUpdateGroupUpdate { + GroupStateUpdateGroupUpdate copyWith( + {String? groupId, enums.GroupUpdateType? type, GroupStateUpdate? data}) { + return GroupStateUpdateGroupUpdate( + groupId: groupId ?? this.groupId, + type: type ?? this.type, + data: data ?? this.data); + } + + GroupStateUpdateGroupUpdate copyWithWrapped( + {Wrapped? groupId, + Wrapped? type, + Wrapped? data}) { + return GroupStateUpdateGroupUpdate( + groupId: (groupId != null ? groupId.value : this.groupId), + type: (type != null ? type.value : this.type), + data: (data != null ? data.value : this.data)); + } +} + +@JsonSerializable(explicitToJson: true) +class GroupUpdate { + const GroupUpdate({ + this.groupId, + this.type, + }); + + factory GroupUpdate.fromJson(Map json) => + _$GroupUpdateFromJson(json); + + static const toJsonFactory = _$GroupUpdateToJson; + Map toJson() => _$GroupUpdateToJson(this); + + @JsonKey(name: 'GroupId', includeIfNull: false) + final String? groupId; + @JsonKey( + name: 'Type', + includeIfNull: false, + toJson: groupUpdateTypeNullableToJson, + fromJson: groupUpdateTypeNullableFromJson, + ) + final enums.GroupUpdateType? type; + static const fromJsonFactory = _$GroupUpdateFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is GroupUpdate && + (identical(other.groupId, groupId) || + const DeepCollectionEquality() + .equals(other.groupId, groupId)) && + (identical(other.type, type) || + const DeepCollectionEquality().equals(other.type, type))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(groupId) ^ + const DeepCollectionEquality().hash(type) ^ + runtimeType.hashCode; +} + +extension $GroupUpdateExtension on GroupUpdate { + GroupUpdate copyWith({String? groupId, enums.GroupUpdateType? type}) { + return GroupUpdate( + groupId: groupId ?? this.groupId, type: type ?? this.type); + } + + GroupUpdate copyWithWrapped( + {Wrapped? groupId, Wrapped? type}) { + return GroupUpdate( + groupId: (groupId != null ? groupId.value : this.groupId), + type: (type != null ? type.value : this.type)); + } +} + +@JsonSerializable(explicitToJson: true) +class GuideInfo { + const GuideInfo({ + this.startDate, + this.endDate, + }); + + factory GuideInfo.fromJson(Map json) => + _$GuideInfoFromJson(json); + + static const toJsonFactory = _$GuideInfoToJson; + Map toJson() => _$GuideInfoToJson(this); + + @JsonKey(name: 'StartDate', includeIfNull: false) + final DateTime? startDate; + @JsonKey(name: 'EndDate', includeIfNull: false) + final DateTime? endDate; + static const fromJsonFactory = _$GuideInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is GuideInfo && + (identical(other.startDate, startDate) || + const DeepCollectionEquality() + .equals(other.startDate, startDate)) && + (identical(other.endDate, endDate) || + const DeepCollectionEquality().equals(other.endDate, endDate))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(startDate) ^ + const DeepCollectionEquality().hash(endDate) ^ + runtimeType.hashCode; +} + +extension $GuideInfoExtension on GuideInfo { + GuideInfo copyWith({DateTime? startDate, DateTime? endDate}) { + return GuideInfo( + startDate: startDate ?? this.startDate, + endDate: endDate ?? this.endDate); + } + + GuideInfo copyWithWrapped( + {Wrapped? startDate, Wrapped? endDate}) { + return GuideInfo( + startDate: (startDate != null ? startDate.value : this.startDate), + endDate: (endDate != null ? endDate.value : this.endDate)); + } +} + +@JsonSerializable(explicitToJson: true) +class IgnoreWaitRequestDto { + const IgnoreWaitRequestDto({ + this.ignoreWait, + }); + + factory IgnoreWaitRequestDto.fromJson(Map json) => + _$IgnoreWaitRequestDtoFromJson(json); + + static const toJsonFactory = _$IgnoreWaitRequestDtoToJson; + Map toJson() => _$IgnoreWaitRequestDtoToJson(this); + + @JsonKey(name: 'IgnoreWait', includeIfNull: false) + final bool? ignoreWait; + static const fromJsonFactory = _$IgnoreWaitRequestDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is IgnoreWaitRequestDto && + (identical(other.ignoreWait, ignoreWait) || + const DeepCollectionEquality() + .equals(other.ignoreWait, ignoreWait))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(ignoreWait) ^ runtimeType.hashCode; +} + +extension $IgnoreWaitRequestDtoExtension on IgnoreWaitRequestDto { + IgnoreWaitRequestDto copyWith({bool? ignoreWait}) { + return IgnoreWaitRequestDto(ignoreWait: ignoreWait ?? this.ignoreWait); + } + + IgnoreWaitRequestDto copyWithWrapped({Wrapped? ignoreWait}) { + return IgnoreWaitRequestDto( + ignoreWait: (ignoreWait != null ? ignoreWait.value : this.ignoreWait)); + } +} + +@JsonSerializable(explicitToJson: true) +class ImageInfo { + const ImageInfo({ + this.imageType, + this.imageIndex, + this.imageTag, + this.path, + this.blurHash, + this.height, + this.width, + this.size, + }); + + factory ImageInfo.fromJson(Map json) => + _$ImageInfoFromJson(json); + + static const toJsonFactory = _$ImageInfoToJson; + Map toJson() => _$ImageInfoToJson(this); + + @JsonKey( + name: 'ImageType', + includeIfNull: false, + toJson: imageTypeNullableToJson, + fromJson: imageTypeNullableFromJson, + ) + final enums.ImageType? imageType; + @JsonKey(name: 'ImageIndex', includeIfNull: false) + final int? imageIndex; + @JsonKey(name: 'ImageTag', includeIfNull: false) + final String? imageTag; + @JsonKey(name: 'Path', includeIfNull: false) + final String? path; + @JsonKey(name: 'BlurHash', includeIfNull: false) + final String? blurHash; + @JsonKey(name: 'Height', includeIfNull: false) + final int? height; + @JsonKey(name: 'Width', includeIfNull: false) + final int? width; + @JsonKey(name: 'Size', includeIfNull: false) + final int? size; + static const fromJsonFactory = _$ImageInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ImageInfo && + (identical(other.imageType, imageType) || + const DeepCollectionEquality() + .equals(other.imageType, imageType)) && + (identical(other.imageIndex, imageIndex) || + const DeepCollectionEquality() + .equals(other.imageIndex, imageIndex)) && + (identical(other.imageTag, imageTag) || + const DeepCollectionEquality() + .equals(other.imageTag, imageTag)) && + (identical(other.path, path) || + const DeepCollectionEquality().equals(other.path, path)) && + (identical(other.blurHash, blurHash) || + const DeepCollectionEquality() + .equals(other.blurHash, blurHash)) && + (identical(other.height, height) || + const DeepCollectionEquality().equals(other.height, height)) && + (identical(other.width, width) || + const DeepCollectionEquality().equals(other.width, width)) && + (identical(other.size, size) || + const DeepCollectionEquality().equals(other.size, size))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(imageType) ^ + const DeepCollectionEquality().hash(imageIndex) ^ + const DeepCollectionEquality().hash(imageTag) ^ + const DeepCollectionEquality().hash(path) ^ + const DeepCollectionEquality().hash(blurHash) ^ + const DeepCollectionEquality().hash(height) ^ + const DeepCollectionEquality().hash(width) ^ + const DeepCollectionEquality().hash(size) ^ + runtimeType.hashCode; +} + +extension $ImageInfoExtension on ImageInfo { + ImageInfo copyWith( + {enums.ImageType? imageType, + int? imageIndex, + String? imageTag, + String? path, + String? blurHash, + int? height, + int? width, + int? size}) { + return ImageInfo( + imageType: imageType ?? this.imageType, + imageIndex: imageIndex ?? this.imageIndex, + imageTag: imageTag ?? this.imageTag, + path: path ?? this.path, + blurHash: blurHash ?? this.blurHash, + height: height ?? this.height, + width: width ?? this.width, + size: size ?? this.size); + } + + ImageInfo copyWithWrapped( + {Wrapped? imageType, + Wrapped? imageIndex, + Wrapped? imageTag, + Wrapped? path, + Wrapped? blurHash, + Wrapped? height, + Wrapped? width, + Wrapped? size}) { + return ImageInfo( + imageType: (imageType != null ? imageType.value : this.imageType), + imageIndex: (imageIndex != null ? imageIndex.value : this.imageIndex), + imageTag: (imageTag != null ? imageTag.value : this.imageTag), + path: (path != null ? path.value : this.path), + blurHash: (blurHash != null ? blurHash.value : this.blurHash), + height: (height != null ? height.value : this.height), + width: (width != null ? width.value : this.width), + size: (size != null ? size.value : this.size)); + } +} + +@JsonSerializable(explicitToJson: true) +class ImageOption { + const ImageOption({ + this.type, + this.limit, + this.minWidth, + }); + + factory ImageOption.fromJson(Map json) => + _$ImageOptionFromJson(json); + + static const toJsonFactory = _$ImageOptionToJson; + Map toJson() => _$ImageOptionToJson(this); + + @JsonKey( + name: 'Type', + includeIfNull: false, + toJson: imageTypeNullableToJson, + fromJson: imageTypeNullableFromJson, + ) + final enums.ImageType? type; + @JsonKey(name: 'Limit', includeIfNull: false) + final int? limit; + @JsonKey(name: 'MinWidth', includeIfNull: false) + final int? minWidth; + static const fromJsonFactory = _$ImageOptionFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ImageOption && + (identical(other.type, type) || + const DeepCollectionEquality().equals(other.type, type)) && + (identical(other.limit, limit) || + const DeepCollectionEquality().equals(other.limit, limit)) && + (identical(other.minWidth, minWidth) || + const DeepCollectionEquality() + .equals(other.minWidth, minWidth))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(type) ^ + const DeepCollectionEquality().hash(limit) ^ + const DeepCollectionEquality().hash(minWidth) ^ + runtimeType.hashCode; +} + +extension $ImageOptionExtension on ImageOption { + ImageOption copyWith({enums.ImageType? type, int? limit, int? minWidth}) { + return ImageOption( + type: type ?? this.type, + limit: limit ?? this.limit, + minWidth: minWidth ?? this.minWidth); + } + + ImageOption copyWithWrapped( + {Wrapped? type, + Wrapped? limit, + Wrapped? minWidth}) { + return ImageOption( + type: (type != null ? type.value : this.type), + limit: (limit != null ? limit.value : this.limit), + minWidth: (minWidth != null ? minWidth.value : this.minWidth)); + } +} + +@JsonSerializable(explicitToJson: true) +class ImageProviderInfo { + const ImageProviderInfo({ + this.name, + this.supportedImages, + }); + + factory ImageProviderInfo.fromJson(Map json) => + _$ImageProviderInfoFromJson(json); + + static const toJsonFactory = _$ImageProviderInfoToJson; + Map toJson() => _$ImageProviderInfoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey( + name: 'SupportedImages', + includeIfNull: false, + toJson: imageTypeListToJson, + fromJson: imageTypeListFromJson, + ) + final List? supportedImages; + static const fromJsonFactory = _$ImageProviderInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ImageProviderInfo && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.supportedImages, supportedImages) || + const DeepCollectionEquality() + .equals(other.supportedImages, supportedImages))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(supportedImages) ^ + runtimeType.hashCode; +} + +extension $ImageProviderInfoExtension on ImageProviderInfo { + ImageProviderInfo copyWith( + {String? name, List? supportedImages}) { + return ImageProviderInfo( + name: name ?? this.name, + supportedImages: supportedImages ?? this.supportedImages); + } + + ImageProviderInfo copyWithWrapped( + {Wrapped? name, + Wrapped?>? supportedImages}) { + return ImageProviderInfo( + name: (name != null ? name.value : this.name), + supportedImages: (supportedImages != null + ? supportedImages.value + : this.supportedImages)); + } +} + +@JsonSerializable(explicitToJson: true) +class InboundKeepAliveMessage { + const InboundKeepAliveMessage({ + this.messageType, + }); + + factory InboundKeepAliveMessage.fromJson(Map json) => + _$InboundKeepAliveMessageFromJson(json); + + static const toJsonFactory = _$InboundKeepAliveMessageToJson; + Map toJson() => _$InboundKeepAliveMessageToJson(this); + + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.keepalive); + + static const fromJsonFactory = _$InboundKeepAliveMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is InboundKeepAliveMessage && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(messageType) ^ runtimeType.hashCode; +} + +extension $InboundKeepAliveMessageExtension on InboundKeepAliveMessage { + InboundKeepAliveMessage copyWith({enums.SessionMessageType? messageType}) { + return InboundKeepAliveMessage( + messageType: messageType ?? this.messageType); + } + + InboundKeepAliveMessage copyWithWrapped( + {Wrapped? messageType}) { + return InboundKeepAliveMessage( + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class InboundWebSocketMessage { + const InboundWebSocketMessage(); + + factory InboundWebSocketMessage.fromJson(Map json) => + _$InboundWebSocketMessageFromJson(json); + + static const toJsonFactory = _$InboundWebSocketMessageToJson; + Map toJson() => _$InboundWebSocketMessageToJson(this); + + static const fromJsonFactory = _$InboundWebSocketMessageFromJson; + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => runtimeType.hashCode; +} + +@JsonSerializable(explicitToJson: true) +class InstallationInfo { + const InstallationInfo({ + this.guid, + this.name, + this.version, + this.changelog, + this.sourceUrl, + this.checksum, + this.packageInfo, + }); + + factory InstallationInfo.fromJson(Map json) => + _$InstallationInfoFromJson(json); + + static const toJsonFactory = _$InstallationInfoToJson; + Map toJson() => _$InstallationInfoToJson(this); + + @JsonKey(name: 'Guid', includeIfNull: false) + final String? guid; + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'Version', includeIfNull: false) + final String? version; + @JsonKey(name: 'Changelog', includeIfNull: false) + final String? changelog; + @JsonKey(name: 'SourceUrl', includeIfNull: false) + final String? sourceUrl; + @JsonKey(name: 'Checksum', includeIfNull: false) + final String? checksum; + @JsonKey(name: 'PackageInfo', includeIfNull: false) + final PackageInfo? packageInfo; + static const fromJsonFactory = _$InstallationInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is InstallationInfo && + (identical(other.guid, guid) || + const DeepCollectionEquality().equals(other.guid, guid)) && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.version, version) || + const DeepCollectionEquality() + .equals(other.version, version)) && + (identical(other.changelog, changelog) || + const DeepCollectionEquality() + .equals(other.changelog, changelog)) && + (identical(other.sourceUrl, sourceUrl) || + const DeepCollectionEquality() + .equals(other.sourceUrl, sourceUrl)) && + (identical(other.checksum, checksum) || + const DeepCollectionEquality() + .equals(other.checksum, checksum)) && + (identical(other.packageInfo, packageInfo) || + const DeepCollectionEquality() + .equals(other.packageInfo, packageInfo))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(guid) ^ + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(version) ^ + const DeepCollectionEquality().hash(changelog) ^ + const DeepCollectionEquality().hash(sourceUrl) ^ + const DeepCollectionEquality().hash(checksum) ^ + const DeepCollectionEquality().hash(packageInfo) ^ + runtimeType.hashCode; +} + +extension $InstallationInfoExtension on InstallationInfo { + InstallationInfo copyWith( + {String? guid, + String? name, + String? version, + String? changelog, + String? sourceUrl, + String? checksum, + PackageInfo? packageInfo}) { + return InstallationInfo( + guid: guid ?? this.guid, + name: name ?? this.name, + version: version ?? this.version, + changelog: changelog ?? this.changelog, + sourceUrl: sourceUrl ?? this.sourceUrl, + checksum: checksum ?? this.checksum, + packageInfo: packageInfo ?? this.packageInfo); + } + + InstallationInfo copyWithWrapped( + {Wrapped? guid, + Wrapped? name, + Wrapped? version, + Wrapped? changelog, + Wrapped? sourceUrl, + Wrapped? checksum, + Wrapped? packageInfo}) { + return InstallationInfo( + guid: (guid != null ? guid.value : this.guid), + name: (name != null ? name.value : this.name), + version: (version != null ? version.value : this.version), + changelog: (changelog != null ? changelog.value : this.changelog), + sourceUrl: (sourceUrl != null ? sourceUrl.value : this.sourceUrl), + checksum: (checksum != null ? checksum.value : this.checksum), + packageInfo: + (packageInfo != null ? packageInfo.value : this.packageInfo)); + } +} + +@JsonSerializable(explicitToJson: true) +class Intro { + const Intro({ + this.episodeId, + this.valid, + this.introStart, + this.introEnd, + this.showSkipPromptAt, + this.hideSkipPromptAt, + }); + + factory Intro.fromJson(Map json) => _$IntroFromJson(json); + + static const toJsonFactory = _$IntroToJson; + Map toJson() => _$IntroToJson(this); + + @JsonKey(name: 'EpisodeId', includeIfNull: false) + final String? episodeId; + @JsonKey(name: 'Valid', includeIfNull: false) + final bool? valid; + @JsonKey(name: 'IntroStart', includeIfNull: false) + final double? introStart; + @JsonKey(name: 'IntroEnd', includeIfNull: false) + final double? introEnd; + @JsonKey(name: 'ShowSkipPromptAt', includeIfNull: false) + final double? showSkipPromptAt; + @JsonKey(name: 'HideSkipPromptAt', includeIfNull: false) + final double? hideSkipPromptAt; + static const fromJsonFactory = _$IntroFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is Intro && + (identical(other.episodeId, episodeId) || + const DeepCollectionEquality() + .equals(other.episodeId, episodeId)) && + (identical(other.valid, valid) || + const DeepCollectionEquality().equals(other.valid, valid)) && + (identical(other.introStart, introStart) || + const DeepCollectionEquality() + .equals(other.introStart, introStart)) && + (identical(other.introEnd, introEnd) || + const DeepCollectionEquality() + .equals(other.introEnd, introEnd)) && + (identical(other.showSkipPromptAt, showSkipPromptAt) || + const DeepCollectionEquality() + .equals(other.showSkipPromptAt, showSkipPromptAt)) && + (identical(other.hideSkipPromptAt, hideSkipPromptAt) || + const DeepCollectionEquality() + .equals(other.hideSkipPromptAt, hideSkipPromptAt))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(episodeId) ^ + const DeepCollectionEquality().hash(valid) ^ + const DeepCollectionEquality().hash(introStart) ^ + const DeepCollectionEquality().hash(introEnd) ^ + const DeepCollectionEquality().hash(showSkipPromptAt) ^ + const DeepCollectionEquality().hash(hideSkipPromptAt) ^ + runtimeType.hashCode; +} + +extension $IntroExtension on Intro { + Intro copyWith( + {String? episodeId, + bool? valid, + double? introStart, + double? introEnd, + double? showSkipPromptAt, + double? hideSkipPromptAt}) { + return Intro( + episodeId: episodeId ?? this.episodeId, + valid: valid ?? this.valid, + introStart: introStart ?? this.introStart, + introEnd: introEnd ?? this.introEnd, + showSkipPromptAt: showSkipPromptAt ?? this.showSkipPromptAt, + hideSkipPromptAt: hideSkipPromptAt ?? this.hideSkipPromptAt); + } + + Intro copyWithWrapped( + {Wrapped? episodeId, + Wrapped? valid, + Wrapped? introStart, + Wrapped? introEnd, + Wrapped? showSkipPromptAt, + Wrapped? hideSkipPromptAt}) { + return Intro( + episodeId: (episodeId != null ? episodeId.value : this.episodeId), + valid: (valid != null ? valid.value : this.valid), + introStart: (introStart != null ? introStart.value : this.introStart), + introEnd: (introEnd != null ? introEnd.value : this.introEnd), + showSkipPromptAt: (showSkipPromptAt != null + ? showSkipPromptAt.value + : this.showSkipPromptAt), + hideSkipPromptAt: (hideSkipPromptAt != null + ? hideSkipPromptAt.value + : this.hideSkipPromptAt)); + } +} + +@JsonSerializable(explicitToJson: true) +class IntroWithMetadata { + const IntroWithMetadata({ + this.episodeId, + this.valid, + this.introStart, + this.introEnd, + this.showSkipPromptAt, + this.hideSkipPromptAt, + this.series, + this.season, + this.title, + }); + + factory IntroWithMetadata.fromJson(Map json) => + _$IntroWithMetadataFromJson(json); + + static const toJsonFactory = _$IntroWithMetadataToJson; + Map toJson() => _$IntroWithMetadataToJson(this); + + @JsonKey(name: 'EpisodeId', includeIfNull: false) + final String? episodeId; + @JsonKey(name: 'Valid', includeIfNull: false) + final bool? valid; + @JsonKey(name: 'IntroStart', includeIfNull: false) + final double? introStart; + @JsonKey(name: 'IntroEnd', includeIfNull: false) + final double? introEnd; + @JsonKey(name: 'ShowSkipPromptAt', includeIfNull: false) + final double? showSkipPromptAt; + @JsonKey(name: 'HideSkipPromptAt', includeIfNull: false) + final double? hideSkipPromptAt; + @JsonKey(name: 'Series', includeIfNull: false) + final String? series; + @JsonKey(name: 'Season', includeIfNull: false) + final int? season; + @JsonKey(name: 'Title', includeIfNull: false) + final String? title; + static const fromJsonFactory = _$IntroWithMetadataFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is IntroWithMetadata && + (identical(other.episodeId, episodeId) || + const DeepCollectionEquality() + .equals(other.episodeId, episodeId)) && + (identical(other.valid, valid) || + const DeepCollectionEquality().equals(other.valid, valid)) && + (identical(other.introStart, introStart) || + const DeepCollectionEquality() + .equals(other.introStart, introStart)) && + (identical(other.introEnd, introEnd) || + const DeepCollectionEquality() + .equals(other.introEnd, introEnd)) && + (identical(other.showSkipPromptAt, showSkipPromptAt) || + const DeepCollectionEquality() + .equals(other.showSkipPromptAt, showSkipPromptAt)) && + (identical(other.hideSkipPromptAt, hideSkipPromptAt) || + const DeepCollectionEquality() + .equals(other.hideSkipPromptAt, hideSkipPromptAt)) && + (identical(other.series, series) || + const DeepCollectionEquality().equals(other.series, series)) && + (identical(other.season, season) || + const DeepCollectionEquality().equals(other.season, season)) && + (identical(other.title, title) || + const DeepCollectionEquality().equals(other.title, title))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(episodeId) ^ + const DeepCollectionEquality().hash(valid) ^ + const DeepCollectionEquality().hash(introStart) ^ + const DeepCollectionEquality().hash(introEnd) ^ + const DeepCollectionEquality().hash(showSkipPromptAt) ^ + const DeepCollectionEquality().hash(hideSkipPromptAt) ^ + const DeepCollectionEquality().hash(series) ^ + const DeepCollectionEquality().hash(season) ^ + const DeepCollectionEquality().hash(title) ^ + runtimeType.hashCode; +} + +extension $IntroWithMetadataExtension on IntroWithMetadata { + IntroWithMetadata copyWith( + {String? episodeId, + bool? valid, + double? introStart, + double? introEnd, + double? showSkipPromptAt, + double? hideSkipPromptAt, + String? series, + int? season, + String? title}) { + return IntroWithMetadata( + episodeId: episodeId ?? this.episodeId, + valid: valid ?? this.valid, + introStart: introStart ?? this.introStart, + introEnd: introEnd ?? this.introEnd, + showSkipPromptAt: showSkipPromptAt ?? this.showSkipPromptAt, + hideSkipPromptAt: hideSkipPromptAt ?? this.hideSkipPromptAt, + series: series ?? this.series, + season: season ?? this.season, + title: title ?? this.title); + } + + IntroWithMetadata copyWithWrapped( + {Wrapped? episodeId, + Wrapped? valid, + Wrapped? introStart, + Wrapped? introEnd, + Wrapped? showSkipPromptAt, + Wrapped? hideSkipPromptAt, + Wrapped? series, + Wrapped? season, + Wrapped? title}) { + return IntroWithMetadata( + episodeId: (episodeId != null ? episodeId.value : this.episodeId), + valid: (valid != null ? valid.value : this.valid), + introStart: (introStart != null ? introStart.value : this.introStart), + introEnd: (introEnd != null ? introEnd.value : this.introEnd), + showSkipPromptAt: (showSkipPromptAt != null + ? showSkipPromptAt.value + : this.showSkipPromptAt), + hideSkipPromptAt: (hideSkipPromptAt != null + ? hideSkipPromptAt.value + : this.hideSkipPromptAt), + series: (series != null ? series.value : this.series), + season: (season != null ? season.value : this.season), + title: (title != null ? title.value : this.title)); + } +} + +@JsonSerializable(explicitToJson: true) +class IPlugin { + const IPlugin({ + this.name, + this.description, + this.id, + this.version, + this.assemblyFilePath, + this.canUninstall, + this.dataFolderPath, + }); + + factory IPlugin.fromJson(Map json) => + _$IPluginFromJson(json); + + static const toJsonFactory = _$IPluginToJson; + Map toJson() => _$IPluginToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'Description', includeIfNull: false) + final String? description; + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'Version', includeIfNull: false) + final String? version; + @JsonKey(name: 'AssemblyFilePath', includeIfNull: false) + final String? assemblyFilePath; + @JsonKey(name: 'CanUninstall', includeIfNull: false) + final bool? canUninstall; + @JsonKey(name: 'DataFolderPath', includeIfNull: false) + final String? dataFolderPath; + static const fromJsonFactory = _$IPluginFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is IPlugin && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.description, description) || + const DeepCollectionEquality() + .equals(other.description, description)) && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.version, version) || + const DeepCollectionEquality() + .equals(other.version, version)) && + (identical(other.assemblyFilePath, assemblyFilePath) || + const DeepCollectionEquality() + .equals(other.assemblyFilePath, assemblyFilePath)) && + (identical(other.canUninstall, canUninstall) || + const DeepCollectionEquality() + .equals(other.canUninstall, canUninstall)) && + (identical(other.dataFolderPath, dataFolderPath) || + const DeepCollectionEquality() + .equals(other.dataFolderPath, dataFolderPath))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(description) ^ + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(version) ^ + const DeepCollectionEquality().hash(assemblyFilePath) ^ + const DeepCollectionEquality().hash(canUninstall) ^ + const DeepCollectionEquality().hash(dataFolderPath) ^ + runtimeType.hashCode; +} + +extension $IPluginExtension on IPlugin { + IPlugin copyWith( + {String? name, + String? description, + String? id, + String? version, + String? assemblyFilePath, + bool? canUninstall, + String? dataFolderPath}) { + return IPlugin( + name: name ?? this.name, + description: description ?? this.description, + id: id ?? this.id, + version: version ?? this.version, + assemblyFilePath: assemblyFilePath ?? this.assemblyFilePath, + canUninstall: canUninstall ?? this.canUninstall, + dataFolderPath: dataFolderPath ?? this.dataFolderPath); + } + + IPlugin copyWithWrapped( + {Wrapped? name, + Wrapped? description, + Wrapped? id, + Wrapped? version, + Wrapped? assemblyFilePath, + Wrapped? canUninstall, + Wrapped? dataFolderPath}) { + return IPlugin( + name: (name != null ? name.value : this.name), + description: + (description != null ? description.value : this.description), + id: (id != null ? id.value : this.id), + version: (version != null ? version.value : this.version), + assemblyFilePath: (assemblyFilePath != null + ? assemblyFilePath.value + : this.assemblyFilePath), + canUninstall: + (canUninstall != null ? canUninstall.value : this.canUninstall), + dataFolderPath: (dataFolderPath != null + ? dataFolderPath.value + : this.dataFolderPath)); + } +} + +@JsonSerializable(explicitToJson: true) +class ItemCounts { + const ItemCounts({ + this.movieCount, + this.seriesCount, + this.episodeCount, + this.artistCount, + this.programCount, + this.trailerCount, + this.songCount, + this.albumCount, + this.musicVideoCount, + this.boxSetCount, + this.bookCount, + this.itemCount, + }); + + factory ItemCounts.fromJson(Map json) => + _$ItemCountsFromJson(json); + + static const toJsonFactory = _$ItemCountsToJson; + Map toJson() => _$ItemCountsToJson(this); + + @JsonKey(name: 'MovieCount', includeIfNull: false) + final int? movieCount; + @JsonKey(name: 'SeriesCount', includeIfNull: false) + final int? seriesCount; + @JsonKey(name: 'EpisodeCount', includeIfNull: false) + final int? episodeCount; + @JsonKey(name: 'ArtistCount', includeIfNull: false) + final int? artistCount; + @JsonKey(name: 'ProgramCount', includeIfNull: false) + final int? programCount; + @JsonKey(name: 'TrailerCount', includeIfNull: false) + final int? trailerCount; + @JsonKey(name: 'SongCount', includeIfNull: false) + final int? songCount; + @JsonKey(name: 'AlbumCount', includeIfNull: false) + final int? albumCount; + @JsonKey(name: 'MusicVideoCount', includeIfNull: false) + final int? musicVideoCount; + @JsonKey(name: 'BoxSetCount', includeIfNull: false) + final int? boxSetCount; + @JsonKey(name: 'BookCount', includeIfNull: false) + final int? bookCount; + @JsonKey(name: 'ItemCount', includeIfNull: false) + final int? itemCount; + static const fromJsonFactory = _$ItemCountsFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ItemCounts && + (identical(other.movieCount, movieCount) || + const DeepCollectionEquality() + .equals(other.movieCount, movieCount)) && + (identical(other.seriesCount, seriesCount) || + const DeepCollectionEquality() + .equals(other.seriesCount, seriesCount)) && + (identical(other.episodeCount, episodeCount) || + const DeepCollectionEquality() + .equals(other.episodeCount, episodeCount)) && + (identical(other.artistCount, artistCount) || + const DeepCollectionEquality() + .equals(other.artistCount, artistCount)) && + (identical(other.programCount, programCount) || + const DeepCollectionEquality() + .equals(other.programCount, programCount)) && + (identical(other.trailerCount, trailerCount) || + const DeepCollectionEquality() + .equals(other.trailerCount, trailerCount)) && + (identical(other.songCount, songCount) || + const DeepCollectionEquality() + .equals(other.songCount, songCount)) && + (identical(other.albumCount, albumCount) || + const DeepCollectionEquality() + .equals(other.albumCount, albumCount)) && + (identical(other.musicVideoCount, musicVideoCount) || + const DeepCollectionEquality() + .equals(other.musicVideoCount, musicVideoCount)) && + (identical(other.boxSetCount, boxSetCount) || + const DeepCollectionEquality() + .equals(other.boxSetCount, boxSetCount)) && + (identical(other.bookCount, bookCount) || + const DeepCollectionEquality() + .equals(other.bookCount, bookCount)) && + (identical(other.itemCount, itemCount) || + const DeepCollectionEquality() + .equals(other.itemCount, itemCount))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(movieCount) ^ + const DeepCollectionEquality().hash(seriesCount) ^ + const DeepCollectionEquality().hash(episodeCount) ^ + const DeepCollectionEquality().hash(artistCount) ^ + const DeepCollectionEquality().hash(programCount) ^ + const DeepCollectionEquality().hash(trailerCount) ^ + const DeepCollectionEquality().hash(songCount) ^ + const DeepCollectionEquality().hash(albumCount) ^ + const DeepCollectionEquality().hash(musicVideoCount) ^ + const DeepCollectionEquality().hash(boxSetCount) ^ + const DeepCollectionEquality().hash(bookCount) ^ + const DeepCollectionEquality().hash(itemCount) ^ + runtimeType.hashCode; +} + +extension $ItemCountsExtension on ItemCounts { + ItemCounts copyWith( + {int? movieCount, + int? seriesCount, + int? episodeCount, + int? artistCount, + int? programCount, + int? trailerCount, + int? songCount, + int? albumCount, + int? musicVideoCount, + int? boxSetCount, + int? bookCount, + int? itemCount}) { + return ItemCounts( + movieCount: movieCount ?? this.movieCount, + seriesCount: seriesCount ?? this.seriesCount, + episodeCount: episodeCount ?? this.episodeCount, + artistCount: artistCount ?? this.artistCount, + programCount: programCount ?? this.programCount, + trailerCount: trailerCount ?? this.trailerCount, + songCount: songCount ?? this.songCount, + albumCount: albumCount ?? this.albumCount, + musicVideoCount: musicVideoCount ?? this.musicVideoCount, + boxSetCount: boxSetCount ?? this.boxSetCount, + bookCount: bookCount ?? this.bookCount, + itemCount: itemCount ?? this.itemCount); + } + + ItemCounts copyWithWrapped( + {Wrapped? movieCount, + Wrapped? seriesCount, + Wrapped? episodeCount, + Wrapped? artistCount, + Wrapped? programCount, + Wrapped? trailerCount, + Wrapped? songCount, + Wrapped? albumCount, + Wrapped? musicVideoCount, + Wrapped? boxSetCount, + Wrapped? bookCount, + Wrapped? itemCount}) { + return ItemCounts( + movieCount: (movieCount != null ? movieCount.value : this.movieCount), + seriesCount: + (seriesCount != null ? seriesCount.value : this.seriesCount), + episodeCount: + (episodeCount != null ? episodeCount.value : this.episodeCount), + artistCount: + (artistCount != null ? artistCount.value : this.artistCount), + programCount: + (programCount != null ? programCount.value : this.programCount), + trailerCount: + (trailerCount != null ? trailerCount.value : this.trailerCount), + songCount: (songCount != null ? songCount.value : this.songCount), + albumCount: (albumCount != null ? albumCount.value : this.albumCount), + musicVideoCount: (musicVideoCount != null + ? musicVideoCount.value + : this.musicVideoCount), + boxSetCount: + (boxSetCount != null ? boxSetCount.value : this.boxSetCount), + bookCount: (bookCount != null ? bookCount.value : this.bookCount), + itemCount: (itemCount != null ? itemCount.value : this.itemCount)); + } +} + +@JsonSerializable(explicitToJson: true) +class Items { + const Items({ + this.movies, + this.episodes, + }); + + factory Items.fromJson(Map json) => _$ItemsFromJson(json); + + static const toJsonFactory = _$ItemsToJson; + Map toJson() => _$ItemsToJson(this); + + @JsonKey(name: 'movies', includeIfNull: false) + final int? movies; + @JsonKey(name: 'episodes', includeIfNull: false) + final int? episodes; + static const fromJsonFactory = _$ItemsFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is Items && + (identical(other.movies, movies) || + const DeepCollectionEquality().equals(other.movies, movies)) && + (identical(other.episodes, episodes) || + const DeepCollectionEquality() + .equals(other.episodes, episodes))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(movies) ^ + const DeepCollectionEquality().hash(episodes) ^ + runtimeType.hashCode; +} + +extension $ItemsExtension on Items { + Items copyWith({int? movies, int? episodes}) { + return Items( + movies: movies ?? this.movies, episodes: episodes ?? this.episodes); + } + + Items copyWithWrapped({Wrapped? movies, Wrapped? episodes}) { + return Items( + movies: (movies != null ? movies.value : this.movies), + episodes: (episodes != null ? episodes.value : this.episodes)); + } +} + +@JsonSerializable(explicitToJson: true) +class JoinGroupRequestDto { + const JoinGroupRequestDto({ + this.groupId, + }); + + factory JoinGroupRequestDto.fromJson(Map json) => + _$JoinGroupRequestDtoFromJson(json); + + static const toJsonFactory = _$JoinGroupRequestDtoToJson; + Map toJson() => _$JoinGroupRequestDtoToJson(this); + + @JsonKey(name: 'GroupId', includeIfNull: false) + final String? groupId; + static const fromJsonFactory = _$JoinGroupRequestDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is JoinGroupRequestDto && + (identical(other.groupId, groupId) || + const DeepCollectionEquality().equals(other.groupId, groupId))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(groupId) ^ runtimeType.hashCode; +} + +extension $JoinGroupRequestDtoExtension on JoinGroupRequestDto { + JoinGroupRequestDto copyWith({String? groupId}) { + return JoinGroupRequestDto(groupId: groupId ?? this.groupId); + } + + JoinGroupRequestDto copyWithWrapped({Wrapped? groupId}) { + return JoinGroupRequestDto( + groupId: (groupId != null ? groupId.value : this.groupId)); + } +} + +@JsonSerializable(explicitToJson: true) +class LibraryChangedMessage { + const LibraryChangedMessage({ + this.data, + this.messageId, + this.messageType, + }); + + factory LibraryChangedMessage.fromJson(Map json) => + _$LibraryChangedMessageFromJson(json); + + static const toJsonFactory = _$LibraryChangedMessageToJson; + Map toJson() => _$LibraryChangedMessageToJson(this); + + @JsonKey(name: 'Data', includeIfNull: false) + final LibraryUpdateInfo? data; + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.librarychanged); + + static const fromJsonFactory = _$LibraryChangedMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is LibraryChangedMessage && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data)) && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(data) ^ + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $LibraryChangedMessageExtension on LibraryChangedMessage { + LibraryChangedMessage copyWith( + {LibraryUpdateInfo? data, + String? messageId, + enums.SessionMessageType? messageType}) { + return LibraryChangedMessage( + data: data ?? this.data, + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + LibraryChangedMessage copyWithWrapped( + {Wrapped? data, + Wrapped? messageId, + Wrapped? messageType}) { + return LibraryChangedMessage( + data: (data != null ? data.value : this.data), + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class LibraryOptionInfoDto { + const LibraryOptionInfoDto({ + this.name, + this.defaultEnabled, + }); + + factory LibraryOptionInfoDto.fromJson(Map json) => + _$LibraryOptionInfoDtoFromJson(json); + + static const toJsonFactory = _$LibraryOptionInfoDtoToJson; + Map toJson() => _$LibraryOptionInfoDtoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'DefaultEnabled', includeIfNull: false) + final bool? defaultEnabled; + static const fromJsonFactory = _$LibraryOptionInfoDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is LibraryOptionInfoDto && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.defaultEnabled, defaultEnabled) || + const DeepCollectionEquality() + .equals(other.defaultEnabled, defaultEnabled))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(defaultEnabled) ^ + runtimeType.hashCode; +} + +extension $LibraryOptionInfoDtoExtension on LibraryOptionInfoDto { + LibraryOptionInfoDto copyWith({String? name, bool? defaultEnabled}) { + return LibraryOptionInfoDto( + name: name ?? this.name, + defaultEnabled: defaultEnabled ?? this.defaultEnabled); + } + + LibraryOptionInfoDto copyWithWrapped( + {Wrapped? name, Wrapped? defaultEnabled}) { + return LibraryOptionInfoDto( + name: (name != null ? name.value : this.name), + defaultEnabled: (defaultEnabled != null + ? defaultEnabled.value + : this.defaultEnabled)); + } +} + +@JsonSerializable(explicitToJson: true) +class LibraryOptions { + const LibraryOptions({ + this.enabled, + this.enablePhotos, + this.enableRealtimeMonitor, + this.enableLUFSScan, + this.enableChapterImageExtraction, + this.extractChapterImagesDuringLibraryScan, + this.enableTrickplayImageExtraction, + this.extractTrickplayImagesDuringLibraryScan, + this.pathInfos, + this.saveLocalMetadata, + this.enableInternetProviders, + this.enableAutomaticSeriesGrouping, + this.enableEmbeddedTitles, + this.enableEmbeddedExtrasTitles, + this.enableEmbeddedEpisodeInfos, + this.automaticRefreshIntervalDays, + this.preferredMetadataLanguage, + this.metadataCountryCode, + this.seasonZeroDisplayName, + this.metadataSavers, + this.disabledLocalMetadataReaders, + this.localMetadataReaderOrder, + this.disabledSubtitleFetchers, + this.subtitleFetcherOrder, + this.skipSubtitlesIfEmbeddedSubtitlesPresent, + this.skipSubtitlesIfAudioTrackMatches, + this.subtitleDownloadLanguages, + this.requirePerfectSubtitleMatch, + this.saveSubtitlesWithMedia, + this.saveLyricsWithMedia, + this.automaticallyAddToCollection, + this.allowEmbeddedSubtitles, + this.typeOptions, + }); + + factory LibraryOptions.fromJson(Map json) => + _$LibraryOptionsFromJson(json); + + static const toJsonFactory = _$LibraryOptionsToJson; + Map toJson() => _$LibraryOptionsToJson(this); + + @JsonKey(name: 'Enabled', includeIfNull: false) + final bool? enabled; + @JsonKey(name: 'EnablePhotos', includeIfNull: false) + final bool? enablePhotos; + @JsonKey(name: 'EnableRealtimeMonitor', includeIfNull: false) + final bool? enableRealtimeMonitor; + @JsonKey(name: 'EnableLUFSScan', includeIfNull: false) + final bool? enableLUFSScan; + @JsonKey(name: 'EnableChapterImageExtraction', includeIfNull: false) + final bool? enableChapterImageExtraction; + @JsonKey(name: 'ExtractChapterImagesDuringLibraryScan', includeIfNull: false) + final bool? extractChapterImagesDuringLibraryScan; + @JsonKey(name: 'EnableTrickplayImageExtraction', includeIfNull: false) + final bool? enableTrickplayImageExtraction; + @JsonKey( + name: 'ExtractTrickplayImagesDuringLibraryScan', includeIfNull: false) + final bool? extractTrickplayImagesDuringLibraryScan; + @JsonKey( + name: 'PathInfos', includeIfNull: false, defaultValue: []) + final List? pathInfos; + @JsonKey(name: 'SaveLocalMetadata', includeIfNull: false) + final bool? saveLocalMetadata; + @JsonKey(name: 'EnableInternetProviders', includeIfNull: false) + @deprecated + final bool? enableInternetProviders; + @JsonKey(name: 'EnableAutomaticSeriesGrouping', includeIfNull: false) + final bool? enableAutomaticSeriesGrouping; + @JsonKey(name: 'EnableEmbeddedTitles', includeIfNull: false) + final bool? enableEmbeddedTitles; + @JsonKey(name: 'EnableEmbeddedExtrasTitles', includeIfNull: false) + final bool? enableEmbeddedExtrasTitles; + @JsonKey(name: 'EnableEmbeddedEpisodeInfos', includeIfNull: false) + final bool? enableEmbeddedEpisodeInfos; + @JsonKey(name: 'AutomaticRefreshIntervalDays', includeIfNull: false) + final int? automaticRefreshIntervalDays; + @JsonKey(name: 'PreferredMetadataLanguage', includeIfNull: false) + final String? preferredMetadataLanguage; + @JsonKey(name: 'MetadataCountryCode', includeIfNull: false) + final String? metadataCountryCode; + @JsonKey(name: 'SeasonZeroDisplayName', includeIfNull: false) + final String? seasonZeroDisplayName; + @JsonKey( + name: 'MetadataSavers', includeIfNull: false, defaultValue: []) + final List? metadataSavers; + @JsonKey( + name: 'DisabledLocalMetadataReaders', + includeIfNull: false, + defaultValue: []) + final List? disabledLocalMetadataReaders; + @JsonKey( + name: 'LocalMetadataReaderOrder', + includeIfNull: false, + defaultValue: []) + final List? localMetadataReaderOrder; + @JsonKey( + name: 'DisabledSubtitleFetchers', + includeIfNull: false, + defaultValue: []) + final List? disabledSubtitleFetchers; + @JsonKey( + name: 'SubtitleFetcherOrder', + includeIfNull: false, + defaultValue: []) + final List? subtitleFetcherOrder; + @JsonKey( + name: 'SkipSubtitlesIfEmbeddedSubtitlesPresent', includeIfNull: false) + final bool? skipSubtitlesIfEmbeddedSubtitlesPresent; + @JsonKey(name: 'SkipSubtitlesIfAudioTrackMatches', includeIfNull: false) + final bool? skipSubtitlesIfAudioTrackMatches; + @JsonKey( + name: 'SubtitleDownloadLanguages', + includeIfNull: false, + defaultValue: []) + final List? subtitleDownloadLanguages; + @JsonKey(name: 'RequirePerfectSubtitleMatch', includeIfNull: false) + final bool? requirePerfectSubtitleMatch; + @JsonKey(name: 'SaveSubtitlesWithMedia', includeIfNull: false) + final bool? saveSubtitlesWithMedia; + @JsonKey( + name: 'SaveLyricsWithMedia', includeIfNull: false, defaultValue: false) + final bool? saveLyricsWithMedia; + @JsonKey(name: 'AutomaticallyAddToCollection', includeIfNull: false) + final bool? automaticallyAddToCollection; + @JsonKey( + name: 'AllowEmbeddedSubtitles', + includeIfNull: false, + toJson: embeddedSubtitleOptionsNullableToJson, + fromJson: embeddedSubtitleOptionsNullableFromJson, + ) + final enums.EmbeddedSubtitleOptions? allowEmbeddedSubtitles; + @JsonKey( + name: 'TypeOptions', includeIfNull: false, defaultValue: []) + final List? typeOptions; + static const fromJsonFactory = _$LibraryOptionsFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is LibraryOptions && + (identical(other.enabled, enabled) || + const DeepCollectionEquality() + .equals(other.enabled, enabled)) && + (identical(other.enablePhotos, enablePhotos) || + const DeepCollectionEquality() + .equals(other.enablePhotos, enablePhotos)) && + (identical(other.enableRealtimeMonitor, enableRealtimeMonitor) || + const DeepCollectionEquality().equals( + other.enableRealtimeMonitor, enableRealtimeMonitor)) && + (identical(other.enableLUFSScan, enableLUFSScan) || + const DeepCollectionEquality() + .equals(other.enableLUFSScan, enableLUFSScan)) && + (identical(other.enableChapterImageExtraction, enableChapterImageExtraction) || + const DeepCollectionEquality().equals( + other.enableChapterImageExtraction, + enableChapterImageExtraction)) && + (identical(other.extractChapterImagesDuringLibraryScan, extractChapterImagesDuringLibraryScan) || + const DeepCollectionEquality().equals( + other.extractChapterImagesDuringLibraryScan, + extractChapterImagesDuringLibraryScan)) && + (identical(other.enableTrickplayImageExtraction, enableTrickplayImageExtraction) || + const DeepCollectionEquality().equals( + other.enableTrickplayImageExtraction, + enableTrickplayImageExtraction)) && + (identical(other.extractTrickplayImagesDuringLibraryScan, extractTrickplayImagesDuringLibraryScan) || + const DeepCollectionEquality().equals( + other.extractTrickplayImagesDuringLibraryScan, + extractTrickplayImagesDuringLibraryScan)) && + (identical(other.pathInfos, pathInfos) || + const DeepCollectionEquality() + .equals(other.pathInfos, pathInfos)) && + (identical(other.saveLocalMetadata, saveLocalMetadata) || + const DeepCollectionEquality() + .equals(other.saveLocalMetadata, saveLocalMetadata)) && + (identical(other.enableInternetProviders, enableInternetProviders) || + const DeepCollectionEquality().equals( + other.enableInternetProviders, enableInternetProviders)) && + (identical(other.enableAutomaticSeriesGrouping, enableAutomaticSeriesGrouping) || + const DeepCollectionEquality() + .equals(other.enableAutomaticSeriesGrouping, enableAutomaticSeriesGrouping)) && + (identical(other.enableEmbeddedTitles, enableEmbeddedTitles) || const DeepCollectionEquality().equals(other.enableEmbeddedTitles, enableEmbeddedTitles)) && + (identical(other.enableEmbeddedExtrasTitles, enableEmbeddedExtrasTitles) || const DeepCollectionEquality().equals(other.enableEmbeddedExtrasTitles, enableEmbeddedExtrasTitles)) && + (identical(other.enableEmbeddedEpisodeInfos, enableEmbeddedEpisodeInfos) || const DeepCollectionEquality().equals(other.enableEmbeddedEpisodeInfos, enableEmbeddedEpisodeInfos)) && + (identical(other.automaticRefreshIntervalDays, automaticRefreshIntervalDays) || const DeepCollectionEquality().equals(other.automaticRefreshIntervalDays, automaticRefreshIntervalDays)) && + (identical(other.preferredMetadataLanguage, preferredMetadataLanguage) || const DeepCollectionEquality().equals(other.preferredMetadataLanguage, preferredMetadataLanguage)) && + (identical(other.metadataCountryCode, metadataCountryCode) || const DeepCollectionEquality().equals(other.metadataCountryCode, metadataCountryCode)) && + (identical(other.seasonZeroDisplayName, seasonZeroDisplayName) || const DeepCollectionEquality().equals(other.seasonZeroDisplayName, seasonZeroDisplayName)) && + (identical(other.metadataSavers, metadataSavers) || const DeepCollectionEquality().equals(other.metadataSavers, metadataSavers)) && + (identical(other.disabledLocalMetadataReaders, disabledLocalMetadataReaders) || const DeepCollectionEquality().equals(other.disabledLocalMetadataReaders, disabledLocalMetadataReaders)) && + (identical(other.localMetadataReaderOrder, localMetadataReaderOrder) || const DeepCollectionEquality().equals(other.localMetadataReaderOrder, localMetadataReaderOrder)) && + (identical(other.disabledSubtitleFetchers, disabledSubtitleFetchers) || const DeepCollectionEquality().equals(other.disabledSubtitleFetchers, disabledSubtitleFetchers)) && + (identical(other.subtitleFetcherOrder, subtitleFetcherOrder) || const DeepCollectionEquality().equals(other.subtitleFetcherOrder, subtitleFetcherOrder)) && + (identical(other.skipSubtitlesIfEmbeddedSubtitlesPresent, skipSubtitlesIfEmbeddedSubtitlesPresent) || const DeepCollectionEquality().equals(other.skipSubtitlesIfEmbeddedSubtitlesPresent, skipSubtitlesIfEmbeddedSubtitlesPresent)) && + (identical(other.skipSubtitlesIfAudioTrackMatches, skipSubtitlesIfAudioTrackMatches) || const DeepCollectionEquality().equals(other.skipSubtitlesIfAudioTrackMatches, skipSubtitlesIfAudioTrackMatches)) && + (identical(other.subtitleDownloadLanguages, subtitleDownloadLanguages) || const DeepCollectionEquality().equals(other.subtitleDownloadLanguages, subtitleDownloadLanguages)) && + (identical(other.requirePerfectSubtitleMatch, requirePerfectSubtitleMatch) || const DeepCollectionEquality().equals(other.requirePerfectSubtitleMatch, requirePerfectSubtitleMatch)) && + (identical(other.saveSubtitlesWithMedia, saveSubtitlesWithMedia) || const DeepCollectionEquality().equals(other.saveSubtitlesWithMedia, saveSubtitlesWithMedia)) && + (identical(other.saveLyricsWithMedia, saveLyricsWithMedia) || const DeepCollectionEquality().equals(other.saveLyricsWithMedia, saveLyricsWithMedia)) && + (identical(other.automaticallyAddToCollection, automaticallyAddToCollection) || const DeepCollectionEquality().equals(other.automaticallyAddToCollection, automaticallyAddToCollection)) && + (identical(other.allowEmbeddedSubtitles, allowEmbeddedSubtitles) || const DeepCollectionEquality().equals(other.allowEmbeddedSubtitles, allowEmbeddedSubtitles)) && + (identical(other.typeOptions, typeOptions) || const DeepCollectionEquality().equals(other.typeOptions, typeOptions))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(enabled) ^ + const DeepCollectionEquality().hash(enablePhotos) ^ + const DeepCollectionEquality().hash(enableRealtimeMonitor) ^ + const DeepCollectionEquality().hash(enableLUFSScan) ^ + const DeepCollectionEquality().hash(enableChapterImageExtraction) ^ + const DeepCollectionEquality() + .hash(extractChapterImagesDuringLibraryScan) ^ + const DeepCollectionEquality().hash(enableTrickplayImageExtraction) ^ + const DeepCollectionEquality() + .hash(extractTrickplayImagesDuringLibraryScan) ^ + const DeepCollectionEquality().hash(pathInfos) ^ + const DeepCollectionEquality().hash(saveLocalMetadata) ^ + const DeepCollectionEquality().hash(enableInternetProviders) ^ + const DeepCollectionEquality().hash(enableAutomaticSeriesGrouping) ^ + const DeepCollectionEquality().hash(enableEmbeddedTitles) ^ + const DeepCollectionEquality().hash(enableEmbeddedExtrasTitles) ^ + const DeepCollectionEquality().hash(enableEmbeddedEpisodeInfos) ^ + const DeepCollectionEquality().hash(automaticRefreshIntervalDays) ^ + const DeepCollectionEquality().hash(preferredMetadataLanguage) ^ + const DeepCollectionEquality().hash(metadataCountryCode) ^ + const DeepCollectionEquality().hash(seasonZeroDisplayName) ^ + const DeepCollectionEquality().hash(metadataSavers) ^ + const DeepCollectionEquality().hash(disabledLocalMetadataReaders) ^ + const DeepCollectionEquality().hash(localMetadataReaderOrder) ^ + const DeepCollectionEquality().hash(disabledSubtitleFetchers) ^ + const DeepCollectionEquality().hash(subtitleFetcherOrder) ^ + const DeepCollectionEquality() + .hash(skipSubtitlesIfEmbeddedSubtitlesPresent) ^ + const DeepCollectionEquality().hash(skipSubtitlesIfAudioTrackMatches) ^ + const DeepCollectionEquality().hash(subtitleDownloadLanguages) ^ + const DeepCollectionEquality().hash(requirePerfectSubtitleMatch) ^ + const DeepCollectionEquality().hash(saveSubtitlesWithMedia) ^ + const DeepCollectionEquality().hash(saveLyricsWithMedia) ^ + const DeepCollectionEquality().hash(automaticallyAddToCollection) ^ + const DeepCollectionEquality().hash(allowEmbeddedSubtitles) ^ + const DeepCollectionEquality().hash(typeOptions) ^ + runtimeType.hashCode; +} + +extension $LibraryOptionsExtension on LibraryOptions { + LibraryOptions copyWith( + {bool? enabled, + bool? enablePhotos, + bool? enableRealtimeMonitor, + bool? enableLUFSScan, + bool? enableChapterImageExtraction, + bool? extractChapterImagesDuringLibraryScan, + bool? enableTrickplayImageExtraction, + bool? extractTrickplayImagesDuringLibraryScan, + List? pathInfos, + bool? saveLocalMetadata, + bool? enableInternetProviders, + bool? enableAutomaticSeriesGrouping, + bool? enableEmbeddedTitles, + bool? enableEmbeddedExtrasTitles, + bool? enableEmbeddedEpisodeInfos, + int? automaticRefreshIntervalDays, + String? preferredMetadataLanguage, + String? metadataCountryCode, + String? seasonZeroDisplayName, + List? metadataSavers, + List? disabledLocalMetadataReaders, + List? localMetadataReaderOrder, + List? disabledSubtitleFetchers, + List? subtitleFetcherOrder, + bool? skipSubtitlesIfEmbeddedSubtitlesPresent, + bool? skipSubtitlesIfAudioTrackMatches, + List? subtitleDownloadLanguages, + bool? requirePerfectSubtitleMatch, + bool? saveSubtitlesWithMedia, + bool? saveLyricsWithMedia, + bool? automaticallyAddToCollection, + enums.EmbeddedSubtitleOptions? allowEmbeddedSubtitles, + List? typeOptions}) { + return LibraryOptions( + enabled: enabled ?? this.enabled, + enablePhotos: enablePhotos ?? this.enablePhotos, + enableRealtimeMonitor: + enableRealtimeMonitor ?? this.enableRealtimeMonitor, + enableLUFSScan: enableLUFSScan ?? this.enableLUFSScan, + enableChapterImageExtraction: + enableChapterImageExtraction ?? this.enableChapterImageExtraction, + extractChapterImagesDuringLibraryScan: + extractChapterImagesDuringLibraryScan ?? + this.extractChapterImagesDuringLibraryScan, + enableTrickplayImageExtraction: enableTrickplayImageExtraction ?? + this.enableTrickplayImageExtraction, + extractTrickplayImagesDuringLibraryScan: + extractTrickplayImagesDuringLibraryScan ?? + this.extractTrickplayImagesDuringLibraryScan, + pathInfos: pathInfos ?? this.pathInfos, + saveLocalMetadata: saveLocalMetadata ?? this.saveLocalMetadata, + enableInternetProviders: + enableInternetProviders ?? this.enableInternetProviders, + enableAutomaticSeriesGrouping: + enableAutomaticSeriesGrouping ?? this.enableAutomaticSeriesGrouping, + enableEmbeddedTitles: enableEmbeddedTitles ?? this.enableEmbeddedTitles, + enableEmbeddedExtrasTitles: + enableEmbeddedExtrasTitles ?? this.enableEmbeddedExtrasTitles, + enableEmbeddedEpisodeInfos: + enableEmbeddedEpisodeInfos ?? this.enableEmbeddedEpisodeInfos, + automaticRefreshIntervalDays: + automaticRefreshIntervalDays ?? this.automaticRefreshIntervalDays, + preferredMetadataLanguage: + preferredMetadataLanguage ?? this.preferredMetadataLanguage, + metadataCountryCode: metadataCountryCode ?? this.metadataCountryCode, + seasonZeroDisplayName: + seasonZeroDisplayName ?? this.seasonZeroDisplayName, + metadataSavers: metadataSavers ?? this.metadataSavers, + disabledLocalMetadataReaders: + disabledLocalMetadataReaders ?? this.disabledLocalMetadataReaders, + localMetadataReaderOrder: + localMetadataReaderOrder ?? this.localMetadataReaderOrder, + disabledSubtitleFetchers: + disabledSubtitleFetchers ?? this.disabledSubtitleFetchers, + subtitleFetcherOrder: subtitleFetcherOrder ?? this.subtitleFetcherOrder, + skipSubtitlesIfEmbeddedSubtitlesPresent: + skipSubtitlesIfEmbeddedSubtitlesPresent ?? + this.skipSubtitlesIfEmbeddedSubtitlesPresent, + skipSubtitlesIfAudioTrackMatches: skipSubtitlesIfAudioTrackMatches ?? + this.skipSubtitlesIfAudioTrackMatches, + subtitleDownloadLanguages: + subtitleDownloadLanguages ?? this.subtitleDownloadLanguages, + requirePerfectSubtitleMatch: + requirePerfectSubtitleMatch ?? this.requirePerfectSubtitleMatch, + saveSubtitlesWithMedia: + saveSubtitlesWithMedia ?? this.saveSubtitlesWithMedia, + saveLyricsWithMedia: saveLyricsWithMedia ?? this.saveLyricsWithMedia, + automaticallyAddToCollection: + automaticallyAddToCollection ?? this.automaticallyAddToCollection, + allowEmbeddedSubtitles: + allowEmbeddedSubtitles ?? this.allowEmbeddedSubtitles, + typeOptions: typeOptions ?? this.typeOptions); + } + + LibraryOptions copyWithWrapped( + {Wrapped? enabled, + Wrapped? enablePhotos, + Wrapped? enableRealtimeMonitor, + Wrapped? enableLUFSScan, + Wrapped? enableChapterImageExtraction, + Wrapped? extractChapterImagesDuringLibraryScan, + Wrapped? enableTrickplayImageExtraction, + Wrapped? extractTrickplayImagesDuringLibraryScan, + Wrapped?>? pathInfos, + Wrapped? saveLocalMetadata, + Wrapped? enableInternetProviders, + Wrapped? enableAutomaticSeriesGrouping, + Wrapped? enableEmbeddedTitles, + Wrapped? enableEmbeddedExtrasTitles, + Wrapped? enableEmbeddedEpisodeInfos, + Wrapped? automaticRefreshIntervalDays, + Wrapped? preferredMetadataLanguage, + Wrapped? metadataCountryCode, + Wrapped? seasonZeroDisplayName, + Wrapped?>? metadataSavers, + Wrapped?>? disabledLocalMetadataReaders, + Wrapped?>? localMetadataReaderOrder, + Wrapped?>? disabledSubtitleFetchers, + Wrapped?>? subtitleFetcherOrder, + Wrapped? skipSubtitlesIfEmbeddedSubtitlesPresent, + Wrapped? skipSubtitlesIfAudioTrackMatches, + Wrapped?>? subtitleDownloadLanguages, + Wrapped? requirePerfectSubtitleMatch, + Wrapped? saveSubtitlesWithMedia, + Wrapped? saveLyricsWithMedia, + Wrapped? automaticallyAddToCollection, + Wrapped? allowEmbeddedSubtitles, + Wrapped?>? typeOptions}) { + return LibraryOptions( + enabled: (enabled != null ? enabled.value : this.enabled), + enablePhotos: + (enablePhotos != null ? enablePhotos.value : this.enablePhotos), + enableRealtimeMonitor: (enableRealtimeMonitor != null + ? enableRealtimeMonitor.value + : this.enableRealtimeMonitor), + enableLUFSScan: (enableLUFSScan != null + ? enableLUFSScan.value + : this.enableLUFSScan), + enableChapterImageExtraction: (enableChapterImageExtraction != null + ? enableChapterImageExtraction.value + : this.enableChapterImageExtraction), + extractChapterImagesDuringLibraryScan: (extractChapterImagesDuringLibraryScan != null + ? extractChapterImagesDuringLibraryScan.value + : this.extractChapterImagesDuringLibraryScan), + enableTrickplayImageExtraction: (enableTrickplayImageExtraction != null + ? enableTrickplayImageExtraction.value + : this.enableTrickplayImageExtraction), + extractTrickplayImagesDuringLibraryScan: (extractTrickplayImagesDuringLibraryScan != null + ? extractTrickplayImagesDuringLibraryScan.value + : this.extractTrickplayImagesDuringLibraryScan), + pathInfos: (pathInfos != null ? pathInfos.value : this.pathInfos), + saveLocalMetadata: (saveLocalMetadata != null + ? saveLocalMetadata.value + : this.saveLocalMetadata), + enableInternetProviders: (enableInternetProviders != null + ? enableInternetProviders.value + : this.enableInternetProviders), + enableAutomaticSeriesGrouping: (enableAutomaticSeriesGrouping != null + ? enableAutomaticSeriesGrouping.value + : this.enableAutomaticSeriesGrouping), + enableEmbeddedTitles: (enableEmbeddedTitles != null + ? enableEmbeddedTitles.value + : this.enableEmbeddedTitles), + enableEmbeddedExtrasTitles: (enableEmbeddedExtrasTitles != null + ? enableEmbeddedExtrasTitles.value + : this.enableEmbeddedExtrasTitles), + enableEmbeddedEpisodeInfos: (enableEmbeddedEpisodeInfos != null + ? enableEmbeddedEpisodeInfos.value + : this.enableEmbeddedEpisodeInfos), + automaticRefreshIntervalDays: (automaticRefreshIntervalDays != null + ? automaticRefreshIntervalDays.value + : this.automaticRefreshIntervalDays), + preferredMetadataLanguage: (preferredMetadataLanguage != null + ? preferredMetadataLanguage.value + : this.preferredMetadataLanguage), + metadataCountryCode: (metadataCountryCode != null + ? metadataCountryCode.value + : this.metadataCountryCode), + seasonZeroDisplayName: (seasonZeroDisplayName != null + ? seasonZeroDisplayName.value + : this.seasonZeroDisplayName), + metadataSavers: (metadataSavers != null + ? metadataSavers.value + : this.metadataSavers), + disabledLocalMetadataReaders: (disabledLocalMetadataReaders != null + ? disabledLocalMetadataReaders.value + : this.disabledLocalMetadataReaders), + localMetadataReaderOrder: (localMetadataReaderOrder != null + ? localMetadataReaderOrder.value + : this.localMetadataReaderOrder), + disabledSubtitleFetchers: (disabledSubtitleFetchers != null + ? disabledSubtitleFetchers.value + : this.disabledSubtitleFetchers), + subtitleFetcherOrder: (subtitleFetcherOrder != null + ? subtitleFetcherOrder.value + : this.subtitleFetcherOrder), + skipSubtitlesIfEmbeddedSubtitlesPresent: + (skipSubtitlesIfEmbeddedSubtitlesPresent != null + ? skipSubtitlesIfEmbeddedSubtitlesPresent.value + : this.skipSubtitlesIfEmbeddedSubtitlesPresent), + skipSubtitlesIfAudioTrackMatches: (skipSubtitlesIfAudioTrackMatches != null ? skipSubtitlesIfAudioTrackMatches.value : this.skipSubtitlesIfAudioTrackMatches), + subtitleDownloadLanguages: (subtitleDownloadLanguages != null ? subtitleDownloadLanguages.value : this.subtitleDownloadLanguages), + requirePerfectSubtitleMatch: (requirePerfectSubtitleMatch != null ? requirePerfectSubtitleMatch.value : this.requirePerfectSubtitleMatch), + saveSubtitlesWithMedia: (saveSubtitlesWithMedia != null ? saveSubtitlesWithMedia.value : this.saveSubtitlesWithMedia), + saveLyricsWithMedia: (saveLyricsWithMedia != null ? saveLyricsWithMedia.value : this.saveLyricsWithMedia), + automaticallyAddToCollection: (automaticallyAddToCollection != null ? automaticallyAddToCollection.value : this.automaticallyAddToCollection), + allowEmbeddedSubtitles: (allowEmbeddedSubtitles != null ? allowEmbeddedSubtitles.value : this.allowEmbeddedSubtitles), + typeOptions: (typeOptions != null ? typeOptions.value : this.typeOptions)); + } +} + +@JsonSerializable(explicitToJson: true) +class LibraryOptionsResultDto { + const LibraryOptionsResultDto({ + this.metadataSavers, + this.metadataReaders, + this.subtitleFetchers, + this.typeOptions, + }); + + factory LibraryOptionsResultDto.fromJson(Map json) => + _$LibraryOptionsResultDtoFromJson(json); + + static const toJsonFactory = _$LibraryOptionsResultDtoToJson; + Map toJson() => _$LibraryOptionsResultDtoToJson(this); + + @JsonKey( + name: 'MetadataSavers', + includeIfNull: false, + defaultValue: []) + final List? metadataSavers; + @JsonKey( + name: 'MetadataReaders', + includeIfNull: false, + defaultValue: []) + final List? metadataReaders; + @JsonKey( + name: 'SubtitleFetchers', + includeIfNull: false, + defaultValue: []) + final List? subtitleFetchers; + @JsonKey( + name: 'TypeOptions', + includeIfNull: false, + defaultValue: []) + final List? typeOptions; + static const fromJsonFactory = _$LibraryOptionsResultDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is LibraryOptionsResultDto && + (identical(other.metadataSavers, metadataSavers) || + const DeepCollectionEquality() + .equals(other.metadataSavers, metadataSavers)) && + (identical(other.metadataReaders, metadataReaders) || + const DeepCollectionEquality() + .equals(other.metadataReaders, metadataReaders)) && + (identical(other.subtitleFetchers, subtitleFetchers) || + const DeepCollectionEquality() + .equals(other.subtitleFetchers, subtitleFetchers)) && + (identical(other.typeOptions, typeOptions) || + const DeepCollectionEquality() + .equals(other.typeOptions, typeOptions))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(metadataSavers) ^ + const DeepCollectionEquality().hash(metadataReaders) ^ + const DeepCollectionEquality().hash(subtitleFetchers) ^ + const DeepCollectionEquality().hash(typeOptions) ^ + runtimeType.hashCode; +} + +extension $LibraryOptionsResultDtoExtension on LibraryOptionsResultDto { + LibraryOptionsResultDto copyWith( + {List? metadataSavers, + List? metadataReaders, + List? subtitleFetchers, + List? typeOptions}) { + return LibraryOptionsResultDto( + metadataSavers: metadataSavers ?? this.metadataSavers, + metadataReaders: metadataReaders ?? this.metadataReaders, + subtitleFetchers: subtitleFetchers ?? this.subtitleFetchers, + typeOptions: typeOptions ?? this.typeOptions); + } + + LibraryOptionsResultDto copyWithWrapped( + {Wrapped?>? metadataSavers, + Wrapped?>? metadataReaders, + Wrapped?>? subtitleFetchers, + Wrapped?>? typeOptions}) { + return LibraryOptionsResultDto( + metadataSavers: (metadataSavers != null + ? metadataSavers.value + : this.metadataSavers), + metadataReaders: (metadataReaders != null + ? metadataReaders.value + : this.metadataReaders), + subtitleFetchers: (subtitleFetchers != null + ? subtitleFetchers.value + : this.subtitleFetchers), + typeOptions: + (typeOptions != null ? typeOptions.value : this.typeOptions)); + } +} + +@JsonSerializable(explicitToJson: true) +class LibraryTypeOptionsDto { + const LibraryTypeOptionsDto({ + this.type, + this.metadataFetchers, + this.imageFetchers, + this.supportedImageTypes, + this.defaultImageOptions, + }); + + factory LibraryTypeOptionsDto.fromJson(Map json) => + _$LibraryTypeOptionsDtoFromJson(json); + + static const toJsonFactory = _$LibraryTypeOptionsDtoToJson; + Map toJson() => _$LibraryTypeOptionsDtoToJson(this); + + @JsonKey(name: 'Type', includeIfNull: false) + final String? type; + @JsonKey( + name: 'MetadataFetchers', + includeIfNull: false, + defaultValue: []) + final List? metadataFetchers; + @JsonKey( + name: 'ImageFetchers', + includeIfNull: false, + defaultValue: []) + final List? imageFetchers; + @JsonKey( + name: 'SupportedImageTypes', + includeIfNull: false, + toJson: imageTypeListToJson, + fromJson: imageTypeListFromJson, + ) + final List? supportedImageTypes; + @JsonKey( + name: 'DefaultImageOptions', + includeIfNull: false, + defaultValue: []) + final List? defaultImageOptions; + static const fromJsonFactory = _$LibraryTypeOptionsDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is LibraryTypeOptionsDto && + (identical(other.type, type) || + const DeepCollectionEquality().equals(other.type, type)) && + (identical(other.metadataFetchers, metadataFetchers) || + const DeepCollectionEquality() + .equals(other.metadataFetchers, metadataFetchers)) && + (identical(other.imageFetchers, imageFetchers) || + const DeepCollectionEquality() + .equals(other.imageFetchers, imageFetchers)) && + (identical(other.supportedImageTypes, supportedImageTypes) || + const DeepCollectionEquality() + .equals(other.supportedImageTypes, supportedImageTypes)) && + (identical(other.defaultImageOptions, defaultImageOptions) || + const DeepCollectionEquality() + .equals(other.defaultImageOptions, defaultImageOptions))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(type) ^ + const DeepCollectionEquality().hash(metadataFetchers) ^ + const DeepCollectionEquality().hash(imageFetchers) ^ + const DeepCollectionEquality().hash(supportedImageTypes) ^ + const DeepCollectionEquality().hash(defaultImageOptions) ^ + runtimeType.hashCode; +} + +extension $LibraryTypeOptionsDtoExtension on LibraryTypeOptionsDto { + LibraryTypeOptionsDto copyWith( + {String? type, + List? metadataFetchers, + List? imageFetchers, + List? supportedImageTypes, + List? defaultImageOptions}) { + return LibraryTypeOptionsDto( + type: type ?? this.type, + metadataFetchers: metadataFetchers ?? this.metadataFetchers, + imageFetchers: imageFetchers ?? this.imageFetchers, + supportedImageTypes: supportedImageTypes ?? this.supportedImageTypes, + defaultImageOptions: defaultImageOptions ?? this.defaultImageOptions); + } + + LibraryTypeOptionsDto copyWithWrapped( + {Wrapped? type, + Wrapped?>? metadataFetchers, + Wrapped?>? imageFetchers, + Wrapped?>? supportedImageTypes, + Wrapped?>? defaultImageOptions}) { + return LibraryTypeOptionsDto( + type: (type != null ? type.value : this.type), + metadataFetchers: (metadataFetchers != null + ? metadataFetchers.value + : this.metadataFetchers), + imageFetchers: + (imageFetchers != null ? imageFetchers.value : this.imageFetchers), + supportedImageTypes: (supportedImageTypes != null + ? supportedImageTypes.value + : this.supportedImageTypes), + defaultImageOptions: (defaultImageOptions != null + ? defaultImageOptions.value + : this.defaultImageOptions)); + } +} + +@JsonSerializable(explicitToJson: true) +class LibraryUpdateInfo { + const LibraryUpdateInfo({ + this.foldersAddedTo, + this.foldersRemovedFrom, + this.itemsAdded, + this.itemsRemoved, + this.itemsUpdated, + this.collectionFolders, + this.isEmpty, + }); + + factory LibraryUpdateInfo.fromJson(Map json) => + _$LibraryUpdateInfoFromJson(json); + + static const toJsonFactory = _$LibraryUpdateInfoToJson; + Map toJson() => _$LibraryUpdateInfoToJson(this); + + @JsonKey( + name: 'FoldersAddedTo', includeIfNull: false, defaultValue: []) + final List? foldersAddedTo; + @JsonKey( + name: 'FoldersRemovedFrom', + includeIfNull: false, + defaultValue: []) + final List? foldersRemovedFrom; + @JsonKey(name: 'ItemsAdded', includeIfNull: false, defaultValue: []) + final List? itemsAdded; + @JsonKey(name: 'ItemsRemoved', includeIfNull: false, defaultValue: []) + final List? itemsRemoved; + @JsonKey(name: 'ItemsUpdated', includeIfNull: false, defaultValue: []) + final List? itemsUpdated; + @JsonKey( + name: 'CollectionFolders', includeIfNull: false, defaultValue: []) + final List? collectionFolders; + @JsonKey(name: 'IsEmpty', includeIfNull: false) + final bool? isEmpty; + static const fromJsonFactory = _$LibraryUpdateInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is LibraryUpdateInfo && + (identical(other.foldersAddedTo, foldersAddedTo) || + const DeepCollectionEquality() + .equals(other.foldersAddedTo, foldersAddedTo)) && + (identical(other.foldersRemovedFrom, foldersRemovedFrom) || + const DeepCollectionEquality() + .equals(other.foldersRemovedFrom, foldersRemovedFrom)) && + (identical(other.itemsAdded, itemsAdded) || + const DeepCollectionEquality() + .equals(other.itemsAdded, itemsAdded)) && + (identical(other.itemsRemoved, itemsRemoved) || + const DeepCollectionEquality() + .equals(other.itemsRemoved, itemsRemoved)) && + (identical(other.itemsUpdated, itemsUpdated) || + const DeepCollectionEquality() + .equals(other.itemsUpdated, itemsUpdated)) && + (identical(other.collectionFolders, collectionFolders) || + const DeepCollectionEquality() + .equals(other.collectionFolders, collectionFolders)) && + (identical(other.isEmpty, isEmpty) || + const DeepCollectionEquality().equals(other.isEmpty, isEmpty))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(foldersAddedTo) ^ + const DeepCollectionEquality().hash(foldersRemovedFrom) ^ + const DeepCollectionEquality().hash(itemsAdded) ^ + const DeepCollectionEquality().hash(itemsRemoved) ^ + const DeepCollectionEquality().hash(itemsUpdated) ^ + const DeepCollectionEquality().hash(collectionFolders) ^ + const DeepCollectionEquality().hash(isEmpty) ^ + runtimeType.hashCode; +} + +extension $LibraryUpdateInfoExtension on LibraryUpdateInfo { + LibraryUpdateInfo copyWith( + {List? foldersAddedTo, + List? foldersRemovedFrom, + List? itemsAdded, + List? itemsRemoved, + List? itemsUpdated, + List? collectionFolders, + bool? isEmpty}) { + return LibraryUpdateInfo( + foldersAddedTo: foldersAddedTo ?? this.foldersAddedTo, + foldersRemovedFrom: foldersRemovedFrom ?? this.foldersRemovedFrom, + itemsAdded: itemsAdded ?? this.itemsAdded, + itemsRemoved: itemsRemoved ?? this.itemsRemoved, + itemsUpdated: itemsUpdated ?? this.itemsUpdated, + collectionFolders: collectionFolders ?? this.collectionFolders, + isEmpty: isEmpty ?? this.isEmpty); + } + + LibraryUpdateInfo copyWithWrapped( + {Wrapped?>? foldersAddedTo, + Wrapped?>? foldersRemovedFrom, + Wrapped?>? itemsAdded, + Wrapped?>? itemsRemoved, + Wrapped?>? itemsUpdated, + Wrapped?>? collectionFolders, + Wrapped? isEmpty}) { + return LibraryUpdateInfo( + foldersAddedTo: (foldersAddedTo != null + ? foldersAddedTo.value + : this.foldersAddedTo), + foldersRemovedFrom: (foldersRemovedFrom != null + ? foldersRemovedFrom.value + : this.foldersRemovedFrom), + itemsAdded: (itemsAdded != null ? itemsAdded.value : this.itemsAdded), + itemsRemoved: + (itemsRemoved != null ? itemsRemoved.value : this.itemsRemoved), + itemsUpdated: + (itemsUpdated != null ? itemsUpdated.value : this.itemsUpdated), + collectionFolders: (collectionFolders != null + ? collectionFolders.value + : this.collectionFolders), + isEmpty: (isEmpty != null ? isEmpty.value : this.isEmpty)); + } +} + +@JsonSerializable(explicitToJson: true) +class ListingsProviderInfo { + const ListingsProviderInfo({ + this.id, + this.type, + this.username, + this.password, + this.listingsId, + this.zipCode, + this.country, + this.path, + this.enabledTuners, + this.enableAllTuners, + this.newsCategories, + this.sportsCategories, + this.kidsCategories, + this.movieCategories, + this.channelMappings, + this.moviePrefix, + this.preferredLanguage, + this.userAgent, + }); + + factory ListingsProviderInfo.fromJson(Map json) => + _$ListingsProviderInfoFromJson(json); + + static const toJsonFactory = _$ListingsProviderInfoToJson; + Map toJson() => _$ListingsProviderInfoToJson(this); + + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'Type', includeIfNull: false) + final String? type; + @JsonKey(name: 'Username', includeIfNull: false) + final String? username; + @JsonKey(name: 'Password', includeIfNull: false) + final String? password; + @JsonKey(name: 'ListingsId', includeIfNull: false) + final String? listingsId; + @JsonKey(name: 'ZipCode', includeIfNull: false) + final String? zipCode; + @JsonKey(name: 'Country', includeIfNull: false) + final String? country; + @JsonKey(name: 'Path', includeIfNull: false) + final String? path; + @JsonKey( + name: 'EnabledTuners', includeIfNull: false, defaultValue: []) + final List? enabledTuners; + @JsonKey(name: 'EnableAllTuners', includeIfNull: false) + final bool? enableAllTuners; + @JsonKey( + name: 'NewsCategories', includeIfNull: false, defaultValue: []) + final List? newsCategories; + @JsonKey( + name: 'SportsCategories', includeIfNull: false, defaultValue: []) + final List? sportsCategories; + @JsonKey( + name: 'KidsCategories', includeIfNull: false, defaultValue: []) + final List? kidsCategories; + @JsonKey( + name: 'MovieCategories', includeIfNull: false, defaultValue: []) + final List? movieCategories; + @JsonKey( + name: 'ChannelMappings', + includeIfNull: false, + defaultValue: []) + final List? channelMappings; + @JsonKey(name: 'MoviePrefix', includeIfNull: false) + final String? moviePrefix; + @JsonKey(name: 'PreferredLanguage', includeIfNull: false) + final String? preferredLanguage; + @JsonKey(name: 'UserAgent', includeIfNull: false) + final String? userAgent; + static const fromJsonFactory = _$ListingsProviderInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ListingsProviderInfo && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.type, type) || + const DeepCollectionEquality().equals(other.type, type)) && + (identical(other.username, username) || + const DeepCollectionEquality() + .equals(other.username, username)) && + (identical(other.password, password) || + const DeepCollectionEquality() + .equals(other.password, password)) && + (identical(other.listingsId, listingsId) || + const DeepCollectionEquality() + .equals(other.listingsId, listingsId)) && + (identical(other.zipCode, zipCode) || + const DeepCollectionEquality() + .equals(other.zipCode, zipCode)) && + (identical(other.country, country) || + const DeepCollectionEquality() + .equals(other.country, country)) && + (identical(other.path, path) || + const DeepCollectionEquality().equals(other.path, path)) && + (identical(other.enabledTuners, enabledTuners) || + const DeepCollectionEquality() + .equals(other.enabledTuners, enabledTuners)) && + (identical(other.enableAllTuners, enableAllTuners) || + const DeepCollectionEquality() + .equals(other.enableAllTuners, enableAllTuners)) && + (identical(other.newsCategories, newsCategories) || + const DeepCollectionEquality() + .equals(other.newsCategories, newsCategories)) && + (identical(other.sportsCategories, sportsCategories) || + const DeepCollectionEquality() + .equals(other.sportsCategories, sportsCategories)) && + (identical(other.kidsCategories, kidsCategories) || + const DeepCollectionEquality() + .equals(other.kidsCategories, kidsCategories)) && + (identical(other.movieCategories, movieCategories) || + const DeepCollectionEquality() + .equals(other.movieCategories, movieCategories)) && + (identical(other.channelMappings, channelMappings) || + const DeepCollectionEquality() + .equals(other.channelMappings, channelMappings)) && + (identical(other.moviePrefix, moviePrefix) || + const DeepCollectionEquality() + .equals(other.moviePrefix, moviePrefix)) && + (identical(other.preferredLanguage, preferredLanguage) || + const DeepCollectionEquality() + .equals(other.preferredLanguage, preferredLanguage)) && + (identical(other.userAgent, userAgent) || + const DeepCollectionEquality() + .equals(other.userAgent, userAgent))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(type) ^ + const DeepCollectionEquality().hash(username) ^ + const DeepCollectionEquality().hash(password) ^ + const DeepCollectionEquality().hash(listingsId) ^ + const DeepCollectionEquality().hash(zipCode) ^ + const DeepCollectionEquality().hash(country) ^ + const DeepCollectionEquality().hash(path) ^ + const DeepCollectionEquality().hash(enabledTuners) ^ + const DeepCollectionEquality().hash(enableAllTuners) ^ + const DeepCollectionEquality().hash(newsCategories) ^ + const DeepCollectionEquality().hash(sportsCategories) ^ + const DeepCollectionEquality().hash(kidsCategories) ^ + const DeepCollectionEquality().hash(movieCategories) ^ + const DeepCollectionEquality().hash(channelMappings) ^ + const DeepCollectionEquality().hash(moviePrefix) ^ + const DeepCollectionEquality().hash(preferredLanguage) ^ + const DeepCollectionEquality().hash(userAgent) ^ + runtimeType.hashCode; +} + +extension $ListingsProviderInfoExtension on ListingsProviderInfo { + ListingsProviderInfo copyWith( + {String? id, + String? type, + String? username, + String? password, + String? listingsId, + String? zipCode, + String? country, + String? path, + List? enabledTuners, + bool? enableAllTuners, + List? newsCategories, + List? sportsCategories, + List? kidsCategories, + List? movieCategories, + List? channelMappings, + String? moviePrefix, + String? preferredLanguage, + String? userAgent}) { + return ListingsProviderInfo( + id: id ?? this.id, + type: type ?? this.type, + username: username ?? this.username, + password: password ?? this.password, + listingsId: listingsId ?? this.listingsId, + zipCode: zipCode ?? this.zipCode, + country: country ?? this.country, + path: path ?? this.path, + enabledTuners: enabledTuners ?? this.enabledTuners, + enableAllTuners: enableAllTuners ?? this.enableAllTuners, + newsCategories: newsCategories ?? this.newsCategories, + sportsCategories: sportsCategories ?? this.sportsCategories, + kidsCategories: kidsCategories ?? this.kidsCategories, + movieCategories: movieCategories ?? this.movieCategories, + channelMappings: channelMappings ?? this.channelMappings, + moviePrefix: moviePrefix ?? this.moviePrefix, + preferredLanguage: preferredLanguage ?? this.preferredLanguage, + userAgent: userAgent ?? this.userAgent); + } + + ListingsProviderInfo copyWithWrapped( + {Wrapped? id, + Wrapped? type, + Wrapped? username, + Wrapped? password, + Wrapped? listingsId, + Wrapped? zipCode, + Wrapped? country, + Wrapped? path, + Wrapped?>? enabledTuners, + Wrapped? enableAllTuners, + Wrapped?>? newsCategories, + Wrapped?>? sportsCategories, + Wrapped?>? kidsCategories, + Wrapped?>? movieCategories, + Wrapped?>? channelMappings, + Wrapped? moviePrefix, + Wrapped? preferredLanguage, + Wrapped? userAgent}) { + return ListingsProviderInfo( + id: (id != null ? id.value : this.id), + type: (type != null ? type.value : this.type), + username: (username != null ? username.value : this.username), + password: (password != null ? password.value : this.password), + listingsId: (listingsId != null ? listingsId.value : this.listingsId), + zipCode: (zipCode != null ? zipCode.value : this.zipCode), + country: (country != null ? country.value : this.country), + path: (path != null ? path.value : this.path), + enabledTuners: + (enabledTuners != null ? enabledTuners.value : this.enabledTuners), + enableAllTuners: (enableAllTuners != null + ? enableAllTuners.value + : this.enableAllTuners), + newsCategories: (newsCategories != null + ? newsCategories.value + : this.newsCategories), + sportsCategories: (sportsCategories != null + ? sportsCategories.value + : this.sportsCategories), + kidsCategories: (kidsCategories != null + ? kidsCategories.value + : this.kidsCategories), + movieCategories: (movieCategories != null + ? movieCategories.value + : this.movieCategories), + channelMappings: (channelMappings != null + ? channelMappings.value + : this.channelMappings), + moviePrefix: + (moviePrefix != null ? moviePrefix.value : this.moviePrefix), + preferredLanguage: (preferredLanguage != null + ? preferredLanguage.value + : this.preferredLanguage), + userAgent: (userAgent != null ? userAgent.value : this.userAgent)); + } +} + +@JsonSerializable(explicitToJson: true) +class LiveStreamResponse { + const LiveStreamResponse({ + this.mediaSource, + }); + + factory LiveStreamResponse.fromJson(Map json) => + _$LiveStreamResponseFromJson(json); + + static const toJsonFactory = _$LiveStreamResponseToJson; + Map toJson() => _$LiveStreamResponseToJson(this); + + @JsonKey(name: 'MediaSource', includeIfNull: false) + final MediaSourceInfo? mediaSource; + static const fromJsonFactory = _$LiveStreamResponseFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is LiveStreamResponse && + (identical(other.mediaSource, mediaSource) || + const DeepCollectionEquality() + .equals(other.mediaSource, mediaSource))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(mediaSource) ^ runtimeType.hashCode; +} + +extension $LiveStreamResponseExtension on LiveStreamResponse { + LiveStreamResponse copyWith({MediaSourceInfo? mediaSource}) { + return LiveStreamResponse(mediaSource: mediaSource ?? this.mediaSource); + } + + LiveStreamResponse copyWithWrapped({Wrapped? mediaSource}) { + return LiveStreamResponse( + mediaSource: + (mediaSource != null ? mediaSource.value : this.mediaSource)); + } +} + +@JsonSerializable(explicitToJson: true) +class LiveTvInfo { + const LiveTvInfo({ + this.services, + this.isEnabled, + this.enabledUsers, + }); + + factory LiveTvInfo.fromJson(Map json) => + _$LiveTvInfoFromJson(json); + + static const toJsonFactory = _$LiveTvInfoToJson; + Map toJson() => _$LiveTvInfoToJson(this); + + @JsonKey( + name: 'Services', + includeIfNull: false, + defaultValue: []) + final List? services; + @JsonKey(name: 'IsEnabled', includeIfNull: false) + final bool? isEnabled; + @JsonKey(name: 'EnabledUsers', includeIfNull: false, defaultValue: []) + final List? enabledUsers; + static const fromJsonFactory = _$LiveTvInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is LiveTvInfo && + (identical(other.services, services) || + const DeepCollectionEquality() + .equals(other.services, services)) && + (identical(other.isEnabled, isEnabled) || + const DeepCollectionEquality() + .equals(other.isEnabled, isEnabled)) && + (identical(other.enabledUsers, enabledUsers) || + const DeepCollectionEquality() + .equals(other.enabledUsers, enabledUsers))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(services) ^ + const DeepCollectionEquality().hash(isEnabled) ^ + const DeepCollectionEquality().hash(enabledUsers) ^ + runtimeType.hashCode; +} + +extension $LiveTvInfoExtension on LiveTvInfo { + LiveTvInfo copyWith( + {List? services, + bool? isEnabled, + List? enabledUsers}) { + return LiveTvInfo( + services: services ?? this.services, + isEnabled: isEnabled ?? this.isEnabled, + enabledUsers: enabledUsers ?? this.enabledUsers); + } + + LiveTvInfo copyWithWrapped( + {Wrapped?>? services, + Wrapped? isEnabled, + Wrapped?>? enabledUsers}) { + return LiveTvInfo( + services: (services != null ? services.value : this.services), + isEnabled: (isEnabled != null ? isEnabled.value : this.isEnabled), + enabledUsers: + (enabledUsers != null ? enabledUsers.value : this.enabledUsers)); + } +} + +@JsonSerializable(explicitToJson: true) +class LiveTvOptions { + const LiveTvOptions({ + this.guideDays, + this.recordingPath, + this.movieRecordingPath, + this.seriesRecordingPath, + this.enableRecordingSubfolders, + this.enableOriginalAudioWithEncodedRecordings, + this.tunerHosts, + this.listingProviders, + this.prePaddingSeconds, + this.postPaddingSeconds, + this.mediaLocationsCreated, + this.recordingPostProcessor, + this.recordingPostProcessorArguments, + this.saveRecordingNFO, + this.saveRecordingImages, + }); + + factory LiveTvOptions.fromJson(Map json) => + _$LiveTvOptionsFromJson(json); + + static const toJsonFactory = _$LiveTvOptionsToJson; + Map toJson() => _$LiveTvOptionsToJson(this); + + @JsonKey(name: 'GuideDays', includeIfNull: false) + final int? guideDays; + @JsonKey(name: 'RecordingPath', includeIfNull: false) + final String? recordingPath; + @JsonKey(name: 'MovieRecordingPath', includeIfNull: false) + final String? movieRecordingPath; + @JsonKey(name: 'SeriesRecordingPath', includeIfNull: false) + final String? seriesRecordingPath; + @JsonKey(name: 'EnableRecordingSubfolders', includeIfNull: false) + final bool? enableRecordingSubfolders; + @JsonKey( + name: 'EnableOriginalAudioWithEncodedRecordings', includeIfNull: false) + final bool? enableOriginalAudioWithEncodedRecordings; + @JsonKey( + name: 'TunerHosts', includeIfNull: false, defaultValue: []) + final List? tunerHosts; + @JsonKey( + name: 'ListingProviders', + includeIfNull: false, + defaultValue: []) + final List? listingProviders; + @JsonKey(name: 'PrePaddingSeconds', includeIfNull: false) + final int? prePaddingSeconds; + @JsonKey(name: 'PostPaddingSeconds', includeIfNull: false) + final int? postPaddingSeconds; + @JsonKey( + name: 'MediaLocationsCreated', + includeIfNull: false, + defaultValue: []) + final List? mediaLocationsCreated; + @JsonKey(name: 'RecordingPostProcessor', includeIfNull: false) + final String? recordingPostProcessor; + @JsonKey(name: 'RecordingPostProcessorArguments', includeIfNull: false) + final String? recordingPostProcessorArguments; + @JsonKey(name: 'SaveRecordingNFO', includeIfNull: false) + final bool? saveRecordingNFO; + @JsonKey(name: 'SaveRecordingImages', includeIfNull: false) + final bool? saveRecordingImages; + static const fromJsonFactory = _$LiveTvOptionsFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is LiveTvOptions && + (identical(other.guideDays, guideDays) || + const DeepCollectionEquality() + .equals(other.guideDays, guideDays)) && + (identical(other.recordingPath, recordingPath) || + const DeepCollectionEquality() + .equals(other.recordingPath, recordingPath)) && + (identical(other.movieRecordingPath, movieRecordingPath) || + const DeepCollectionEquality() + .equals(other.movieRecordingPath, movieRecordingPath)) && + (identical(other.seriesRecordingPath, seriesRecordingPath) || + const DeepCollectionEquality() + .equals(other.seriesRecordingPath, seriesRecordingPath)) && + (identical(other.enableRecordingSubfolders, enableRecordingSubfolders) || + const DeepCollectionEquality().equals( + other.enableRecordingSubfolders, + enableRecordingSubfolders)) && + (identical(other.enableOriginalAudioWithEncodedRecordings, enableOriginalAudioWithEncodedRecordings) || + const DeepCollectionEquality().equals( + other.enableOriginalAudioWithEncodedRecordings, + enableOriginalAudioWithEncodedRecordings)) && + (identical(other.tunerHosts, tunerHosts) || + const DeepCollectionEquality() + .equals(other.tunerHosts, tunerHosts)) && + (identical(other.listingProviders, listingProviders) || + const DeepCollectionEquality() + .equals(other.listingProviders, listingProviders)) && + (identical(other.prePaddingSeconds, prePaddingSeconds) || + const DeepCollectionEquality() + .equals(other.prePaddingSeconds, prePaddingSeconds)) && + (identical(other.postPaddingSeconds, postPaddingSeconds) || + const DeepCollectionEquality() + .equals(other.postPaddingSeconds, postPaddingSeconds)) && + (identical(other.mediaLocationsCreated, mediaLocationsCreated) || + const DeepCollectionEquality().equals( + other.mediaLocationsCreated, mediaLocationsCreated)) && + (identical(other.recordingPostProcessor, recordingPostProcessor) || + const DeepCollectionEquality().equals( + other.recordingPostProcessor, recordingPostProcessor)) && + (identical(other.recordingPostProcessorArguments, recordingPostProcessorArguments) || + const DeepCollectionEquality().equals( + other.recordingPostProcessorArguments, + recordingPostProcessorArguments)) && + (identical(other.saveRecordingNFO, saveRecordingNFO) || const DeepCollectionEquality().equals(other.saveRecordingNFO, saveRecordingNFO)) && + (identical(other.saveRecordingImages, saveRecordingImages) || const DeepCollectionEquality().equals(other.saveRecordingImages, saveRecordingImages))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(guideDays) ^ + const DeepCollectionEquality().hash(recordingPath) ^ + const DeepCollectionEquality().hash(movieRecordingPath) ^ + const DeepCollectionEquality().hash(seriesRecordingPath) ^ + const DeepCollectionEquality().hash(enableRecordingSubfolders) ^ + const DeepCollectionEquality() + .hash(enableOriginalAudioWithEncodedRecordings) ^ + const DeepCollectionEquality().hash(tunerHosts) ^ + const DeepCollectionEquality().hash(listingProviders) ^ + const DeepCollectionEquality().hash(prePaddingSeconds) ^ + const DeepCollectionEquality().hash(postPaddingSeconds) ^ + const DeepCollectionEquality().hash(mediaLocationsCreated) ^ + const DeepCollectionEquality().hash(recordingPostProcessor) ^ + const DeepCollectionEquality().hash(recordingPostProcessorArguments) ^ + const DeepCollectionEquality().hash(saveRecordingNFO) ^ + const DeepCollectionEquality().hash(saveRecordingImages) ^ + runtimeType.hashCode; +} + +extension $LiveTvOptionsExtension on LiveTvOptions { + LiveTvOptions copyWith( + {int? guideDays, + String? recordingPath, + String? movieRecordingPath, + String? seriesRecordingPath, + bool? enableRecordingSubfolders, + bool? enableOriginalAudioWithEncodedRecordings, + List? tunerHosts, + List? listingProviders, + int? prePaddingSeconds, + int? postPaddingSeconds, + List? mediaLocationsCreated, + String? recordingPostProcessor, + String? recordingPostProcessorArguments, + bool? saveRecordingNFO, + bool? saveRecordingImages}) { + return LiveTvOptions( + guideDays: guideDays ?? this.guideDays, + recordingPath: recordingPath ?? this.recordingPath, + movieRecordingPath: movieRecordingPath ?? this.movieRecordingPath, + seriesRecordingPath: seriesRecordingPath ?? this.seriesRecordingPath, + enableRecordingSubfolders: + enableRecordingSubfolders ?? this.enableRecordingSubfolders, + enableOriginalAudioWithEncodedRecordings: + enableOriginalAudioWithEncodedRecordings ?? + this.enableOriginalAudioWithEncodedRecordings, + tunerHosts: tunerHosts ?? this.tunerHosts, + listingProviders: listingProviders ?? this.listingProviders, + prePaddingSeconds: prePaddingSeconds ?? this.prePaddingSeconds, + postPaddingSeconds: postPaddingSeconds ?? this.postPaddingSeconds, + mediaLocationsCreated: + mediaLocationsCreated ?? this.mediaLocationsCreated, + recordingPostProcessor: + recordingPostProcessor ?? this.recordingPostProcessor, + recordingPostProcessorArguments: recordingPostProcessorArguments ?? + this.recordingPostProcessorArguments, + saveRecordingNFO: saveRecordingNFO ?? this.saveRecordingNFO, + saveRecordingImages: saveRecordingImages ?? this.saveRecordingImages); + } + + LiveTvOptions copyWithWrapped( + {Wrapped? guideDays, + Wrapped? recordingPath, + Wrapped? movieRecordingPath, + Wrapped? seriesRecordingPath, + Wrapped? enableRecordingSubfolders, + Wrapped? enableOriginalAudioWithEncodedRecordings, + Wrapped?>? tunerHosts, + Wrapped?>? listingProviders, + Wrapped? prePaddingSeconds, + Wrapped? postPaddingSeconds, + Wrapped?>? mediaLocationsCreated, + Wrapped? recordingPostProcessor, + Wrapped? recordingPostProcessorArguments, + Wrapped? saveRecordingNFO, + Wrapped? saveRecordingImages}) { + return LiveTvOptions( + guideDays: (guideDays != null ? guideDays.value : this.guideDays), + recordingPath: + (recordingPath != null ? recordingPath.value : this.recordingPath), + movieRecordingPath: (movieRecordingPath != null + ? movieRecordingPath.value + : this.movieRecordingPath), + seriesRecordingPath: (seriesRecordingPath != null + ? seriesRecordingPath.value + : this.seriesRecordingPath), + enableRecordingSubfolders: (enableRecordingSubfolders != null + ? enableRecordingSubfolders.value + : this.enableRecordingSubfolders), + enableOriginalAudioWithEncodedRecordings: + (enableOriginalAudioWithEncodedRecordings != null + ? enableOriginalAudioWithEncodedRecordings.value + : this.enableOriginalAudioWithEncodedRecordings), + tunerHosts: (tunerHosts != null ? tunerHosts.value : this.tunerHosts), + listingProviders: (listingProviders != null + ? listingProviders.value + : this.listingProviders), + prePaddingSeconds: (prePaddingSeconds != null + ? prePaddingSeconds.value + : this.prePaddingSeconds), + postPaddingSeconds: (postPaddingSeconds != null + ? postPaddingSeconds.value + : this.postPaddingSeconds), + mediaLocationsCreated: (mediaLocationsCreated != null + ? mediaLocationsCreated.value + : this.mediaLocationsCreated), + recordingPostProcessor: (recordingPostProcessor != null + ? recordingPostProcessor.value + : this.recordingPostProcessor), + recordingPostProcessorArguments: + (recordingPostProcessorArguments != null + ? recordingPostProcessorArguments.value + : this.recordingPostProcessorArguments), + saveRecordingNFO: (saveRecordingNFO != null + ? saveRecordingNFO.value + : this.saveRecordingNFO), + saveRecordingImages: (saveRecordingImages != null + ? saveRecordingImages.value + : this.saveRecordingImages)); + } +} + +@JsonSerializable(explicitToJson: true) +class LiveTvServiceInfo { + const LiveTvServiceInfo({ + this.name, + this.homePageUrl, + this.status, + this.statusMessage, + this.version, + this.hasUpdateAvailable, + this.isVisible, + this.tuners, + }); + + factory LiveTvServiceInfo.fromJson(Map json) => + _$LiveTvServiceInfoFromJson(json); + + static const toJsonFactory = _$LiveTvServiceInfoToJson; + Map toJson() => _$LiveTvServiceInfoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'HomePageUrl', includeIfNull: false) + final String? homePageUrl; + @JsonKey( + name: 'Status', + includeIfNull: false, + toJson: liveTvServiceStatusNullableToJson, + fromJson: liveTvServiceStatusNullableFromJson, + ) + final enums.LiveTvServiceStatus? status; + @JsonKey(name: 'StatusMessage', includeIfNull: false) + final String? statusMessage; + @JsonKey(name: 'Version', includeIfNull: false) + final String? version; + @JsonKey(name: 'HasUpdateAvailable', includeIfNull: false) + final bool? hasUpdateAvailable; + @JsonKey(name: 'IsVisible', includeIfNull: false) + final bool? isVisible; + @JsonKey(name: 'Tuners', includeIfNull: false, defaultValue: []) + final List? tuners; + static const fromJsonFactory = _$LiveTvServiceInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is LiveTvServiceInfo && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.homePageUrl, homePageUrl) || + const DeepCollectionEquality() + .equals(other.homePageUrl, homePageUrl)) && + (identical(other.status, status) || + const DeepCollectionEquality().equals(other.status, status)) && + (identical(other.statusMessage, statusMessage) || + const DeepCollectionEquality() + .equals(other.statusMessage, statusMessage)) && + (identical(other.version, version) || + const DeepCollectionEquality() + .equals(other.version, version)) && + (identical(other.hasUpdateAvailable, hasUpdateAvailable) || + const DeepCollectionEquality() + .equals(other.hasUpdateAvailable, hasUpdateAvailable)) && + (identical(other.isVisible, isVisible) || + const DeepCollectionEquality() + .equals(other.isVisible, isVisible)) && + (identical(other.tuners, tuners) || + const DeepCollectionEquality().equals(other.tuners, tuners))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(homePageUrl) ^ + const DeepCollectionEquality().hash(status) ^ + const DeepCollectionEquality().hash(statusMessage) ^ + const DeepCollectionEquality().hash(version) ^ + const DeepCollectionEquality().hash(hasUpdateAvailable) ^ + const DeepCollectionEquality().hash(isVisible) ^ + const DeepCollectionEquality().hash(tuners) ^ + runtimeType.hashCode; +} + +extension $LiveTvServiceInfoExtension on LiveTvServiceInfo { + LiveTvServiceInfo copyWith( + {String? name, + String? homePageUrl, + enums.LiveTvServiceStatus? status, + String? statusMessage, + String? version, + bool? hasUpdateAvailable, + bool? isVisible, + List? tuners}) { + return LiveTvServiceInfo( + name: name ?? this.name, + homePageUrl: homePageUrl ?? this.homePageUrl, + status: status ?? this.status, + statusMessage: statusMessage ?? this.statusMessage, + version: version ?? this.version, + hasUpdateAvailable: hasUpdateAvailable ?? this.hasUpdateAvailable, + isVisible: isVisible ?? this.isVisible, + tuners: tuners ?? this.tuners); + } + + LiveTvServiceInfo copyWithWrapped( + {Wrapped? name, + Wrapped? homePageUrl, + Wrapped? status, + Wrapped? statusMessage, + Wrapped? version, + Wrapped? hasUpdateAvailable, + Wrapped? isVisible, + Wrapped?>? tuners}) { + return LiveTvServiceInfo( + name: (name != null ? name.value : this.name), + homePageUrl: + (homePageUrl != null ? homePageUrl.value : this.homePageUrl), + status: (status != null ? status.value : this.status), + statusMessage: + (statusMessage != null ? statusMessage.value : this.statusMessage), + version: (version != null ? version.value : this.version), + hasUpdateAvailable: (hasUpdateAvailable != null + ? hasUpdateAvailable.value + : this.hasUpdateAvailable), + isVisible: (isVisible != null ? isVisible.value : this.isVisible), + tuners: (tuners != null ? tuners.value : this.tuners)); + } +} + +@JsonSerializable(explicitToJson: true) +class LocalizationOption { + const LocalizationOption({ + this.name, + this.$Value, + }); + + factory LocalizationOption.fromJson(Map json) => + _$LocalizationOptionFromJson(json); + + static const toJsonFactory = _$LocalizationOptionToJson; + Map toJson() => _$LocalizationOptionToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'Value', includeIfNull: false) + final String? $Value; + static const fromJsonFactory = _$LocalizationOptionFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is LocalizationOption && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.$Value, $Value) || + const DeepCollectionEquality().equals(other.$Value, $Value))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash($Value) ^ + runtimeType.hashCode; +} + +extension $LocalizationOptionExtension on LocalizationOption { + LocalizationOption copyWith({String? name, String? $Value}) { + return LocalizationOption( + name: name ?? this.name, $Value: $Value ?? this.$Value); + } + + LocalizationOption copyWithWrapped( + {Wrapped? name, Wrapped? $Value}) { + return LocalizationOption( + name: (name != null ? name.value : this.name), + $Value: ($Value != null ? $Value.value : this.$Value)); + } +} + +@JsonSerializable(explicitToJson: true) +class LogFile { + const LogFile({ + this.dateCreated, + this.dateModified, + this.size, + this.name, + }); + + factory LogFile.fromJson(Map json) => + _$LogFileFromJson(json); + + static const toJsonFactory = _$LogFileToJson; + Map toJson() => _$LogFileToJson(this); + + @JsonKey(name: 'DateCreated', includeIfNull: false) + final DateTime? dateCreated; + @JsonKey(name: 'DateModified', includeIfNull: false) + final DateTime? dateModified; + @JsonKey(name: 'Size', includeIfNull: false) + final int? size; + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + static const fromJsonFactory = _$LogFileFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is LogFile && + (identical(other.dateCreated, dateCreated) || + const DeepCollectionEquality() + .equals(other.dateCreated, dateCreated)) && + (identical(other.dateModified, dateModified) || + const DeepCollectionEquality() + .equals(other.dateModified, dateModified)) && + (identical(other.size, size) || + const DeepCollectionEquality().equals(other.size, size)) && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(dateCreated) ^ + const DeepCollectionEquality().hash(dateModified) ^ + const DeepCollectionEquality().hash(size) ^ + const DeepCollectionEquality().hash(name) ^ + runtimeType.hashCode; +} + +extension $LogFileExtension on LogFile { + LogFile copyWith( + {DateTime? dateCreated, + DateTime? dateModified, + int? size, + String? name}) { + return LogFile( + dateCreated: dateCreated ?? this.dateCreated, + dateModified: dateModified ?? this.dateModified, + size: size ?? this.size, + name: name ?? this.name); + } + + LogFile copyWithWrapped( + {Wrapped? dateCreated, + Wrapped? dateModified, + Wrapped? size, + Wrapped? name}) { + return LogFile( + dateCreated: + (dateCreated != null ? dateCreated.value : this.dateCreated), + dateModified: + (dateModified != null ? dateModified.value : this.dateModified), + size: (size != null ? size.value : this.size), + name: (name != null ? name.value : this.name)); + } +} + +@JsonSerializable(explicitToJson: true) +class LyricDto { + const LyricDto({ + this.metadata, + this.lyrics, + }); + + factory LyricDto.fromJson(Map json) => + _$LyricDtoFromJson(json); + + static const toJsonFactory = _$LyricDtoToJson; + Map toJson() => _$LyricDtoToJson(this); + + @JsonKey(name: 'Metadata', includeIfNull: false) + final LyricMetadata? metadata; + @JsonKey(name: 'Lyrics', includeIfNull: false, defaultValue: []) + final List? lyrics; + static const fromJsonFactory = _$LyricDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is LyricDto && + (identical(other.metadata, metadata) || + const DeepCollectionEquality() + .equals(other.metadata, metadata)) && + (identical(other.lyrics, lyrics) || + const DeepCollectionEquality().equals(other.lyrics, lyrics))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(metadata) ^ + const DeepCollectionEquality().hash(lyrics) ^ + runtimeType.hashCode; +} + +extension $LyricDtoExtension on LyricDto { + LyricDto copyWith({LyricMetadata? metadata, List? lyrics}) { + return LyricDto( + metadata: metadata ?? this.metadata, lyrics: lyrics ?? this.lyrics); + } + + LyricDto copyWithWrapped( + {Wrapped? metadata, Wrapped?>? lyrics}) { + return LyricDto( + metadata: (metadata != null ? metadata.value : this.metadata), + lyrics: (lyrics != null ? lyrics.value : this.lyrics)); + } +} + +@JsonSerializable(explicitToJson: true) +class LyricLine { + const LyricLine({ + this.text, + this.start, + }); + + factory LyricLine.fromJson(Map json) => + _$LyricLineFromJson(json); + + static const toJsonFactory = _$LyricLineToJson; + Map toJson() => _$LyricLineToJson(this); + + @JsonKey(name: 'Text', includeIfNull: false) + final String? text; + @JsonKey(name: 'Start', includeIfNull: false) + final int? start; + static const fromJsonFactory = _$LyricLineFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is LyricLine && + (identical(other.text, text) || + const DeepCollectionEquality().equals(other.text, text)) && + (identical(other.start, start) || + const DeepCollectionEquality().equals(other.start, start))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(text) ^ + const DeepCollectionEquality().hash(start) ^ + runtimeType.hashCode; +} + +extension $LyricLineExtension on LyricLine { + LyricLine copyWith({String? text, int? start}) { + return LyricLine(text: text ?? this.text, start: start ?? this.start); + } + + LyricLine copyWithWrapped({Wrapped? text, Wrapped? start}) { + return LyricLine( + text: (text != null ? text.value : this.text), + start: (start != null ? start.value : this.start)); + } +} + +@JsonSerializable(explicitToJson: true) +class LyricMetadata { + const LyricMetadata({ + this.artist, + this.album, + this.title, + this.author, + this.length, + this.by, + this.offset, + this.creator, + this.version, + this.isSynced, + }); + + factory LyricMetadata.fromJson(Map json) => + _$LyricMetadataFromJson(json); + + static const toJsonFactory = _$LyricMetadataToJson; + Map toJson() => _$LyricMetadataToJson(this); + + @JsonKey(name: 'Artist', includeIfNull: false) + final String? artist; + @JsonKey(name: 'Album', includeIfNull: false) + final String? album; + @JsonKey(name: 'Title', includeIfNull: false) + final String? title; + @JsonKey(name: 'Author', includeIfNull: false) + final String? author; + @JsonKey(name: 'Length', includeIfNull: false) + final int? length; + @JsonKey(name: 'By', includeIfNull: false) + final String? by; + @JsonKey(name: 'Offset', includeIfNull: false) + final int? offset; + @JsonKey(name: 'Creator', includeIfNull: false) + final String? creator; + @JsonKey(name: 'Version', includeIfNull: false) + final String? version; + @JsonKey(name: 'IsSynced', includeIfNull: false) + final bool? isSynced; + static const fromJsonFactory = _$LyricMetadataFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is LyricMetadata && + (identical(other.artist, artist) || + const DeepCollectionEquality().equals(other.artist, artist)) && + (identical(other.album, album) || + const DeepCollectionEquality().equals(other.album, album)) && + (identical(other.title, title) || + const DeepCollectionEquality().equals(other.title, title)) && + (identical(other.author, author) || + const DeepCollectionEquality().equals(other.author, author)) && + (identical(other.length, length) || + const DeepCollectionEquality().equals(other.length, length)) && + (identical(other.by, by) || + const DeepCollectionEquality().equals(other.by, by)) && + (identical(other.offset, offset) || + const DeepCollectionEquality().equals(other.offset, offset)) && + (identical(other.creator, creator) || + const DeepCollectionEquality() + .equals(other.creator, creator)) && + (identical(other.version, version) || + const DeepCollectionEquality() + .equals(other.version, version)) && + (identical(other.isSynced, isSynced) || + const DeepCollectionEquality() + .equals(other.isSynced, isSynced))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(artist) ^ + const DeepCollectionEquality().hash(album) ^ + const DeepCollectionEquality().hash(title) ^ + const DeepCollectionEquality().hash(author) ^ + const DeepCollectionEquality().hash(length) ^ + const DeepCollectionEquality().hash(by) ^ + const DeepCollectionEquality().hash(offset) ^ + const DeepCollectionEquality().hash(creator) ^ + const DeepCollectionEquality().hash(version) ^ + const DeepCollectionEquality().hash(isSynced) ^ + runtimeType.hashCode; +} + +extension $LyricMetadataExtension on LyricMetadata { + LyricMetadata copyWith( + {String? artist, + String? album, + String? title, + String? author, + int? length, + String? by, + int? offset, + String? creator, + String? version, + bool? isSynced}) { + return LyricMetadata( + artist: artist ?? this.artist, + album: album ?? this.album, + title: title ?? this.title, + author: author ?? this.author, + length: length ?? this.length, + by: by ?? this.by, + offset: offset ?? this.offset, + creator: creator ?? this.creator, + version: version ?? this.version, + isSynced: isSynced ?? this.isSynced); + } + + LyricMetadata copyWithWrapped( + {Wrapped? artist, + Wrapped? album, + Wrapped? title, + Wrapped? author, + Wrapped? length, + Wrapped? by, + Wrapped? offset, + Wrapped? creator, + Wrapped? version, + Wrapped? isSynced}) { + return LyricMetadata( + artist: (artist != null ? artist.value : this.artist), + album: (album != null ? album.value : this.album), + title: (title != null ? title.value : this.title), + author: (author != null ? author.value : this.author), + length: (length != null ? length.value : this.length), + by: (by != null ? by.value : this.by), + offset: (offset != null ? offset.value : this.offset), + creator: (creator != null ? creator.value : this.creator), + version: (version != null ? version.value : this.version), + isSynced: (isSynced != null ? isSynced.value : this.isSynced)); + } +} + +@JsonSerializable(explicitToJson: true) +class MediaAttachment { + const MediaAttachment({ + this.codec, + this.codecTag, + this.comment, + this.index, + this.fileName, + this.mimeType, + this.deliveryUrl, + }); + + factory MediaAttachment.fromJson(Map json) => + _$MediaAttachmentFromJson(json); + + static const toJsonFactory = _$MediaAttachmentToJson; + Map toJson() => _$MediaAttachmentToJson(this); + + @JsonKey(name: 'Codec', includeIfNull: false) + final String? codec; + @JsonKey(name: 'CodecTag', includeIfNull: false) + final String? codecTag; + @JsonKey(name: 'Comment', includeIfNull: false) + final String? comment; + @JsonKey(name: 'Index', includeIfNull: false) + final int? index; + @JsonKey(name: 'FileName', includeIfNull: false) + final String? fileName; + @JsonKey(name: 'MimeType', includeIfNull: false) + final String? mimeType; + @JsonKey(name: 'DeliveryUrl', includeIfNull: false) + final String? deliveryUrl; + static const fromJsonFactory = _$MediaAttachmentFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is MediaAttachment && + (identical(other.codec, codec) || + const DeepCollectionEquality().equals(other.codec, codec)) && + (identical(other.codecTag, codecTag) || + const DeepCollectionEquality() + .equals(other.codecTag, codecTag)) && + (identical(other.comment, comment) || + const DeepCollectionEquality() + .equals(other.comment, comment)) && + (identical(other.index, index) || + const DeepCollectionEquality().equals(other.index, index)) && + (identical(other.fileName, fileName) || + const DeepCollectionEquality() + .equals(other.fileName, fileName)) && + (identical(other.mimeType, mimeType) || + const DeepCollectionEquality() + .equals(other.mimeType, mimeType)) && + (identical(other.deliveryUrl, deliveryUrl) || + const DeepCollectionEquality() + .equals(other.deliveryUrl, deliveryUrl))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(codec) ^ + const DeepCollectionEquality().hash(codecTag) ^ + const DeepCollectionEquality().hash(comment) ^ + const DeepCollectionEquality().hash(index) ^ + const DeepCollectionEquality().hash(fileName) ^ + const DeepCollectionEquality().hash(mimeType) ^ + const DeepCollectionEquality().hash(deliveryUrl) ^ + runtimeType.hashCode; +} + +extension $MediaAttachmentExtension on MediaAttachment { + MediaAttachment copyWith( + {String? codec, + String? codecTag, + String? comment, + int? index, + String? fileName, + String? mimeType, + String? deliveryUrl}) { + return MediaAttachment( + codec: codec ?? this.codec, + codecTag: codecTag ?? this.codecTag, + comment: comment ?? this.comment, + index: index ?? this.index, + fileName: fileName ?? this.fileName, + mimeType: mimeType ?? this.mimeType, + deliveryUrl: deliveryUrl ?? this.deliveryUrl); + } + + MediaAttachment copyWithWrapped( + {Wrapped? codec, + Wrapped? codecTag, + Wrapped? comment, + Wrapped? index, + Wrapped? fileName, + Wrapped? mimeType, + Wrapped? deliveryUrl}) { + return MediaAttachment( + codec: (codec != null ? codec.value : this.codec), + codecTag: (codecTag != null ? codecTag.value : this.codecTag), + comment: (comment != null ? comment.value : this.comment), + index: (index != null ? index.value : this.index), + fileName: (fileName != null ? fileName.value : this.fileName), + mimeType: (mimeType != null ? mimeType.value : this.mimeType), + deliveryUrl: + (deliveryUrl != null ? deliveryUrl.value : this.deliveryUrl)); + } +} + +@JsonSerializable(explicitToJson: true) +class MediaPathDto { + const MediaPathDto({ + required this.name, + this.path, + this.pathInfo, + }); + + factory MediaPathDto.fromJson(Map json) => + _$MediaPathDtoFromJson(json); + + static const toJsonFactory = _$MediaPathDtoToJson; + Map toJson() => _$MediaPathDtoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String name; + @JsonKey(name: 'Path', includeIfNull: false) + final String? path; + @JsonKey(name: 'PathInfo', includeIfNull: false) + final MediaPathInfo? pathInfo; + static const fromJsonFactory = _$MediaPathDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is MediaPathDto && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.path, path) || + const DeepCollectionEquality().equals(other.path, path)) && + (identical(other.pathInfo, pathInfo) || + const DeepCollectionEquality() + .equals(other.pathInfo, pathInfo))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(path) ^ + const DeepCollectionEquality().hash(pathInfo) ^ + runtimeType.hashCode; +} + +extension $MediaPathDtoExtension on MediaPathDto { + MediaPathDto copyWith({String? name, String? path, MediaPathInfo? pathInfo}) { + return MediaPathDto( + name: name ?? this.name, + path: path ?? this.path, + pathInfo: pathInfo ?? this.pathInfo); + } + + MediaPathDto copyWithWrapped( + {Wrapped? name, + Wrapped? path, + Wrapped? pathInfo}) { + return MediaPathDto( + name: (name != null ? name.value : this.name), + path: (path != null ? path.value : this.path), + pathInfo: (pathInfo != null ? pathInfo.value : this.pathInfo)); + } +} + +@JsonSerializable(explicitToJson: true) +class MediaPathInfo { + const MediaPathInfo({ + this.path, + this.networkPath, + }); + + factory MediaPathInfo.fromJson(Map json) => + _$MediaPathInfoFromJson(json); + + static const toJsonFactory = _$MediaPathInfoToJson; + Map toJson() => _$MediaPathInfoToJson(this); + + @JsonKey(name: 'Path', includeIfNull: false) + final String? path; + @JsonKey(name: 'NetworkPath', includeIfNull: false) + final String? networkPath; + static const fromJsonFactory = _$MediaPathInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is MediaPathInfo && + (identical(other.path, path) || + const DeepCollectionEquality().equals(other.path, path)) && + (identical(other.networkPath, networkPath) || + const DeepCollectionEquality() + .equals(other.networkPath, networkPath))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(path) ^ + const DeepCollectionEquality().hash(networkPath) ^ + runtimeType.hashCode; +} + +extension $MediaPathInfoExtension on MediaPathInfo { + MediaPathInfo copyWith({String? path, String? networkPath}) { + return MediaPathInfo( + path: path ?? this.path, networkPath: networkPath ?? this.networkPath); + } + + MediaPathInfo copyWithWrapped( + {Wrapped? path, Wrapped? networkPath}) { + return MediaPathInfo( + path: (path != null ? path.value : this.path), + networkPath: + (networkPath != null ? networkPath.value : this.networkPath)); + } +} + +@JsonSerializable(explicitToJson: true) +class MediaSourceInfo { + const MediaSourceInfo({ + this.protocol, + this.id, + this.path, + this.encoderPath, + this.encoderProtocol, + this.type, + this.container, + this.size, + this.name, + this.isRemote, + this.eTag, + this.runTimeTicks, + this.readAtNativeFramerate, + this.ignoreDts, + this.ignoreIndex, + this.genPtsInput, + this.supportsTranscoding, + this.supportsDirectStream, + this.supportsDirectPlay, + this.isInfiniteStream, + this.requiresOpening, + this.openToken, + this.requiresClosing, + this.liveStreamId, + this.bufferMs, + this.requiresLooping, + this.supportsProbing, + this.videoType, + this.isoType, + this.video3DFormat, + this.mediaStreams, + this.mediaAttachments, + this.formats, + this.bitrate, + this.timestamp, + this.requiredHttpHeaders, + this.transcodingUrl, + this.transcodingSubProtocol, + this.transcodingContainer, + this.analyzeDurationMs, + this.defaultAudioStreamIndex, + this.defaultSubtitleStreamIndex, + }); + + factory MediaSourceInfo.fromJson(Map json) => + _$MediaSourceInfoFromJson(json); + + static const toJsonFactory = _$MediaSourceInfoToJson; + Map toJson() => _$MediaSourceInfoToJson(this); + + @JsonKey( + name: 'Protocol', + includeIfNull: false, + toJson: mediaProtocolNullableToJson, + fromJson: mediaProtocolNullableFromJson, + ) + final enums.MediaProtocol? protocol; + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'Path', includeIfNull: false) + final String? path; + @JsonKey(name: 'EncoderPath', includeIfNull: false) + final String? encoderPath; + @JsonKey( + name: 'EncoderProtocol', + includeIfNull: false, + toJson: mediaProtocolNullableToJson, + fromJson: mediaProtocolNullableFromJson, + ) + final enums.MediaProtocol? encoderProtocol; + @JsonKey( + name: 'Type', + includeIfNull: false, + toJson: mediaSourceTypeNullableToJson, + fromJson: mediaSourceTypeNullableFromJson, + ) + final enums.MediaSourceType? type; + @JsonKey(name: 'Container', includeIfNull: false) + final String? container; + @JsonKey(name: 'Size', includeIfNull: false) + final int? size; + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'IsRemote', includeIfNull: false) + final bool? isRemote; + @JsonKey(name: 'ETag', includeIfNull: false) + final String? eTag; + @JsonKey(name: 'RunTimeTicks', includeIfNull: false) + final int? runTimeTicks; + @JsonKey(name: 'ReadAtNativeFramerate', includeIfNull: false) + final bool? readAtNativeFramerate; + @JsonKey(name: 'IgnoreDts', includeIfNull: false) + final bool? ignoreDts; + @JsonKey(name: 'IgnoreIndex', includeIfNull: false) + final bool? ignoreIndex; + @JsonKey(name: 'GenPtsInput', includeIfNull: false) + final bool? genPtsInput; + @JsonKey(name: 'SupportsTranscoding', includeIfNull: false) + final bool? supportsTranscoding; + @JsonKey(name: 'SupportsDirectStream', includeIfNull: false) + final bool? supportsDirectStream; + @JsonKey(name: 'SupportsDirectPlay', includeIfNull: false) + final bool? supportsDirectPlay; + @JsonKey(name: 'IsInfiniteStream', includeIfNull: false) + final bool? isInfiniteStream; + @JsonKey(name: 'RequiresOpening', includeIfNull: false) + final bool? requiresOpening; + @JsonKey(name: 'OpenToken', includeIfNull: false) + final String? openToken; + @JsonKey(name: 'RequiresClosing', includeIfNull: false) + final bool? requiresClosing; + @JsonKey(name: 'LiveStreamId', includeIfNull: false) + final String? liveStreamId; + @JsonKey(name: 'BufferMs', includeIfNull: false) + final int? bufferMs; + @JsonKey(name: 'RequiresLooping', includeIfNull: false) + final bool? requiresLooping; + @JsonKey(name: 'SupportsProbing', includeIfNull: false) + final bool? supportsProbing; + @JsonKey( + name: 'VideoType', + includeIfNull: false, + toJson: videoTypeNullableToJson, + fromJson: videoTypeNullableFromJson, + ) + final enums.VideoType? videoType; + @JsonKey( + name: 'IsoType', + includeIfNull: false, + toJson: isoTypeNullableToJson, + fromJson: isoTypeNullableFromJson, + ) + final enums.IsoType? isoType; + @JsonKey( + name: 'Video3DFormat', + includeIfNull: false, + toJson: video3DFormatNullableToJson, + fromJson: video3DFormatNullableFromJson, + ) + final enums.Video3DFormat? video3DFormat; + @JsonKey( + name: 'MediaStreams', includeIfNull: false, defaultValue: []) + final List? mediaStreams; + @JsonKey( + name: 'MediaAttachments', + includeIfNull: false, + defaultValue: []) + final List? mediaAttachments; + @JsonKey(name: 'Formats', includeIfNull: false, defaultValue: []) + final List? formats; + @JsonKey(name: 'Bitrate', includeIfNull: false) + final int? bitrate; + @JsonKey( + name: 'Timestamp', + includeIfNull: false, + toJson: transportStreamTimestampNullableToJson, + fromJson: transportStreamTimestampNullableFromJson, + ) + final enums.TransportStreamTimestamp? timestamp; + @JsonKey(name: 'RequiredHttpHeaders', includeIfNull: false) + final Map? requiredHttpHeaders; + @JsonKey(name: 'TranscodingUrl', includeIfNull: false) + final String? transcodingUrl; + @JsonKey( + name: 'TranscodingSubProtocol', + includeIfNull: false, + toJson: mediaStreamProtocolNullableToJson, + fromJson: mediaStreamProtocolNullableFromJson, + ) + final enums.MediaStreamProtocol? transcodingSubProtocol; + @JsonKey(name: 'TranscodingContainer', includeIfNull: false) + final String? transcodingContainer; + @JsonKey(name: 'AnalyzeDurationMs', includeIfNull: false) + final int? analyzeDurationMs; + @JsonKey(name: 'DefaultAudioStreamIndex', includeIfNull: false) + final int? defaultAudioStreamIndex; + @JsonKey(name: 'DefaultSubtitleStreamIndex', includeIfNull: false) + final int? defaultSubtitleStreamIndex; + static const fromJsonFactory = _$MediaSourceInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is MediaSourceInfo && + (identical(other.protocol, protocol) || + const DeepCollectionEquality() + .equals(other.protocol, protocol)) && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.path, path) || + const DeepCollectionEquality().equals(other.path, path)) && + (identical(other.encoderPath, encoderPath) || + const DeepCollectionEquality() + .equals(other.encoderPath, encoderPath)) && + (identical(other.encoderProtocol, encoderProtocol) || + const DeepCollectionEquality() + .equals(other.encoderProtocol, encoderProtocol)) && + (identical(other.type, type) || + const DeepCollectionEquality().equals(other.type, type)) && + (identical(other.container, container) || + const DeepCollectionEquality() + .equals(other.container, container)) && + (identical(other.size, size) || + const DeepCollectionEquality().equals(other.size, size)) && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.isRemote, isRemote) || + const DeepCollectionEquality() + .equals(other.isRemote, isRemote)) && + (identical(other.eTag, eTag) || + const DeepCollectionEquality().equals(other.eTag, eTag)) && + (identical(other.runTimeTicks, runTimeTicks) || + const DeepCollectionEquality() + .equals(other.runTimeTicks, runTimeTicks)) && + (identical(other.readAtNativeFramerate, readAtNativeFramerate) || + const DeepCollectionEquality().equals( + other.readAtNativeFramerate, readAtNativeFramerate)) && + (identical(other.ignoreDts, ignoreDts) || + const DeepCollectionEquality() + .equals(other.ignoreDts, ignoreDts)) && + (identical(other.ignoreIndex, ignoreIndex) || + const DeepCollectionEquality() + .equals(other.ignoreIndex, ignoreIndex)) && + (identical(other.genPtsInput, genPtsInput) || + const DeepCollectionEquality() + .equals(other.genPtsInput, genPtsInput)) && + (identical(other.supportsTranscoding, supportsTranscoding) || + const DeepCollectionEquality() + .equals(other.supportsTranscoding, supportsTranscoding)) && + (identical(other.supportsDirectStream, supportsDirectStream) || + const DeepCollectionEquality().equals( + other.supportsDirectStream, supportsDirectStream)) && + (identical(other.supportsDirectPlay, supportsDirectPlay) || + const DeepCollectionEquality() + .equals(other.supportsDirectPlay, supportsDirectPlay)) && + (identical(other.isInfiniteStream, isInfiniteStream) || + const DeepCollectionEquality() + .equals(other.isInfiniteStream, isInfiniteStream)) && + (identical(other.requiresOpening, requiresOpening) || + const DeepCollectionEquality() + .equals(other.requiresOpening, requiresOpening)) && + (identical(other.openToken, openToken) || + const DeepCollectionEquality() + .equals(other.openToken, openToken)) && + (identical(other.requiresClosing, requiresClosing) || + const DeepCollectionEquality() + .equals(other.requiresClosing, requiresClosing)) && + (identical(other.liveStreamId, liveStreamId) || + const DeepCollectionEquality() + .equals(other.liveStreamId, liveStreamId)) && + (identical(other.bufferMs, bufferMs) || const DeepCollectionEquality().equals(other.bufferMs, bufferMs)) && + (identical(other.requiresLooping, requiresLooping) || const DeepCollectionEquality().equals(other.requiresLooping, requiresLooping)) && + (identical(other.supportsProbing, supportsProbing) || const DeepCollectionEquality().equals(other.supportsProbing, supportsProbing)) && + (identical(other.videoType, videoType) || const DeepCollectionEquality().equals(other.videoType, videoType)) && + (identical(other.isoType, isoType) || const DeepCollectionEquality().equals(other.isoType, isoType)) && + (identical(other.video3DFormat, video3DFormat) || const DeepCollectionEquality().equals(other.video3DFormat, video3DFormat)) && + (identical(other.mediaStreams, mediaStreams) || const DeepCollectionEquality().equals(other.mediaStreams, mediaStreams)) && + (identical(other.mediaAttachments, mediaAttachments) || const DeepCollectionEquality().equals(other.mediaAttachments, mediaAttachments)) && + (identical(other.formats, formats) || const DeepCollectionEquality().equals(other.formats, formats)) && + (identical(other.bitrate, bitrate) || const DeepCollectionEquality().equals(other.bitrate, bitrate)) && + (identical(other.timestamp, timestamp) || const DeepCollectionEquality().equals(other.timestamp, timestamp)) && + (identical(other.requiredHttpHeaders, requiredHttpHeaders) || const DeepCollectionEquality().equals(other.requiredHttpHeaders, requiredHttpHeaders)) && + (identical(other.transcodingUrl, transcodingUrl) || const DeepCollectionEquality().equals(other.transcodingUrl, transcodingUrl)) && + (identical(other.transcodingSubProtocol, transcodingSubProtocol) || const DeepCollectionEquality().equals(other.transcodingSubProtocol, transcodingSubProtocol)) && + (identical(other.transcodingContainer, transcodingContainer) || const DeepCollectionEquality().equals(other.transcodingContainer, transcodingContainer)) && + (identical(other.analyzeDurationMs, analyzeDurationMs) || const DeepCollectionEquality().equals(other.analyzeDurationMs, analyzeDurationMs)) && + (identical(other.defaultAudioStreamIndex, defaultAudioStreamIndex) || const DeepCollectionEquality().equals(other.defaultAudioStreamIndex, defaultAudioStreamIndex)) && + (identical(other.defaultSubtitleStreamIndex, defaultSubtitleStreamIndex) || const DeepCollectionEquality().equals(other.defaultSubtitleStreamIndex, defaultSubtitleStreamIndex))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(protocol) ^ + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(path) ^ + const DeepCollectionEquality().hash(encoderPath) ^ + const DeepCollectionEquality().hash(encoderProtocol) ^ + const DeepCollectionEquality().hash(type) ^ + const DeepCollectionEquality().hash(container) ^ + const DeepCollectionEquality().hash(size) ^ + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(isRemote) ^ + const DeepCollectionEquality().hash(eTag) ^ + const DeepCollectionEquality().hash(runTimeTicks) ^ + const DeepCollectionEquality().hash(readAtNativeFramerate) ^ + const DeepCollectionEquality().hash(ignoreDts) ^ + const DeepCollectionEquality().hash(ignoreIndex) ^ + const DeepCollectionEquality().hash(genPtsInput) ^ + const DeepCollectionEquality().hash(supportsTranscoding) ^ + const DeepCollectionEquality().hash(supportsDirectStream) ^ + const DeepCollectionEquality().hash(supportsDirectPlay) ^ + const DeepCollectionEquality().hash(isInfiniteStream) ^ + const DeepCollectionEquality().hash(requiresOpening) ^ + const DeepCollectionEquality().hash(openToken) ^ + const DeepCollectionEquality().hash(requiresClosing) ^ + const DeepCollectionEquality().hash(liveStreamId) ^ + const DeepCollectionEquality().hash(bufferMs) ^ + const DeepCollectionEquality().hash(requiresLooping) ^ + const DeepCollectionEquality().hash(supportsProbing) ^ + const DeepCollectionEquality().hash(videoType) ^ + const DeepCollectionEquality().hash(isoType) ^ + const DeepCollectionEquality().hash(video3DFormat) ^ + const DeepCollectionEquality().hash(mediaStreams) ^ + const DeepCollectionEquality().hash(mediaAttachments) ^ + const DeepCollectionEquality().hash(formats) ^ + const DeepCollectionEquality().hash(bitrate) ^ + const DeepCollectionEquality().hash(timestamp) ^ + const DeepCollectionEquality().hash(requiredHttpHeaders) ^ + const DeepCollectionEquality().hash(transcodingUrl) ^ + const DeepCollectionEquality().hash(transcodingSubProtocol) ^ + const DeepCollectionEquality().hash(transcodingContainer) ^ + const DeepCollectionEquality().hash(analyzeDurationMs) ^ + const DeepCollectionEquality().hash(defaultAudioStreamIndex) ^ + const DeepCollectionEquality().hash(defaultSubtitleStreamIndex) ^ + runtimeType.hashCode; +} + +extension $MediaSourceInfoExtension on MediaSourceInfo { + MediaSourceInfo copyWith( + {enums.MediaProtocol? protocol, + String? id, + String? path, + String? encoderPath, + enums.MediaProtocol? encoderProtocol, + enums.MediaSourceType? type, + String? container, + int? size, + String? name, + bool? isRemote, + String? eTag, + int? runTimeTicks, + bool? readAtNativeFramerate, + bool? ignoreDts, + bool? ignoreIndex, + bool? genPtsInput, + bool? supportsTranscoding, + bool? supportsDirectStream, + bool? supportsDirectPlay, + bool? isInfiniteStream, + bool? requiresOpening, + String? openToken, + bool? requiresClosing, + String? liveStreamId, + int? bufferMs, + bool? requiresLooping, + bool? supportsProbing, + enums.VideoType? videoType, + enums.IsoType? isoType, + enums.Video3DFormat? video3DFormat, + List? mediaStreams, + List? mediaAttachments, + List? formats, + int? bitrate, + enums.TransportStreamTimestamp? timestamp, + Map? requiredHttpHeaders, + String? transcodingUrl, + enums.MediaStreamProtocol? transcodingSubProtocol, + String? transcodingContainer, + int? analyzeDurationMs, + int? defaultAudioStreamIndex, + int? defaultSubtitleStreamIndex}) { + return MediaSourceInfo( + protocol: protocol ?? this.protocol, + id: id ?? this.id, + path: path ?? this.path, + encoderPath: encoderPath ?? this.encoderPath, + encoderProtocol: encoderProtocol ?? this.encoderProtocol, + type: type ?? this.type, + container: container ?? this.container, + size: size ?? this.size, + name: name ?? this.name, + isRemote: isRemote ?? this.isRemote, + eTag: eTag ?? this.eTag, + runTimeTicks: runTimeTicks ?? this.runTimeTicks, + readAtNativeFramerate: + readAtNativeFramerate ?? this.readAtNativeFramerate, + ignoreDts: ignoreDts ?? this.ignoreDts, + ignoreIndex: ignoreIndex ?? this.ignoreIndex, + genPtsInput: genPtsInput ?? this.genPtsInput, + supportsTranscoding: supportsTranscoding ?? this.supportsTranscoding, + supportsDirectStream: supportsDirectStream ?? this.supportsDirectStream, + supportsDirectPlay: supportsDirectPlay ?? this.supportsDirectPlay, + isInfiniteStream: isInfiniteStream ?? this.isInfiniteStream, + requiresOpening: requiresOpening ?? this.requiresOpening, + openToken: openToken ?? this.openToken, + requiresClosing: requiresClosing ?? this.requiresClosing, + liveStreamId: liveStreamId ?? this.liveStreamId, + bufferMs: bufferMs ?? this.bufferMs, + requiresLooping: requiresLooping ?? this.requiresLooping, + supportsProbing: supportsProbing ?? this.supportsProbing, + videoType: videoType ?? this.videoType, + isoType: isoType ?? this.isoType, + video3DFormat: video3DFormat ?? this.video3DFormat, + mediaStreams: mediaStreams ?? this.mediaStreams, + mediaAttachments: mediaAttachments ?? this.mediaAttachments, + formats: formats ?? this.formats, + bitrate: bitrate ?? this.bitrate, + timestamp: timestamp ?? this.timestamp, + requiredHttpHeaders: requiredHttpHeaders ?? this.requiredHttpHeaders, + transcodingUrl: transcodingUrl ?? this.transcodingUrl, + transcodingSubProtocol: + transcodingSubProtocol ?? this.transcodingSubProtocol, + transcodingContainer: transcodingContainer ?? this.transcodingContainer, + analyzeDurationMs: analyzeDurationMs ?? this.analyzeDurationMs, + defaultAudioStreamIndex: + defaultAudioStreamIndex ?? this.defaultAudioStreamIndex, + defaultSubtitleStreamIndex: + defaultSubtitleStreamIndex ?? this.defaultSubtitleStreamIndex); + } + + MediaSourceInfo copyWithWrapped( + {Wrapped? protocol, + Wrapped? id, + Wrapped? path, + Wrapped? encoderPath, + Wrapped? encoderProtocol, + Wrapped? type, + Wrapped? container, + Wrapped? size, + Wrapped? name, + Wrapped? isRemote, + Wrapped? eTag, + Wrapped? runTimeTicks, + Wrapped? readAtNativeFramerate, + Wrapped? ignoreDts, + Wrapped? ignoreIndex, + Wrapped? genPtsInput, + Wrapped? supportsTranscoding, + Wrapped? supportsDirectStream, + Wrapped? supportsDirectPlay, + Wrapped? isInfiniteStream, + Wrapped? requiresOpening, + Wrapped? openToken, + Wrapped? requiresClosing, + Wrapped? liveStreamId, + Wrapped? bufferMs, + Wrapped? requiresLooping, + Wrapped? supportsProbing, + Wrapped? videoType, + Wrapped? isoType, + Wrapped? video3DFormat, + Wrapped?>? mediaStreams, + Wrapped?>? mediaAttachments, + Wrapped?>? formats, + Wrapped? bitrate, + Wrapped? timestamp, + Wrapped?>? requiredHttpHeaders, + Wrapped? transcodingUrl, + Wrapped? transcodingSubProtocol, + Wrapped? transcodingContainer, + Wrapped? analyzeDurationMs, + Wrapped? defaultAudioStreamIndex, + Wrapped? defaultSubtitleStreamIndex}) { + return MediaSourceInfo( + protocol: (protocol != null ? protocol.value : this.protocol), + id: (id != null ? id.value : this.id), + path: (path != null ? path.value : this.path), + encoderPath: + (encoderPath != null ? encoderPath.value : this.encoderPath), + encoderProtocol: (encoderProtocol != null + ? encoderProtocol.value + : this.encoderProtocol), + type: (type != null ? type.value : this.type), + container: (container != null ? container.value : this.container), + size: (size != null ? size.value : this.size), + name: (name != null ? name.value : this.name), + isRemote: (isRemote != null ? isRemote.value : this.isRemote), + eTag: (eTag != null ? eTag.value : this.eTag), + runTimeTicks: + (runTimeTicks != null ? runTimeTicks.value : this.runTimeTicks), + readAtNativeFramerate: (readAtNativeFramerate != null + ? readAtNativeFramerate.value + : this.readAtNativeFramerate), + ignoreDts: (ignoreDts != null ? ignoreDts.value : this.ignoreDts), + ignoreIndex: + (ignoreIndex != null ? ignoreIndex.value : this.ignoreIndex), + genPtsInput: + (genPtsInput != null ? genPtsInput.value : this.genPtsInput), + supportsTranscoding: (supportsTranscoding != null + ? supportsTranscoding.value + : this.supportsTranscoding), + supportsDirectStream: (supportsDirectStream != null + ? supportsDirectStream.value + : this.supportsDirectStream), + supportsDirectPlay: (supportsDirectPlay != null + ? supportsDirectPlay.value + : this.supportsDirectPlay), + isInfiniteStream: (isInfiniteStream != null + ? isInfiniteStream.value + : this.isInfiniteStream), + requiresOpening: (requiresOpening != null + ? requiresOpening.value + : this.requiresOpening), + openToken: (openToken != null ? openToken.value : this.openToken), + requiresClosing: (requiresClosing != null + ? requiresClosing.value + : this.requiresClosing), + liveStreamId: + (liveStreamId != null ? liveStreamId.value : this.liveStreamId), + bufferMs: (bufferMs != null ? bufferMs.value : this.bufferMs), + requiresLooping: (requiresLooping != null + ? requiresLooping.value + : this.requiresLooping), + supportsProbing: (supportsProbing != null + ? supportsProbing.value + : this.supportsProbing), + videoType: (videoType != null ? videoType.value : this.videoType), + isoType: (isoType != null ? isoType.value : this.isoType), + video3DFormat: + (video3DFormat != null ? video3DFormat.value : this.video3DFormat), + mediaStreams: + (mediaStreams != null ? mediaStreams.value : this.mediaStreams), + mediaAttachments: (mediaAttachments != null + ? mediaAttachments.value + : this.mediaAttachments), + formats: (formats != null ? formats.value : this.formats), + bitrate: (bitrate != null ? bitrate.value : this.bitrate), + timestamp: (timestamp != null ? timestamp.value : this.timestamp), + requiredHttpHeaders: (requiredHttpHeaders != null + ? requiredHttpHeaders.value + : this.requiredHttpHeaders), + transcodingUrl: (transcodingUrl != null + ? transcodingUrl.value + : this.transcodingUrl), + transcodingSubProtocol: (transcodingSubProtocol != null + ? transcodingSubProtocol.value + : this.transcodingSubProtocol), + transcodingContainer: (transcodingContainer != null + ? transcodingContainer.value + : this.transcodingContainer), + analyzeDurationMs: (analyzeDurationMs != null + ? analyzeDurationMs.value + : this.analyzeDurationMs), + defaultAudioStreamIndex: (defaultAudioStreamIndex != null + ? defaultAudioStreamIndex.value + : this.defaultAudioStreamIndex), + defaultSubtitleStreamIndex: (defaultSubtitleStreamIndex != null + ? defaultSubtitleStreamIndex.value + : this.defaultSubtitleStreamIndex)); + } +} + +@JsonSerializable(explicitToJson: true) +class MediaStream { + const MediaStream({ + this.codec, + this.codecTag, + this.language, + this.colorRange, + this.colorSpace, + this.colorTransfer, + this.colorPrimaries, + this.dvVersionMajor, + this.dvVersionMinor, + this.dvProfile, + this.dvLevel, + this.rpuPresentFlag, + this.elPresentFlag, + this.blPresentFlag, + this.dvBlSignalCompatibilityId, + this.comment, + this.timeBase, + this.codecTimeBase, + this.title, + this.videoRange, + this.videoRangeType, + this.videoDoViTitle, + this.audioSpatialFormat, + this.localizedUndefined, + this.localizedDefault, + this.localizedForced, + this.localizedExternal, + this.localizedHearingImpaired, + this.displayTitle, + this.nalLengthSize, + this.isInterlaced, + this.isAVC, + this.channelLayout, + this.bitRate, + this.bitDepth, + this.refFrames, + this.packetLength, + this.channels, + this.sampleRate, + this.isDefault, + this.isForced, + this.isHearingImpaired, + this.height, + this.width, + this.averageFrameRate, + this.realFrameRate, + this.profile, + this.type, + this.aspectRatio, + this.index, + this.score, + this.isExternal, + this.deliveryMethod, + this.deliveryUrl, + this.isExternalUrl, + this.isTextSubtitleStream, + this.supportsExternalStream, + this.path, + this.pixelFormat, + this.level, + this.isAnamorphic, + }); + + factory MediaStream.fromJson(Map json) => + _$MediaStreamFromJson(json); + + static const toJsonFactory = _$MediaStreamToJson; + Map toJson() => _$MediaStreamToJson(this); + + @JsonKey(name: 'Codec', includeIfNull: false) + final String? codec; + @JsonKey(name: 'CodecTag', includeIfNull: false) + final String? codecTag; + @JsonKey(name: 'Language', includeIfNull: false) + final String? language; + @JsonKey(name: 'ColorRange', includeIfNull: false) + final String? colorRange; + @JsonKey(name: 'ColorSpace', includeIfNull: false) + final String? colorSpace; + @JsonKey(name: 'ColorTransfer', includeIfNull: false) + final String? colorTransfer; + @JsonKey(name: 'ColorPrimaries', includeIfNull: false) + final String? colorPrimaries; + @JsonKey(name: 'DvVersionMajor', includeIfNull: false) + final int? dvVersionMajor; + @JsonKey(name: 'DvVersionMinor', includeIfNull: false) + final int? dvVersionMinor; + @JsonKey(name: 'DvProfile', includeIfNull: false) + final int? dvProfile; + @JsonKey(name: 'DvLevel', includeIfNull: false) + final int? dvLevel; + @JsonKey(name: 'RpuPresentFlag', includeIfNull: false) + final int? rpuPresentFlag; + @JsonKey(name: 'ElPresentFlag', includeIfNull: false) + final int? elPresentFlag; + @JsonKey(name: 'BlPresentFlag', includeIfNull: false) + final int? blPresentFlag; + @JsonKey(name: 'DvBlSignalCompatibilityId', includeIfNull: false) + final int? dvBlSignalCompatibilityId; + @JsonKey(name: 'Comment', includeIfNull: false) + final String? comment; + @JsonKey(name: 'TimeBase', includeIfNull: false) + final String? timeBase; + @JsonKey(name: 'CodecTimeBase', includeIfNull: false) + final String? codecTimeBase; + @JsonKey(name: 'Title', includeIfNull: false) + final String? title; + @JsonKey( + name: 'VideoRange', + includeIfNull: false, + toJson: videoRangeNullableToJson, + fromJson: videoRangeNullableFromJson, + ) + final enums.VideoRange? videoRange; + @JsonKey( + name: 'VideoRangeType', + includeIfNull: false, + toJson: videoRangeTypeNullableToJson, + fromJson: videoRangeTypeNullableFromJson, + ) + final enums.VideoRangeType? videoRangeType; + @JsonKey(name: 'VideoDoViTitle', includeIfNull: false) + final String? videoDoViTitle; + @JsonKey( + name: 'AudioSpatialFormat', + includeIfNull: false, + toJson: audioSpatialFormatNullableToJson, + fromJson: audioSpatialFormatAudioSpatialFormatNullableFromJson, + ) + final enums.AudioSpatialFormat? audioSpatialFormat; + static enums.AudioSpatialFormat? + audioSpatialFormatAudioSpatialFormatNullableFromJson(Object? value) => + audioSpatialFormatNullableFromJson( + value, enums.AudioSpatialFormat.none); + + @JsonKey(name: 'LocalizedUndefined', includeIfNull: false) + final String? localizedUndefined; + @JsonKey(name: 'LocalizedDefault', includeIfNull: false) + final String? localizedDefault; + @JsonKey(name: 'LocalizedForced', includeIfNull: false) + final String? localizedForced; + @JsonKey(name: 'LocalizedExternal', includeIfNull: false) + final String? localizedExternal; + @JsonKey(name: 'LocalizedHearingImpaired', includeIfNull: false) + final String? localizedHearingImpaired; + @JsonKey(name: 'DisplayTitle', includeIfNull: false) + final String? displayTitle; + @JsonKey(name: 'NalLengthSize', includeIfNull: false) + final String? nalLengthSize; + @JsonKey(name: 'IsInterlaced', includeIfNull: false) + final bool? isInterlaced; + @JsonKey(name: 'IsAVC', includeIfNull: false) + final bool? isAVC; + @JsonKey(name: 'ChannelLayout', includeIfNull: false) + final String? channelLayout; + @JsonKey(name: 'BitRate', includeIfNull: false) + final int? bitRate; + @JsonKey(name: 'BitDepth', includeIfNull: false) + final int? bitDepth; + @JsonKey(name: 'RefFrames', includeIfNull: false) + final int? refFrames; + @JsonKey(name: 'PacketLength', includeIfNull: false) + final int? packetLength; + @JsonKey(name: 'Channels', includeIfNull: false) + final int? channels; + @JsonKey(name: 'SampleRate', includeIfNull: false) + final int? sampleRate; + @JsonKey(name: 'IsDefault', includeIfNull: false) + final bool? isDefault; + @JsonKey(name: 'IsForced', includeIfNull: false) + final bool? isForced; + @JsonKey(name: 'IsHearingImpaired', includeIfNull: false) + final bool? isHearingImpaired; + @JsonKey(name: 'Height', includeIfNull: false) + final int? height; + @JsonKey(name: 'Width', includeIfNull: false) + final int? width; + @JsonKey(name: 'AverageFrameRate', includeIfNull: false) + final double? averageFrameRate; + @JsonKey(name: 'RealFrameRate', includeIfNull: false) + final double? realFrameRate; + @JsonKey(name: 'Profile', includeIfNull: false) + final String? profile; + @JsonKey( + name: 'Type', + includeIfNull: false, + toJson: mediaStreamTypeNullableToJson, + fromJson: mediaStreamTypeNullableFromJson, + ) + final enums.MediaStreamType? type; + @JsonKey(name: 'AspectRatio', includeIfNull: false) + final String? aspectRatio; + @JsonKey(name: 'Index', includeIfNull: false) + final int? index; + @JsonKey(name: 'Score', includeIfNull: false) + final int? score; + @JsonKey(name: 'IsExternal', includeIfNull: false) + final bool? isExternal; + @JsonKey( + name: 'DeliveryMethod', + includeIfNull: false, + toJson: subtitleDeliveryMethodNullableToJson, + fromJson: subtitleDeliveryMethodNullableFromJson, + ) + final enums.SubtitleDeliveryMethod? deliveryMethod; + @JsonKey(name: 'DeliveryUrl', includeIfNull: false) + final String? deliveryUrl; + @JsonKey(name: 'IsExternalUrl', includeIfNull: false) + final bool? isExternalUrl; + @JsonKey(name: 'IsTextSubtitleStream', includeIfNull: false) + final bool? isTextSubtitleStream; + @JsonKey(name: 'SupportsExternalStream', includeIfNull: false) + final bool? supportsExternalStream; + @JsonKey(name: 'Path', includeIfNull: false) + final String? path; + @JsonKey(name: 'PixelFormat', includeIfNull: false) + final String? pixelFormat; + @JsonKey(name: 'Level', includeIfNull: false) + final double? level; + @JsonKey(name: 'IsAnamorphic', includeIfNull: false) + final bool? isAnamorphic; + static const fromJsonFactory = _$MediaStreamFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is MediaStream && + (identical(other.codec, codec) || + const DeepCollectionEquality().equals(other.codec, codec)) && + (identical(other.codecTag, codecTag) || + const DeepCollectionEquality() + .equals(other.codecTag, codecTag)) && + (identical(other.language, language) || + const DeepCollectionEquality() + .equals(other.language, language)) && + (identical(other.colorRange, colorRange) || + const DeepCollectionEquality() + .equals(other.colorRange, colorRange)) && + (identical(other.colorSpace, colorSpace) || + const DeepCollectionEquality() + .equals(other.colorSpace, colorSpace)) && + (identical(other.colorTransfer, colorTransfer) || + const DeepCollectionEquality() + .equals(other.colorTransfer, colorTransfer)) && + (identical(other.colorPrimaries, colorPrimaries) || + const DeepCollectionEquality() + .equals(other.colorPrimaries, colorPrimaries)) && + (identical(other.dvVersionMajor, dvVersionMajor) || + const DeepCollectionEquality() + .equals(other.dvVersionMajor, dvVersionMajor)) && + (identical(other.dvVersionMinor, dvVersionMinor) || + const DeepCollectionEquality() + .equals(other.dvVersionMinor, dvVersionMinor)) && + (identical(other.dvProfile, dvProfile) || + const DeepCollectionEquality() + .equals(other.dvProfile, dvProfile)) && + (identical(other.dvLevel, dvLevel) || + const DeepCollectionEquality() + .equals(other.dvLevel, dvLevel)) && + (identical(other.rpuPresentFlag, rpuPresentFlag) || + const DeepCollectionEquality() + .equals(other.rpuPresentFlag, rpuPresentFlag)) && + (identical(other.elPresentFlag, elPresentFlag) || + const DeepCollectionEquality() + .equals(other.elPresentFlag, elPresentFlag)) && + (identical(other.blPresentFlag, blPresentFlag) || + const DeepCollectionEquality() + .equals(other.blPresentFlag, blPresentFlag)) && + (identical(other.dvBlSignalCompatibilityId, dvBlSignalCompatibilityId) || + const DeepCollectionEquality().equals( + other.dvBlSignalCompatibilityId, + dvBlSignalCompatibilityId)) && + (identical(other.comment, comment) || + const DeepCollectionEquality() + .equals(other.comment, comment)) && + (identical(other.timeBase, timeBase) || + const DeepCollectionEquality() + .equals(other.timeBase, timeBase)) && + (identical(other.codecTimeBase, codecTimeBase) || + const DeepCollectionEquality() + .equals(other.codecTimeBase, codecTimeBase)) && + (identical(other.title, title) || + const DeepCollectionEquality().equals(other.title, title)) && + (identical(other.videoRange, videoRange) || + const DeepCollectionEquality() + .equals(other.videoRange, videoRange)) && + (identical(other.videoRangeType, videoRangeType) || + const DeepCollectionEquality() + .equals(other.videoRangeType, videoRangeType)) && + (identical(other.videoDoViTitle, videoDoViTitle) || const DeepCollectionEquality().equals(other.videoDoViTitle, videoDoViTitle)) && + (identical(other.audioSpatialFormat, audioSpatialFormat) || const DeepCollectionEquality().equals(other.audioSpatialFormat, audioSpatialFormat)) && + (identical(other.localizedUndefined, localizedUndefined) || const DeepCollectionEquality().equals(other.localizedUndefined, localizedUndefined)) && + (identical(other.localizedDefault, localizedDefault) || const DeepCollectionEquality().equals(other.localizedDefault, localizedDefault)) && + (identical(other.localizedForced, localizedForced) || const DeepCollectionEquality().equals(other.localizedForced, localizedForced)) && + (identical(other.localizedExternal, localizedExternal) || const DeepCollectionEquality().equals(other.localizedExternal, localizedExternal)) && + (identical(other.localizedHearingImpaired, localizedHearingImpaired) || const DeepCollectionEquality().equals(other.localizedHearingImpaired, localizedHearingImpaired)) && + (identical(other.displayTitle, displayTitle) || const DeepCollectionEquality().equals(other.displayTitle, displayTitle)) && + (identical(other.nalLengthSize, nalLengthSize) || const DeepCollectionEquality().equals(other.nalLengthSize, nalLengthSize)) && + (identical(other.isInterlaced, isInterlaced) || const DeepCollectionEquality().equals(other.isInterlaced, isInterlaced)) && + (identical(other.isAVC, isAVC) || const DeepCollectionEquality().equals(other.isAVC, isAVC)) && + (identical(other.channelLayout, channelLayout) || const DeepCollectionEquality().equals(other.channelLayout, channelLayout)) && + (identical(other.bitRate, bitRate) || const DeepCollectionEquality().equals(other.bitRate, bitRate)) && + (identical(other.bitDepth, bitDepth) || const DeepCollectionEquality().equals(other.bitDepth, bitDepth)) && + (identical(other.refFrames, refFrames) || const DeepCollectionEquality().equals(other.refFrames, refFrames)) && + (identical(other.packetLength, packetLength) || const DeepCollectionEquality().equals(other.packetLength, packetLength)) && + (identical(other.channels, channels) || const DeepCollectionEquality().equals(other.channels, channels)) && + (identical(other.sampleRate, sampleRate) || const DeepCollectionEquality().equals(other.sampleRate, sampleRate)) && + (identical(other.isDefault, isDefault) || const DeepCollectionEquality().equals(other.isDefault, isDefault)) && + (identical(other.isForced, isForced) || const DeepCollectionEquality().equals(other.isForced, isForced)) && + (identical(other.isHearingImpaired, isHearingImpaired) || const DeepCollectionEquality().equals(other.isHearingImpaired, isHearingImpaired)) && + (identical(other.height, height) || const DeepCollectionEquality().equals(other.height, height)) && + (identical(other.width, width) || const DeepCollectionEquality().equals(other.width, width)) && + (identical(other.averageFrameRate, averageFrameRate) || const DeepCollectionEquality().equals(other.averageFrameRate, averageFrameRate)) && + (identical(other.realFrameRate, realFrameRate) || const DeepCollectionEquality().equals(other.realFrameRate, realFrameRate)) && + (identical(other.profile, profile) || const DeepCollectionEquality().equals(other.profile, profile)) && + (identical(other.type, type) || const DeepCollectionEquality().equals(other.type, type)) && + (identical(other.aspectRatio, aspectRatio) || const DeepCollectionEquality().equals(other.aspectRatio, aspectRatio)) && + (identical(other.index, index) || const DeepCollectionEquality().equals(other.index, index)) && + (identical(other.score, score) || const DeepCollectionEquality().equals(other.score, score)) && + (identical(other.isExternal, isExternal) || const DeepCollectionEquality().equals(other.isExternal, isExternal)) && + (identical(other.deliveryMethod, deliveryMethod) || const DeepCollectionEquality().equals(other.deliveryMethod, deliveryMethod)) && + (identical(other.deliveryUrl, deliveryUrl) || const DeepCollectionEquality().equals(other.deliveryUrl, deliveryUrl)) && + (identical(other.isExternalUrl, isExternalUrl) || const DeepCollectionEquality().equals(other.isExternalUrl, isExternalUrl)) && + (identical(other.isTextSubtitleStream, isTextSubtitleStream) || const DeepCollectionEquality().equals(other.isTextSubtitleStream, isTextSubtitleStream)) && + (identical(other.supportsExternalStream, supportsExternalStream) || const DeepCollectionEquality().equals(other.supportsExternalStream, supportsExternalStream)) && + (identical(other.path, path) || const DeepCollectionEquality().equals(other.path, path)) && + (identical(other.pixelFormat, pixelFormat) || const DeepCollectionEquality().equals(other.pixelFormat, pixelFormat)) && + (identical(other.level, level) || const DeepCollectionEquality().equals(other.level, level)) && + (identical(other.isAnamorphic, isAnamorphic) || const DeepCollectionEquality().equals(other.isAnamorphic, isAnamorphic))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(codec) ^ + const DeepCollectionEquality().hash(codecTag) ^ + const DeepCollectionEquality().hash(language) ^ + const DeepCollectionEquality().hash(colorRange) ^ + const DeepCollectionEquality().hash(colorSpace) ^ + const DeepCollectionEquality().hash(colorTransfer) ^ + const DeepCollectionEquality().hash(colorPrimaries) ^ + const DeepCollectionEquality().hash(dvVersionMajor) ^ + const DeepCollectionEquality().hash(dvVersionMinor) ^ + const DeepCollectionEquality().hash(dvProfile) ^ + const DeepCollectionEquality().hash(dvLevel) ^ + const DeepCollectionEquality().hash(rpuPresentFlag) ^ + const DeepCollectionEquality().hash(elPresentFlag) ^ + const DeepCollectionEquality().hash(blPresentFlag) ^ + const DeepCollectionEquality().hash(dvBlSignalCompatibilityId) ^ + const DeepCollectionEquality().hash(comment) ^ + const DeepCollectionEquality().hash(timeBase) ^ + const DeepCollectionEquality().hash(codecTimeBase) ^ + const DeepCollectionEquality().hash(title) ^ + const DeepCollectionEquality().hash(videoRange) ^ + const DeepCollectionEquality().hash(videoRangeType) ^ + const DeepCollectionEquality().hash(videoDoViTitle) ^ + const DeepCollectionEquality().hash(audioSpatialFormat) ^ + const DeepCollectionEquality().hash(localizedUndefined) ^ + const DeepCollectionEquality().hash(localizedDefault) ^ + const DeepCollectionEquality().hash(localizedForced) ^ + const DeepCollectionEquality().hash(localizedExternal) ^ + const DeepCollectionEquality().hash(localizedHearingImpaired) ^ + const DeepCollectionEquality().hash(displayTitle) ^ + const DeepCollectionEquality().hash(nalLengthSize) ^ + const DeepCollectionEquality().hash(isInterlaced) ^ + const DeepCollectionEquality().hash(isAVC) ^ + const DeepCollectionEquality().hash(channelLayout) ^ + const DeepCollectionEquality().hash(bitRate) ^ + const DeepCollectionEquality().hash(bitDepth) ^ + const DeepCollectionEquality().hash(refFrames) ^ + const DeepCollectionEquality().hash(packetLength) ^ + const DeepCollectionEquality().hash(channels) ^ + const DeepCollectionEquality().hash(sampleRate) ^ + const DeepCollectionEquality().hash(isDefault) ^ + const DeepCollectionEquality().hash(isForced) ^ + const DeepCollectionEquality().hash(isHearingImpaired) ^ + const DeepCollectionEquality().hash(height) ^ + const DeepCollectionEquality().hash(width) ^ + const DeepCollectionEquality().hash(averageFrameRate) ^ + const DeepCollectionEquality().hash(realFrameRate) ^ + const DeepCollectionEquality().hash(profile) ^ + const DeepCollectionEquality().hash(type) ^ + const DeepCollectionEquality().hash(aspectRatio) ^ + const DeepCollectionEquality().hash(index) ^ + const DeepCollectionEquality().hash(score) ^ + const DeepCollectionEquality().hash(isExternal) ^ + const DeepCollectionEquality().hash(deliveryMethod) ^ + const DeepCollectionEquality().hash(deliveryUrl) ^ + const DeepCollectionEquality().hash(isExternalUrl) ^ + const DeepCollectionEquality().hash(isTextSubtitleStream) ^ + const DeepCollectionEquality().hash(supportsExternalStream) ^ + const DeepCollectionEquality().hash(path) ^ + const DeepCollectionEquality().hash(pixelFormat) ^ + const DeepCollectionEquality().hash(level) ^ + const DeepCollectionEquality().hash(isAnamorphic) ^ + runtimeType.hashCode; +} + +extension $MediaStreamExtension on MediaStream { + MediaStream copyWith( + {String? codec, + String? codecTag, + String? language, + String? colorRange, + String? colorSpace, + String? colorTransfer, + String? colorPrimaries, + int? dvVersionMajor, + int? dvVersionMinor, + int? dvProfile, + int? dvLevel, + int? rpuPresentFlag, + int? elPresentFlag, + int? blPresentFlag, + int? dvBlSignalCompatibilityId, + String? comment, + String? timeBase, + String? codecTimeBase, + String? title, + enums.VideoRange? videoRange, + enums.VideoRangeType? videoRangeType, + String? videoDoViTitle, + enums.AudioSpatialFormat? audioSpatialFormat, + String? localizedUndefined, + String? localizedDefault, + String? localizedForced, + String? localizedExternal, + String? localizedHearingImpaired, + String? displayTitle, + String? nalLengthSize, + bool? isInterlaced, + bool? isAVC, + String? channelLayout, + int? bitRate, + int? bitDepth, + int? refFrames, + int? packetLength, + int? channels, + int? sampleRate, + bool? isDefault, + bool? isForced, + bool? isHearingImpaired, + int? height, + int? width, + double? averageFrameRate, + double? realFrameRate, + String? profile, + enums.MediaStreamType? type, + String? aspectRatio, + int? index, + int? score, + bool? isExternal, + enums.SubtitleDeliveryMethod? deliveryMethod, + String? deliveryUrl, + bool? isExternalUrl, + bool? isTextSubtitleStream, + bool? supportsExternalStream, + String? path, + String? pixelFormat, + double? level, + bool? isAnamorphic}) { + return MediaStream( + codec: codec ?? this.codec, + codecTag: codecTag ?? this.codecTag, + language: language ?? this.language, + colorRange: colorRange ?? this.colorRange, + colorSpace: colorSpace ?? this.colorSpace, + colorTransfer: colorTransfer ?? this.colorTransfer, + colorPrimaries: colorPrimaries ?? this.colorPrimaries, + dvVersionMajor: dvVersionMajor ?? this.dvVersionMajor, + dvVersionMinor: dvVersionMinor ?? this.dvVersionMinor, + dvProfile: dvProfile ?? this.dvProfile, + dvLevel: dvLevel ?? this.dvLevel, + rpuPresentFlag: rpuPresentFlag ?? this.rpuPresentFlag, + elPresentFlag: elPresentFlag ?? this.elPresentFlag, + blPresentFlag: blPresentFlag ?? this.blPresentFlag, + dvBlSignalCompatibilityId: + dvBlSignalCompatibilityId ?? this.dvBlSignalCompatibilityId, + comment: comment ?? this.comment, + timeBase: timeBase ?? this.timeBase, + codecTimeBase: codecTimeBase ?? this.codecTimeBase, + title: title ?? this.title, + videoRange: videoRange ?? this.videoRange, + videoRangeType: videoRangeType ?? this.videoRangeType, + videoDoViTitle: videoDoViTitle ?? this.videoDoViTitle, + audioSpatialFormat: audioSpatialFormat ?? this.audioSpatialFormat, + localizedUndefined: localizedUndefined ?? this.localizedUndefined, + localizedDefault: localizedDefault ?? this.localizedDefault, + localizedForced: localizedForced ?? this.localizedForced, + localizedExternal: localizedExternal ?? this.localizedExternal, + localizedHearingImpaired: + localizedHearingImpaired ?? this.localizedHearingImpaired, + displayTitle: displayTitle ?? this.displayTitle, + nalLengthSize: nalLengthSize ?? this.nalLengthSize, + isInterlaced: isInterlaced ?? this.isInterlaced, + isAVC: isAVC ?? this.isAVC, + channelLayout: channelLayout ?? this.channelLayout, + bitRate: bitRate ?? this.bitRate, + bitDepth: bitDepth ?? this.bitDepth, + refFrames: refFrames ?? this.refFrames, + packetLength: packetLength ?? this.packetLength, + channels: channels ?? this.channels, + sampleRate: sampleRate ?? this.sampleRate, + isDefault: isDefault ?? this.isDefault, + isForced: isForced ?? this.isForced, + isHearingImpaired: isHearingImpaired ?? this.isHearingImpaired, + height: height ?? this.height, + width: width ?? this.width, + averageFrameRate: averageFrameRate ?? this.averageFrameRate, + realFrameRate: realFrameRate ?? this.realFrameRate, + profile: profile ?? this.profile, + type: type ?? this.type, + aspectRatio: aspectRatio ?? this.aspectRatio, + index: index ?? this.index, + score: score ?? this.score, + isExternal: isExternal ?? this.isExternal, + deliveryMethod: deliveryMethod ?? this.deliveryMethod, + deliveryUrl: deliveryUrl ?? this.deliveryUrl, + isExternalUrl: isExternalUrl ?? this.isExternalUrl, + isTextSubtitleStream: isTextSubtitleStream ?? this.isTextSubtitleStream, + supportsExternalStream: + supportsExternalStream ?? this.supportsExternalStream, + path: path ?? this.path, + pixelFormat: pixelFormat ?? this.pixelFormat, + level: level ?? this.level, + isAnamorphic: isAnamorphic ?? this.isAnamorphic); + } + + MediaStream copyWithWrapped( + {Wrapped? codec, + Wrapped? codecTag, + Wrapped? language, + Wrapped? colorRange, + Wrapped? colorSpace, + Wrapped? colorTransfer, + Wrapped? colorPrimaries, + Wrapped? dvVersionMajor, + Wrapped? dvVersionMinor, + Wrapped? dvProfile, + Wrapped? dvLevel, + Wrapped? rpuPresentFlag, + Wrapped? elPresentFlag, + Wrapped? blPresentFlag, + Wrapped? dvBlSignalCompatibilityId, + Wrapped? comment, + Wrapped? timeBase, + Wrapped? codecTimeBase, + Wrapped? title, + Wrapped? videoRange, + Wrapped? videoRangeType, + Wrapped? videoDoViTitle, + Wrapped? audioSpatialFormat, + Wrapped? localizedUndefined, + Wrapped? localizedDefault, + Wrapped? localizedForced, + Wrapped? localizedExternal, + Wrapped? localizedHearingImpaired, + Wrapped? displayTitle, + Wrapped? nalLengthSize, + Wrapped? isInterlaced, + Wrapped? isAVC, + Wrapped? channelLayout, + Wrapped? bitRate, + Wrapped? bitDepth, + Wrapped? refFrames, + Wrapped? packetLength, + Wrapped? channels, + Wrapped? sampleRate, + Wrapped? isDefault, + Wrapped? isForced, + Wrapped? isHearingImpaired, + Wrapped? height, + Wrapped? width, + Wrapped? averageFrameRate, + Wrapped? realFrameRate, + Wrapped? profile, + Wrapped? type, + Wrapped? aspectRatio, + Wrapped? index, + Wrapped? score, + Wrapped? isExternal, + Wrapped? deliveryMethod, + Wrapped? deliveryUrl, + Wrapped? isExternalUrl, + Wrapped? isTextSubtitleStream, + Wrapped? supportsExternalStream, + Wrapped? path, + Wrapped? pixelFormat, + Wrapped? level, + Wrapped? isAnamorphic}) { + return MediaStream( + codec: (codec != null ? codec.value : this.codec), + codecTag: (codecTag != null ? codecTag.value : this.codecTag), + language: (language != null ? language.value : this.language), + colorRange: (colorRange != null ? colorRange.value : this.colorRange), + colorSpace: (colorSpace != null ? colorSpace.value : this.colorSpace), + colorTransfer: + (colorTransfer != null ? colorTransfer.value : this.colorTransfer), + colorPrimaries: (colorPrimaries != null + ? colorPrimaries.value + : this.colorPrimaries), + dvVersionMajor: (dvVersionMajor != null + ? dvVersionMajor.value + : this.dvVersionMajor), + dvVersionMinor: (dvVersionMinor != null + ? dvVersionMinor.value + : this.dvVersionMinor), + dvProfile: (dvProfile != null ? dvProfile.value : this.dvProfile), + dvLevel: (dvLevel != null ? dvLevel.value : this.dvLevel), + rpuPresentFlag: (rpuPresentFlag != null + ? rpuPresentFlag.value + : this.rpuPresentFlag), + elPresentFlag: + (elPresentFlag != null ? elPresentFlag.value : this.elPresentFlag), + blPresentFlag: + (blPresentFlag != null ? blPresentFlag.value : this.blPresentFlag), + dvBlSignalCompatibilityId: (dvBlSignalCompatibilityId != null + ? dvBlSignalCompatibilityId.value + : this.dvBlSignalCompatibilityId), + comment: (comment != null ? comment.value : this.comment), + timeBase: (timeBase != null ? timeBase.value : this.timeBase), + codecTimeBase: + (codecTimeBase != null ? codecTimeBase.value : this.codecTimeBase), + title: (title != null ? title.value : this.title), + videoRange: (videoRange != null ? videoRange.value : this.videoRange), + videoRangeType: (videoRangeType != null + ? videoRangeType.value + : this.videoRangeType), + videoDoViTitle: (videoDoViTitle != null + ? videoDoViTitle.value + : this.videoDoViTitle), + audioSpatialFormat: (audioSpatialFormat != null + ? audioSpatialFormat.value + : this.audioSpatialFormat), + localizedUndefined: (localizedUndefined != null + ? localizedUndefined.value + : this.localizedUndefined), + localizedDefault: (localizedDefault != null + ? localizedDefault.value + : this.localizedDefault), + localizedForced: (localizedForced != null + ? localizedForced.value + : this.localizedForced), + localizedExternal: (localizedExternal != null + ? localizedExternal.value + : this.localizedExternal), + localizedHearingImpaired: (localizedHearingImpaired != null + ? localizedHearingImpaired.value + : this.localizedHearingImpaired), + displayTitle: + (displayTitle != null ? displayTitle.value : this.displayTitle), + nalLengthSize: + (nalLengthSize != null ? nalLengthSize.value : this.nalLengthSize), + isInterlaced: + (isInterlaced != null ? isInterlaced.value : this.isInterlaced), + isAVC: (isAVC != null ? isAVC.value : this.isAVC), + channelLayout: + (channelLayout != null ? channelLayout.value : this.channelLayout), + bitRate: (bitRate != null ? bitRate.value : this.bitRate), + bitDepth: (bitDepth != null ? bitDepth.value : this.bitDepth), + refFrames: (refFrames != null ? refFrames.value : this.refFrames), + packetLength: + (packetLength != null ? packetLength.value : this.packetLength), + channels: (channels != null ? channels.value : this.channels), + sampleRate: (sampleRate != null ? sampleRate.value : this.sampleRate), + isDefault: (isDefault != null ? isDefault.value : this.isDefault), + isForced: (isForced != null ? isForced.value : this.isForced), + isHearingImpaired: (isHearingImpaired != null + ? isHearingImpaired.value + : this.isHearingImpaired), + height: (height != null ? height.value : this.height), + width: (width != null ? width.value : this.width), + averageFrameRate: (averageFrameRate != null + ? averageFrameRate.value + : this.averageFrameRate), + realFrameRate: + (realFrameRate != null ? realFrameRate.value : this.realFrameRate), + profile: (profile != null ? profile.value : this.profile), + type: (type != null ? type.value : this.type), + aspectRatio: + (aspectRatio != null ? aspectRatio.value : this.aspectRatio), + index: (index != null ? index.value : this.index), + score: (score != null ? score.value : this.score), + isExternal: (isExternal != null ? isExternal.value : this.isExternal), + deliveryMethod: (deliveryMethod != null + ? deliveryMethod.value + : this.deliveryMethod), + deliveryUrl: + (deliveryUrl != null ? deliveryUrl.value : this.deliveryUrl), + isExternalUrl: + (isExternalUrl != null ? isExternalUrl.value : this.isExternalUrl), + isTextSubtitleStream: (isTextSubtitleStream != null + ? isTextSubtitleStream.value + : this.isTextSubtitleStream), + supportsExternalStream: (supportsExternalStream != null + ? supportsExternalStream.value + : this.supportsExternalStream), + path: (path != null ? path.value : this.path), + pixelFormat: + (pixelFormat != null ? pixelFormat.value : this.pixelFormat), + level: (level != null ? level.value : this.level), + isAnamorphic: + (isAnamorphic != null ? isAnamorphic.value : this.isAnamorphic)); + } +} + +@JsonSerializable(explicitToJson: true) +class MediaUpdateInfoDto { + const MediaUpdateInfoDto({ + this.updates, + }); + + factory MediaUpdateInfoDto.fromJson(Map json) => + _$MediaUpdateInfoDtoFromJson(json); + + static const toJsonFactory = _$MediaUpdateInfoDtoToJson; + Map toJson() => _$MediaUpdateInfoDtoToJson(this); + + @JsonKey( + name: 'Updates', + includeIfNull: false, + defaultValue: []) + final List? updates; + static const fromJsonFactory = _$MediaUpdateInfoDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is MediaUpdateInfoDto && + (identical(other.updates, updates) || + const DeepCollectionEquality().equals(other.updates, updates))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(updates) ^ runtimeType.hashCode; +} + +extension $MediaUpdateInfoDtoExtension on MediaUpdateInfoDto { + MediaUpdateInfoDto copyWith({List? updates}) { + return MediaUpdateInfoDto(updates: updates ?? this.updates); + } + + MediaUpdateInfoDto copyWithWrapped( + {Wrapped?>? updates}) { + return MediaUpdateInfoDto( + updates: (updates != null ? updates.value : this.updates)); + } +} + +@JsonSerializable(explicitToJson: true) +class MediaUpdateInfoPathDto { + const MediaUpdateInfoPathDto({ + this.path, + this.updateType, + }); + + factory MediaUpdateInfoPathDto.fromJson(Map json) => + _$MediaUpdateInfoPathDtoFromJson(json); + + static const toJsonFactory = _$MediaUpdateInfoPathDtoToJson; + Map toJson() => _$MediaUpdateInfoPathDtoToJson(this); + + @JsonKey(name: 'Path', includeIfNull: false) + final String? path; + @JsonKey(name: 'UpdateType', includeIfNull: false) + final String? updateType; + static const fromJsonFactory = _$MediaUpdateInfoPathDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is MediaUpdateInfoPathDto && + (identical(other.path, path) || + const DeepCollectionEquality().equals(other.path, path)) && + (identical(other.updateType, updateType) || + const DeepCollectionEquality() + .equals(other.updateType, updateType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(path) ^ + const DeepCollectionEquality().hash(updateType) ^ + runtimeType.hashCode; +} + +extension $MediaUpdateInfoPathDtoExtension on MediaUpdateInfoPathDto { + MediaUpdateInfoPathDto copyWith({String? path, String? updateType}) { + return MediaUpdateInfoPathDto( + path: path ?? this.path, updateType: updateType ?? this.updateType); + } + + MediaUpdateInfoPathDto copyWithWrapped( + {Wrapped? path, Wrapped? updateType}) { + return MediaUpdateInfoPathDto( + path: (path != null ? path.value : this.path), + updateType: (updateType != null ? updateType.value : this.updateType)); + } +} + +@JsonSerializable(explicitToJson: true) +class MediaUrl { + const MediaUrl({ + this.url, + this.name, + }); + + factory MediaUrl.fromJson(Map json) => + _$MediaUrlFromJson(json); + + static const toJsonFactory = _$MediaUrlToJson; + Map toJson() => _$MediaUrlToJson(this); + + @JsonKey(name: 'Url', includeIfNull: false) + final String? url; + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + static const fromJsonFactory = _$MediaUrlFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is MediaUrl && + (identical(other.url, url) || + const DeepCollectionEquality().equals(other.url, url)) && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(url) ^ + const DeepCollectionEquality().hash(name) ^ + runtimeType.hashCode; +} + +extension $MediaUrlExtension on MediaUrl { + MediaUrl copyWith({String? url, String? name}) { + return MediaUrl(url: url ?? this.url, name: name ?? this.name); + } + + MediaUrl copyWithWrapped({Wrapped? url, Wrapped? name}) { + return MediaUrl( + url: (url != null ? url.value : this.url), + name: (name != null ? name.value : this.name)); + } +} + +@JsonSerializable(explicitToJson: true) +class MessageCommand { + const MessageCommand({ + this.header, + required this.text, + this.timeoutMs, + }); + + factory MessageCommand.fromJson(Map json) => + _$MessageCommandFromJson(json); + + static const toJsonFactory = _$MessageCommandToJson; + Map toJson() => _$MessageCommandToJson(this); + + @JsonKey(name: 'Header', includeIfNull: false) + final String? header; + @JsonKey(name: 'Text', includeIfNull: false) + final String text; + @JsonKey(name: 'TimeoutMs', includeIfNull: false) + final int? timeoutMs; + static const fromJsonFactory = _$MessageCommandFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is MessageCommand && + (identical(other.header, header) || + const DeepCollectionEquality().equals(other.header, header)) && + (identical(other.text, text) || + const DeepCollectionEquality().equals(other.text, text)) && + (identical(other.timeoutMs, timeoutMs) || + const DeepCollectionEquality() + .equals(other.timeoutMs, timeoutMs))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(header) ^ + const DeepCollectionEquality().hash(text) ^ + const DeepCollectionEquality().hash(timeoutMs) ^ + runtimeType.hashCode; +} + +extension $MessageCommandExtension on MessageCommand { + MessageCommand copyWith({String? header, String? text, int? timeoutMs}) { + return MessageCommand( + header: header ?? this.header, + text: text ?? this.text, + timeoutMs: timeoutMs ?? this.timeoutMs); + } + + MessageCommand copyWithWrapped( + {Wrapped? header, + Wrapped? text, + Wrapped? timeoutMs}) { + return MessageCommand( + header: (header != null ? header.value : this.header), + text: (text != null ? text.value : this.text), + timeoutMs: (timeoutMs != null ? timeoutMs.value : this.timeoutMs)); + } +} + +@JsonSerializable(explicitToJson: true) +class MetadataConfiguration { + const MetadataConfiguration({ + this.useFileCreationTimeForDateAdded, + }); + + factory MetadataConfiguration.fromJson(Map json) => + _$MetadataConfigurationFromJson(json); + + static const toJsonFactory = _$MetadataConfigurationToJson; + Map toJson() => _$MetadataConfigurationToJson(this); + + @JsonKey(name: 'UseFileCreationTimeForDateAdded', includeIfNull: false) + final bool? useFileCreationTimeForDateAdded; + static const fromJsonFactory = _$MetadataConfigurationFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is MetadataConfiguration && + (identical(other.useFileCreationTimeForDateAdded, + useFileCreationTimeForDateAdded) || + const DeepCollectionEquality().equals( + other.useFileCreationTimeForDateAdded, + useFileCreationTimeForDateAdded))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(useFileCreationTimeForDateAdded) ^ + runtimeType.hashCode; +} + +extension $MetadataConfigurationExtension on MetadataConfiguration { + MetadataConfiguration copyWith({bool? useFileCreationTimeForDateAdded}) { + return MetadataConfiguration( + useFileCreationTimeForDateAdded: useFileCreationTimeForDateAdded ?? + this.useFileCreationTimeForDateAdded); + } + + MetadataConfiguration copyWithWrapped( + {Wrapped? useFileCreationTimeForDateAdded}) { + return MetadataConfiguration( + useFileCreationTimeForDateAdded: + (useFileCreationTimeForDateAdded != null + ? useFileCreationTimeForDateAdded.value + : this.useFileCreationTimeForDateAdded)); + } +} + +@JsonSerializable(explicitToJson: true) +class MetadataEditorInfo { + const MetadataEditorInfo({ + this.parentalRatingOptions, + this.countries, + this.cultures, + this.externalIdInfos, + this.contentType, + this.contentTypeOptions, + }); + + factory MetadataEditorInfo.fromJson(Map json) => + _$MetadataEditorInfoFromJson(json); + + static const toJsonFactory = _$MetadataEditorInfoToJson; + Map toJson() => _$MetadataEditorInfoToJson(this); + + @JsonKey( + name: 'ParentalRatingOptions', + includeIfNull: false, + defaultValue: []) + final List? parentalRatingOptions; + @JsonKey( + name: 'Countries', includeIfNull: false, defaultValue: []) + final List? countries; + @JsonKey(name: 'Cultures', includeIfNull: false, defaultValue: []) + final List? cultures; + @JsonKey( + name: 'ExternalIdInfos', + includeIfNull: false, + defaultValue: []) + final List? externalIdInfos; + @JsonKey( + name: 'ContentType', + includeIfNull: false, + toJson: collectionTypeNullableToJson, + fromJson: collectionTypeNullableFromJson, + ) + final enums.CollectionType? contentType; + @JsonKey( + name: 'ContentTypeOptions', + includeIfNull: false, + defaultValue: []) + final List? contentTypeOptions; + static const fromJsonFactory = _$MetadataEditorInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is MetadataEditorInfo && + (identical(other.parentalRatingOptions, parentalRatingOptions) || + const DeepCollectionEquality().equals( + other.parentalRatingOptions, parentalRatingOptions)) && + (identical(other.countries, countries) || + const DeepCollectionEquality() + .equals(other.countries, countries)) && + (identical(other.cultures, cultures) || + const DeepCollectionEquality() + .equals(other.cultures, cultures)) && + (identical(other.externalIdInfos, externalIdInfos) || + const DeepCollectionEquality() + .equals(other.externalIdInfos, externalIdInfos)) && + (identical(other.contentType, contentType) || + const DeepCollectionEquality() + .equals(other.contentType, contentType)) && + (identical(other.contentTypeOptions, contentTypeOptions) || + const DeepCollectionEquality() + .equals(other.contentTypeOptions, contentTypeOptions))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(parentalRatingOptions) ^ + const DeepCollectionEquality().hash(countries) ^ + const DeepCollectionEquality().hash(cultures) ^ + const DeepCollectionEquality().hash(externalIdInfos) ^ + const DeepCollectionEquality().hash(contentType) ^ + const DeepCollectionEquality().hash(contentTypeOptions) ^ + runtimeType.hashCode; +} + +extension $MetadataEditorInfoExtension on MetadataEditorInfo { + MetadataEditorInfo copyWith( + {List? parentalRatingOptions, + List? countries, + List? cultures, + List? externalIdInfos, + enums.CollectionType? contentType, + List? contentTypeOptions}) { + return MetadataEditorInfo( + parentalRatingOptions: + parentalRatingOptions ?? this.parentalRatingOptions, + countries: countries ?? this.countries, + cultures: cultures ?? this.cultures, + externalIdInfos: externalIdInfos ?? this.externalIdInfos, + contentType: contentType ?? this.contentType, + contentTypeOptions: contentTypeOptions ?? this.contentTypeOptions); + } + + MetadataEditorInfo copyWithWrapped( + {Wrapped?>? parentalRatingOptions, + Wrapped?>? countries, + Wrapped?>? cultures, + Wrapped?>? externalIdInfos, + Wrapped? contentType, + Wrapped?>? contentTypeOptions}) { + return MetadataEditorInfo( + parentalRatingOptions: (parentalRatingOptions != null + ? parentalRatingOptions.value + : this.parentalRatingOptions), + countries: (countries != null ? countries.value : this.countries), + cultures: (cultures != null ? cultures.value : this.cultures), + externalIdInfos: (externalIdInfos != null + ? externalIdInfos.value + : this.externalIdInfos), + contentType: + (contentType != null ? contentType.value : this.contentType), + contentTypeOptions: (contentTypeOptions != null + ? contentTypeOptions.value + : this.contentTypeOptions)); + } +} + +@JsonSerializable(explicitToJson: true) +class MetadataOptions { + const MetadataOptions({ + this.itemType, + this.disabledMetadataSavers, + this.localMetadataReaderOrder, + this.disabledMetadataFetchers, + this.metadataFetcherOrder, + this.disabledImageFetchers, + this.imageFetcherOrder, + }); + + factory MetadataOptions.fromJson(Map json) => + _$MetadataOptionsFromJson(json); + + static const toJsonFactory = _$MetadataOptionsToJson; + Map toJson() => _$MetadataOptionsToJson(this); + + @JsonKey(name: 'ItemType', includeIfNull: false) + final String? itemType; + @JsonKey( + name: 'DisabledMetadataSavers', + includeIfNull: false, + defaultValue: []) + final List? disabledMetadataSavers; + @JsonKey( + name: 'LocalMetadataReaderOrder', + includeIfNull: false, + defaultValue: []) + final List? localMetadataReaderOrder; + @JsonKey( + name: 'DisabledMetadataFetchers', + includeIfNull: false, + defaultValue: []) + final List? disabledMetadataFetchers; + @JsonKey( + name: 'MetadataFetcherOrder', + includeIfNull: false, + defaultValue: []) + final List? metadataFetcherOrder; + @JsonKey( + name: 'DisabledImageFetchers', + includeIfNull: false, + defaultValue: []) + final List? disabledImageFetchers; + @JsonKey( + name: 'ImageFetcherOrder', includeIfNull: false, defaultValue: []) + final List? imageFetcherOrder; + static const fromJsonFactory = _$MetadataOptionsFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is MetadataOptions && + (identical(other.itemType, itemType) || + const DeepCollectionEquality() + .equals(other.itemType, itemType)) && + (identical(other.disabledMetadataSavers, disabledMetadataSavers) || + const DeepCollectionEquality().equals( + other.disabledMetadataSavers, disabledMetadataSavers)) && + (identical( + other.localMetadataReaderOrder, localMetadataReaderOrder) || + const DeepCollectionEquality().equals( + other.localMetadataReaderOrder, + localMetadataReaderOrder)) && + (identical( + other.disabledMetadataFetchers, disabledMetadataFetchers) || + const DeepCollectionEquality().equals( + other.disabledMetadataFetchers, + disabledMetadataFetchers)) && + (identical(other.metadataFetcherOrder, metadataFetcherOrder) || + const DeepCollectionEquality().equals( + other.metadataFetcherOrder, metadataFetcherOrder)) && + (identical(other.disabledImageFetchers, disabledImageFetchers) || + const DeepCollectionEquality().equals( + other.disabledImageFetchers, disabledImageFetchers)) && + (identical(other.imageFetcherOrder, imageFetcherOrder) || + const DeepCollectionEquality() + .equals(other.imageFetcherOrder, imageFetcherOrder))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(itemType) ^ + const DeepCollectionEquality().hash(disabledMetadataSavers) ^ + const DeepCollectionEquality().hash(localMetadataReaderOrder) ^ + const DeepCollectionEquality().hash(disabledMetadataFetchers) ^ + const DeepCollectionEquality().hash(metadataFetcherOrder) ^ + const DeepCollectionEquality().hash(disabledImageFetchers) ^ + const DeepCollectionEquality().hash(imageFetcherOrder) ^ + runtimeType.hashCode; +} + +extension $MetadataOptionsExtension on MetadataOptions { + MetadataOptions copyWith( + {String? itemType, + List? disabledMetadataSavers, + List? localMetadataReaderOrder, + List? disabledMetadataFetchers, + List? metadataFetcherOrder, + List? disabledImageFetchers, + List? imageFetcherOrder}) { + return MetadataOptions( + itemType: itemType ?? this.itemType, + disabledMetadataSavers: + disabledMetadataSavers ?? this.disabledMetadataSavers, + localMetadataReaderOrder: + localMetadataReaderOrder ?? this.localMetadataReaderOrder, + disabledMetadataFetchers: + disabledMetadataFetchers ?? this.disabledMetadataFetchers, + metadataFetcherOrder: metadataFetcherOrder ?? this.metadataFetcherOrder, + disabledImageFetchers: + disabledImageFetchers ?? this.disabledImageFetchers, + imageFetcherOrder: imageFetcherOrder ?? this.imageFetcherOrder); + } + + MetadataOptions copyWithWrapped( + {Wrapped? itemType, + Wrapped?>? disabledMetadataSavers, + Wrapped?>? localMetadataReaderOrder, + Wrapped?>? disabledMetadataFetchers, + Wrapped?>? metadataFetcherOrder, + Wrapped?>? disabledImageFetchers, + Wrapped?>? imageFetcherOrder}) { + return MetadataOptions( + itemType: (itemType != null ? itemType.value : this.itemType), + disabledMetadataSavers: (disabledMetadataSavers != null + ? disabledMetadataSavers.value + : this.disabledMetadataSavers), + localMetadataReaderOrder: (localMetadataReaderOrder != null + ? localMetadataReaderOrder.value + : this.localMetadataReaderOrder), + disabledMetadataFetchers: (disabledMetadataFetchers != null + ? disabledMetadataFetchers.value + : this.disabledMetadataFetchers), + metadataFetcherOrder: (metadataFetcherOrder != null + ? metadataFetcherOrder.value + : this.metadataFetcherOrder), + disabledImageFetchers: (disabledImageFetchers != null + ? disabledImageFetchers.value + : this.disabledImageFetchers), + imageFetcherOrder: (imageFetcherOrder != null + ? imageFetcherOrder.value + : this.imageFetcherOrder)); + } +} + +@JsonSerializable(explicitToJson: true) +class MovePlaylistItemRequestDto { + const MovePlaylistItemRequestDto({ + this.playlistItemId, + this.newIndex, + }); + + factory MovePlaylistItemRequestDto.fromJson(Map json) => + _$MovePlaylistItemRequestDtoFromJson(json); + + static const toJsonFactory = _$MovePlaylistItemRequestDtoToJson; + Map toJson() => _$MovePlaylistItemRequestDtoToJson(this); + + @JsonKey(name: 'PlaylistItemId', includeIfNull: false) + final String? playlistItemId; + @JsonKey(name: 'NewIndex', includeIfNull: false) + final int? newIndex; + static const fromJsonFactory = _$MovePlaylistItemRequestDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is MovePlaylistItemRequestDto && + (identical(other.playlistItemId, playlistItemId) || + const DeepCollectionEquality() + .equals(other.playlistItemId, playlistItemId)) && + (identical(other.newIndex, newIndex) || + const DeepCollectionEquality() + .equals(other.newIndex, newIndex))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(playlistItemId) ^ + const DeepCollectionEquality().hash(newIndex) ^ + runtimeType.hashCode; +} + +extension $MovePlaylistItemRequestDtoExtension on MovePlaylistItemRequestDto { + MovePlaylistItemRequestDto copyWith({String? playlistItemId, int? newIndex}) { + return MovePlaylistItemRequestDto( + playlistItemId: playlistItemId ?? this.playlistItemId, + newIndex: newIndex ?? this.newIndex); + } + + MovePlaylistItemRequestDto copyWithWrapped( + {Wrapped? playlistItemId, Wrapped? newIndex}) { + return MovePlaylistItemRequestDto( + playlistItemId: (playlistItemId != null + ? playlistItemId.value + : this.playlistItemId), + newIndex: (newIndex != null ? newIndex.value : this.newIndex)); + } +} + +@JsonSerializable(explicitToJson: true) +class MovieInfo { + const MovieInfo({ + this.name, + this.originalTitle, + this.path, + this.metadataLanguage, + this.metadataCountryCode, + this.providerIds, + this.year, + this.indexNumber, + this.parentIndexNumber, + this.premiereDate, + this.isAutomated, + }); + + factory MovieInfo.fromJson(Map json) => + _$MovieInfoFromJson(json); + + static const toJsonFactory = _$MovieInfoToJson; + Map toJson() => _$MovieInfoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'OriginalTitle', includeIfNull: false) + final String? originalTitle; + @JsonKey(name: 'Path', includeIfNull: false) + final String? path; + @JsonKey(name: 'MetadataLanguage', includeIfNull: false) + final String? metadataLanguage; + @JsonKey(name: 'MetadataCountryCode', includeIfNull: false) + final String? metadataCountryCode; + @JsonKey(name: 'ProviderIds', includeIfNull: false) + final Map? providerIds; + @JsonKey(name: 'Year', includeIfNull: false) + final int? year; + @JsonKey(name: 'IndexNumber', includeIfNull: false) + final int? indexNumber; + @JsonKey(name: 'ParentIndexNumber', includeIfNull: false) + final int? parentIndexNumber; + @JsonKey(name: 'PremiereDate', includeIfNull: false) + final DateTime? premiereDate; + @JsonKey(name: 'IsAutomated', includeIfNull: false) + final bool? isAutomated; + static const fromJsonFactory = _$MovieInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is MovieInfo && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.originalTitle, originalTitle) || + const DeepCollectionEquality() + .equals(other.originalTitle, originalTitle)) && + (identical(other.path, path) || + const DeepCollectionEquality().equals(other.path, path)) && + (identical(other.metadataLanguage, metadataLanguage) || + const DeepCollectionEquality() + .equals(other.metadataLanguage, metadataLanguage)) && + (identical(other.metadataCountryCode, metadataCountryCode) || + const DeepCollectionEquality() + .equals(other.metadataCountryCode, metadataCountryCode)) && + (identical(other.providerIds, providerIds) || + const DeepCollectionEquality() + .equals(other.providerIds, providerIds)) && + (identical(other.year, year) || + const DeepCollectionEquality().equals(other.year, year)) && + (identical(other.indexNumber, indexNumber) || + const DeepCollectionEquality() + .equals(other.indexNumber, indexNumber)) && + (identical(other.parentIndexNumber, parentIndexNumber) || + const DeepCollectionEquality() + .equals(other.parentIndexNumber, parentIndexNumber)) && + (identical(other.premiereDate, premiereDate) || + const DeepCollectionEquality() + .equals(other.premiereDate, premiereDate)) && + (identical(other.isAutomated, isAutomated) || + const DeepCollectionEquality() + .equals(other.isAutomated, isAutomated))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(originalTitle) ^ + const DeepCollectionEquality().hash(path) ^ + const DeepCollectionEquality().hash(metadataLanguage) ^ + const DeepCollectionEquality().hash(metadataCountryCode) ^ + const DeepCollectionEquality().hash(providerIds) ^ + const DeepCollectionEquality().hash(year) ^ + const DeepCollectionEquality().hash(indexNumber) ^ + const DeepCollectionEquality().hash(parentIndexNumber) ^ + const DeepCollectionEquality().hash(premiereDate) ^ + const DeepCollectionEquality().hash(isAutomated) ^ + runtimeType.hashCode; +} + +extension $MovieInfoExtension on MovieInfo { + MovieInfo copyWith( + {String? name, + String? originalTitle, + String? path, + String? metadataLanguage, + String? metadataCountryCode, + Map? providerIds, + int? year, + int? indexNumber, + int? parentIndexNumber, + DateTime? premiereDate, + bool? isAutomated}) { + return MovieInfo( + name: name ?? this.name, + originalTitle: originalTitle ?? this.originalTitle, + path: path ?? this.path, + metadataLanguage: metadataLanguage ?? this.metadataLanguage, + metadataCountryCode: metadataCountryCode ?? this.metadataCountryCode, + providerIds: providerIds ?? this.providerIds, + year: year ?? this.year, + indexNumber: indexNumber ?? this.indexNumber, + parentIndexNumber: parentIndexNumber ?? this.parentIndexNumber, + premiereDate: premiereDate ?? this.premiereDate, + isAutomated: isAutomated ?? this.isAutomated); + } + + MovieInfo copyWithWrapped( + {Wrapped? name, + Wrapped? originalTitle, + Wrapped? path, + Wrapped? metadataLanguage, + Wrapped? metadataCountryCode, + Wrapped?>? providerIds, + Wrapped? year, + Wrapped? indexNumber, + Wrapped? parentIndexNumber, + Wrapped? premiereDate, + Wrapped? isAutomated}) { + return MovieInfo( + name: (name != null ? name.value : this.name), + originalTitle: + (originalTitle != null ? originalTitle.value : this.originalTitle), + path: (path != null ? path.value : this.path), + metadataLanguage: (metadataLanguage != null + ? metadataLanguage.value + : this.metadataLanguage), + metadataCountryCode: (metadataCountryCode != null + ? metadataCountryCode.value + : this.metadataCountryCode), + providerIds: + (providerIds != null ? providerIds.value : this.providerIds), + year: (year != null ? year.value : this.year), + indexNumber: + (indexNumber != null ? indexNumber.value : this.indexNumber), + parentIndexNumber: (parentIndexNumber != null + ? parentIndexNumber.value + : this.parentIndexNumber), + premiereDate: + (premiereDate != null ? premiereDate.value : this.premiereDate), + isAutomated: + (isAutomated != null ? isAutomated.value : this.isAutomated)); + } +} + +@JsonSerializable(explicitToJson: true) +class MovieInfoRemoteSearchQuery { + const MovieInfoRemoteSearchQuery({ + this.searchInfo, + this.itemId, + this.searchProviderName, + this.includeDisabledProviders, + }); + + factory MovieInfoRemoteSearchQuery.fromJson(Map json) => + _$MovieInfoRemoteSearchQueryFromJson(json); + + static const toJsonFactory = _$MovieInfoRemoteSearchQueryToJson; + Map toJson() => _$MovieInfoRemoteSearchQueryToJson(this); + + @JsonKey(name: 'SearchInfo', includeIfNull: false) + final MovieInfo? searchInfo; + @JsonKey(name: 'ItemId', includeIfNull: false) + final String? itemId; + @JsonKey(name: 'SearchProviderName', includeIfNull: false) + final String? searchProviderName; + @JsonKey(name: 'IncludeDisabledProviders', includeIfNull: false) + final bool? includeDisabledProviders; + static const fromJsonFactory = _$MovieInfoRemoteSearchQueryFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is MovieInfoRemoteSearchQuery && + (identical(other.searchInfo, searchInfo) || + const DeepCollectionEquality() + .equals(other.searchInfo, searchInfo)) && + (identical(other.itemId, itemId) || + const DeepCollectionEquality().equals(other.itemId, itemId)) && + (identical(other.searchProviderName, searchProviderName) || + const DeepCollectionEquality() + .equals(other.searchProviderName, searchProviderName)) && + (identical( + other.includeDisabledProviders, includeDisabledProviders) || + const DeepCollectionEquality().equals( + other.includeDisabledProviders, includeDisabledProviders))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(searchInfo) ^ + const DeepCollectionEquality().hash(itemId) ^ + const DeepCollectionEquality().hash(searchProviderName) ^ + const DeepCollectionEquality().hash(includeDisabledProviders) ^ + runtimeType.hashCode; +} + +extension $MovieInfoRemoteSearchQueryExtension on MovieInfoRemoteSearchQuery { + MovieInfoRemoteSearchQuery copyWith( + {MovieInfo? searchInfo, + String? itemId, + String? searchProviderName, + bool? includeDisabledProviders}) { + return MovieInfoRemoteSearchQuery( + searchInfo: searchInfo ?? this.searchInfo, + itemId: itemId ?? this.itemId, + searchProviderName: searchProviderName ?? this.searchProviderName, + includeDisabledProviders: + includeDisabledProviders ?? this.includeDisabledProviders); + } + + MovieInfoRemoteSearchQuery copyWithWrapped( + {Wrapped? searchInfo, + Wrapped? itemId, + Wrapped? searchProviderName, + Wrapped? includeDisabledProviders}) { + return MovieInfoRemoteSearchQuery( + searchInfo: (searchInfo != null ? searchInfo.value : this.searchInfo), + itemId: (itemId != null ? itemId.value : this.itemId), + searchProviderName: (searchProviderName != null + ? searchProviderName.value + : this.searchProviderName), + includeDisabledProviders: (includeDisabledProviders != null + ? includeDisabledProviders.value + : this.includeDisabledProviders)); + } +} + +@JsonSerializable(explicitToJson: true) +class MusicVideoInfo { + const MusicVideoInfo({ + this.name, + this.originalTitle, + this.path, + this.metadataLanguage, + this.metadataCountryCode, + this.providerIds, + this.year, + this.indexNumber, + this.parentIndexNumber, + this.premiereDate, + this.isAutomated, + this.artists, + }); + + factory MusicVideoInfo.fromJson(Map json) => + _$MusicVideoInfoFromJson(json); + + static const toJsonFactory = _$MusicVideoInfoToJson; + Map toJson() => _$MusicVideoInfoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'OriginalTitle', includeIfNull: false) + final String? originalTitle; + @JsonKey(name: 'Path', includeIfNull: false) + final String? path; + @JsonKey(name: 'MetadataLanguage', includeIfNull: false) + final String? metadataLanguage; + @JsonKey(name: 'MetadataCountryCode', includeIfNull: false) + final String? metadataCountryCode; + @JsonKey(name: 'ProviderIds', includeIfNull: false) + final Map? providerIds; + @JsonKey(name: 'Year', includeIfNull: false) + final int? year; + @JsonKey(name: 'IndexNumber', includeIfNull: false) + final int? indexNumber; + @JsonKey(name: 'ParentIndexNumber', includeIfNull: false) + final int? parentIndexNumber; + @JsonKey(name: 'PremiereDate', includeIfNull: false) + final DateTime? premiereDate; + @JsonKey(name: 'IsAutomated', includeIfNull: false) + final bool? isAutomated; + @JsonKey(name: 'Artists', includeIfNull: false, defaultValue: []) + final List? artists; + static const fromJsonFactory = _$MusicVideoInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is MusicVideoInfo && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.originalTitle, originalTitle) || + const DeepCollectionEquality() + .equals(other.originalTitle, originalTitle)) && + (identical(other.path, path) || + const DeepCollectionEquality().equals(other.path, path)) && + (identical(other.metadataLanguage, metadataLanguage) || + const DeepCollectionEquality() + .equals(other.metadataLanguage, metadataLanguage)) && + (identical(other.metadataCountryCode, metadataCountryCode) || + const DeepCollectionEquality() + .equals(other.metadataCountryCode, metadataCountryCode)) && + (identical(other.providerIds, providerIds) || + const DeepCollectionEquality() + .equals(other.providerIds, providerIds)) && + (identical(other.year, year) || + const DeepCollectionEquality().equals(other.year, year)) && + (identical(other.indexNumber, indexNumber) || + const DeepCollectionEquality() + .equals(other.indexNumber, indexNumber)) && + (identical(other.parentIndexNumber, parentIndexNumber) || + const DeepCollectionEquality() + .equals(other.parentIndexNumber, parentIndexNumber)) && + (identical(other.premiereDate, premiereDate) || + const DeepCollectionEquality() + .equals(other.premiereDate, premiereDate)) && + (identical(other.isAutomated, isAutomated) || + const DeepCollectionEquality() + .equals(other.isAutomated, isAutomated)) && + (identical(other.artists, artists) || + const DeepCollectionEquality().equals(other.artists, artists))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(originalTitle) ^ + const DeepCollectionEquality().hash(path) ^ + const DeepCollectionEquality().hash(metadataLanguage) ^ + const DeepCollectionEquality().hash(metadataCountryCode) ^ + const DeepCollectionEquality().hash(providerIds) ^ + const DeepCollectionEquality().hash(year) ^ + const DeepCollectionEquality().hash(indexNumber) ^ + const DeepCollectionEquality().hash(parentIndexNumber) ^ + const DeepCollectionEquality().hash(premiereDate) ^ + const DeepCollectionEquality().hash(isAutomated) ^ + const DeepCollectionEquality().hash(artists) ^ + runtimeType.hashCode; +} + +extension $MusicVideoInfoExtension on MusicVideoInfo { + MusicVideoInfo copyWith( + {String? name, + String? originalTitle, + String? path, + String? metadataLanguage, + String? metadataCountryCode, + Map? providerIds, + int? year, + int? indexNumber, + int? parentIndexNumber, + DateTime? premiereDate, + bool? isAutomated, + List? artists}) { + return MusicVideoInfo( + name: name ?? this.name, + originalTitle: originalTitle ?? this.originalTitle, + path: path ?? this.path, + metadataLanguage: metadataLanguage ?? this.metadataLanguage, + metadataCountryCode: metadataCountryCode ?? this.metadataCountryCode, + providerIds: providerIds ?? this.providerIds, + year: year ?? this.year, + indexNumber: indexNumber ?? this.indexNumber, + parentIndexNumber: parentIndexNumber ?? this.parentIndexNumber, + premiereDate: premiereDate ?? this.premiereDate, + isAutomated: isAutomated ?? this.isAutomated, + artists: artists ?? this.artists); + } + + MusicVideoInfo copyWithWrapped( + {Wrapped? name, + Wrapped? originalTitle, + Wrapped? path, + Wrapped? metadataLanguage, + Wrapped? metadataCountryCode, + Wrapped?>? providerIds, + Wrapped? year, + Wrapped? indexNumber, + Wrapped? parentIndexNumber, + Wrapped? premiereDate, + Wrapped? isAutomated, + Wrapped?>? artists}) { + return MusicVideoInfo( + name: (name != null ? name.value : this.name), + originalTitle: + (originalTitle != null ? originalTitle.value : this.originalTitle), + path: (path != null ? path.value : this.path), + metadataLanguage: (metadataLanguage != null + ? metadataLanguage.value + : this.metadataLanguage), + metadataCountryCode: (metadataCountryCode != null + ? metadataCountryCode.value + : this.metadataCountryCode), + providerIds: + (providerIds != null ? providerIds.value : this.providerIds), + year: (year != null ? year.value : this.year), + indexNumber: + (indexNumber != null ? indexNumber.value : this.indexNumber), + parentIndexNumber: (parentIndexNumber != null + ? parentIndexNumber.value + : this.parentIndexNumber), + premiereDate: + (premiereDate != null ? premiereDate.value : this.premiereDate), + isAutomated: + (isAutomated != null ? isAutomated.value : this.isAutomated), + artists: (artists != null ? artists.value : this.artists)); + } +} + +@JsonSerializable(explicitToJson: true) +class MusicVideoInfoRemoteSearchQuery { + const MusicVideoInfoRemoteSearchQuery({ + this.searchInfo, + this.itemId, + this.searchProviderName, + this.includeDisabledProviders, + }); + + factory MusicVideoInfoRemoteSearchQuery.fromJson(Map json) => + _$MusicVideoInfoRemoteSearchQueryFromJson(json); + + static const toJsonFactory = _$MusicVideoInfoRemoteSearchQueryToJson; + Map toJson() => + _$MusicVideoInfoRemoteSearchQueryToJson(this); + + @JsonKey(name: 'SearchInfo', includeIfNull: false) + final MusicVideoInfo? searchInfo; + @JsonKey(name: 'ItemId', includeIfNull: false) + final String? itemId; + @JsonKey(name: 'SearchProviderName', includeIfNull: false) + final String? searchProviderName; + @JsonKey(name: 'IncludeDisabledProviders', includeIfNull: false) + final bool? includeDisabledProviders; + static const fromJsonFactory = _$MusicVideoInfoRemoteSearchQueryFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is MusicVideoInfoRemoteSearchQuery && + (identical(other.searchInfo, searchInfo) || + const DeepCollectionEquality() + .equals(other.searchInfo, searchInfo)) && + (identical(other.itemId, itemId) || + const DeepCollectionEquality().equals(other.itemId, itemId)) && + (identical(other.searchProviderName, searchProviderName) || + const DeepCollectionEquality() + .equals(other.searchProviderName, searchProviderName)) && + (identical( + other.includeDisabledProviders, includeDisabledProviders) || + const DeepCollectionEquality().equals( + other.includeDisabledProviders, includeDisabledProviders))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(searchInfo) ^ + const DeepCollectionEquality().hash(itemId) ^ + const DeepCollectionEquality().hash(searchProviderName) ^ + const DeepCollectionEquality().hash(includeDisabledProviders) ^ + runtimeType.hashCode; +} + +extension $MusicVideoInfoRemoteSearchQueryExtension + on MusicVideoInfoRemoteSearchQuery { + MusicVideoInfoRemoteSearchQuery copyWith( + {MusicVideoInfo? searchInfo, + String? itemId, + String? searchProviderName, + bool? includeDisabledProviders}) { + return MusicVideoInfoRemoteSearchQuery( + searchInfo: searchInfo ?? this.searchInfo, + itemId: itemId ?? this.itemId, + searchProviderName: searchProviderName ?? this.searchProviderName, + includeDisabledProviders: + includeDisabledProviders ?? this.includeDisabledProviders); + } + + MusicVideoInfoRemoteSearchQuery copyWithWrapped( + {Wrapped? searchInfo, + Wrapped? itemId, + Wrapped? searchProviderName, + Wrapped? includeDisabledProviders}) { + return MusicVideoInfoRemoteSearchQuery( + searchInfo: (searchInfo != null ? searchInfo.value : this.searchInfo), + itemId: (itemId != null ? itemId.value : this.itemId), + searchProviderName: (searchProviderName != null + ? searchProviderName.value + : this.searchProviderName), + includeDisabledProviders: (includeDisabledProviders != null + ? includeDisabledProviders.value + : this.includeDisabledProviders)); + } +} + +@JsonSerializable(explicitToJson: true) +class NameGuidPair { + const NameGuidPair({ + this.name, + this.id, + }); + + factory NameGuidPair.fromJson(Map json) => + _$NameGuidPairFromJson(json); + + static const toJsonFactory = _$NameGuidPairToJson; + Map toJson() => _$NameGuidPairToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + static const fromJsonFactory = _$NameGuidPairFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is NameGuidPair && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(id) ^ + runtimeType.hashCode; +} + +extension $NameGuidPairExtension on NameGuidPair { + NameGuidPair copyWith({String? name, String? id}) { + return NameGuidPair(name: name ?? this.name, id: id ?? this.id); + } + + NameGuidPair copyWithWrapped({Wrapped? name, Wrapped? id}) { + return NameGuidPair( + name: (name != null ? name.value : this.name), + id: (id != null ? id.value : this.id)); + } +} + +@JsonSerializable(explicitToJson: true) +class NameIdPair { + const NameIdPair({ + this.name, + this.id, + }); + + factory NameIdPair.fromJson(Map json) => + _$NameIdPairFromJson(json); + + static const toJsonFactory = _$NameIdPairToJson; + Map toJson() => _$NameIdPairToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + static const fromJsonFactory = _$NameIdPairFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is NameIdPair && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(id) ^ + runtimeType.hashCode; +} + +extension $NameIdPairExtension on NameIdPair { + NameIdPair copyWith({String? name, String? id}) { + return NameIdPair(name: name ?? this.name, id: id ?? this.id); + } + + NameIdPair copyWithWrapped({Wrapped? name, Wrapped? id}) { + return NameIdPair( + name: (name != null ? name.value : this.name), + id: (id != null ? id.value : this.id)); + } +} + +@JsonSerializable(explicitToJson: true) +class NameValuePair { + const NameValuePair({ + this.name, + this.$Value, + }); + + factory NameValuePair.fromJson(Map json) => + _$NameValuePairFromJson(json); + + static const toJsonFactory = _$NameValuePairToJson; + Map toJson() => _$NameValuePairToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'Value', includeIfNull: false) + final String? $Value; + static const fromJsonFactory = _$NameValuePairFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is NameValuePair && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.$Value, $Value) || + const DeepCollectionEquality().equals(other.$Value, $Value))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash($Value) ^ + runtimeType.hashCode; +} + +extension $NameValuePairExtension on NameValuePair { + NameValuePair copyWith({String? name, String? $Value}) { + return NameValuePair( + name: name ?? this.name, $Value: $Value ?? this.$Value); + } + + NameValuePair copyWithWrapped( + {Wrapped? name, Wrapped? $Value}) { + return NameValuePair( + name: (name != null ? name.value : this.name), + $Value: ($Value != null ? $Value.value : this.$Value)); + } +} + +@JsonSerializable(explicitToJson: true) +class NetworkConfiguration { + const NetworkConfiguration({ + this.baseUrl, + this.enableHttps, + this.requireHttps, + this.certificatePath, + this.certificatePassword, + this.internalHttpPort, + this.internalHttpsPort, + this.publicHttpPort, + this.publicHttpsPort, + this.autoDiscovery, + this.enableUPnP, + this.enableIPv4, + this.enableIPv6, + this.enableRemoteAccess, + this.localNetworkSubnets, + this.localNetworkAddresses, + this.knownProxies, + this.ignoreVirtualInterfaces, + this.virtualInterfaceNames, + this.enablePublishedServerUriByRequest, + this.publishedServerUriBySubnet, + this.remoteIPFilter, + this.isRemoteIPFilterBlacklist, + }); + + factory NetworkConfiguration.fromJson(Map json) => + _$NetworkConfigurationFromJson(json); + + static const toJsonFactory = _$NetworkConfigurationToJson; + Map toJson() => _$NetworkConfigurationToJson(this); + + @JsonKey(name: 'BaseUrl', includeIfNull: false) + final String? baseUrl; + @JsonKey(name: 'EnableHttps', includeIfNull: false) + final bool? enableHttps; + @JsonKey(name: 'RequireHttps', includeIfNull: false) + final bool? requireHttps; + @JsonKey(name: 'CertificatePath', includeIfNull: false) + final String? certificatePath; + @JsonKey(name: 'CertificatePassword', includeIfNull: false) + final String? certificatePassword; + @JsonKey(name: 'InternalHttpPort', includeIfNull: false) + final int? internalHttpPort; + @JsonKey(name: 'InternalHttpsPort', includeIfNull: false) + final int? internalHttpsPort; + @JsonKey(name: 'PublicHttpPort', includeIfNull: false) + final int? publicHttpPort; + @JsonKey(name: 'PublicHttpsPort', includeIfNull: false) + final int? publicHttpsPort; + @JsonKey(name: 'AutoDiscovery', includeIfNull: false) + final bool? autoDiscovery; + @JsonKey(name: 'EnableUPnP', includeIfNull: false) + final bool? enableUPnP; + @JsonKey(name: 'EnableIPv4', includeIfNull: false) + final bool? enableIPv4; + @JsonKey(name: 'EnableIPv6', includeIfNull: false) + final bool? enableIPv6; + @JsonKey(name: 'EnableRemoteAccess', includeIfNull: false) + final bool? enableRemoteAccess; + @JsonKey( + name: 'LocalNetworkSubnets', + includeIfNull: false, + defaultValue: []) + final List? localNetworkSubnets; + @JsonKey( + name: 'LocalNetworkAddresses', + includeIfNull: false, + defaultValue: []) + final List? localNetworkAddresses; + @JsonKey(name: 'KnownProxies', includeIfNull: false, defaultValue: []) + final List? knownProxies; + @JsonKey(name: 'IgnoreVirtualInterfaces', includeIfNull: false) + final bool? ignoreVirtualInterfaces; + @JsonKey( + name: 'VirtualInterfaceNames', + includeIfNull: false, + defaultValue: []) + final List? virtualInterfaceNames; + @JsonKey(name: 'EnablePublishedServerUriByRequest', includeIfNull: false) + final bool? enablePublishedServerUriByRequest; + @JsonKey( + name: 'PublishedServerUriBySubnet', + includeIfNull: false, + defaultValue: []) + final List? publishedServerUriBySubnet; + @JsonKey( + name: 'RemoteIPFilter', includeIfNull: false, defaultValue: []) + final List? remoteIPFilter; + @JsonKey(name: 'IsRemoteIPFilterBlacklist', includeIfNull: false) + final bool? isRemoteIPFilterBlacklist; + static const fromJsonFactory = _$NetworkConfigurationFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is NetworkConfiguration && + (identical(other.baseUrl, baseUrl) || + const DeepCollectionEquality() + .equals(other.baseUrl, baseUrl)) && + (identical(other.enableHttps, enableHttps) || + const DeepCollectionEquality() + .equals(other.enableHttps, enableHttps)) && + (identical(other.requireHttps, requireHttps) || + const DeepCollectionEquality() + .equals(other.requireHttps, requireHttps)) && + (identical(other.certificatePath, certificatePath) || + const DeepCollectionEquality() + .equals(other.certificatePath, certificatePath)) && + (identical(other.certificatePassword, certificatePassword) || + const DeepCollectionEquality() + .equals(other.certificatePassword, certificatePassword)) && + (identical(other.internalHttpPort, internalHttpPort) || + const DeepCollectionEquality() + .equals(other.internalHttpPort, internalHttpPort)) && + (identical(other.internalHttpsPort, internalHttpsPort) || + const DeepCollectionEquality() + .equals(other.internalHttpsPort, internalHttpsPort)) && + (identical(other.publicHttpPort, publicHttpPort) || + const DeepCollectionEquality() + .equals(other.publicHttpPort, publicHttpPort)) && + (identical(other.publicHttpsPort, publicHttpsPort) || + const DeepCollectionEquality() + .equals(other.publicHttpsPort, publicHttpsPort)) && + (identical(other.autoDiscovery, autoDiscovery) || + const DeepCollectionEquality() + .equals(other.autoDiscovery, autoDiscovery)) && + (identical(other.enableUPnP, enableUPnP) || + const DeepCollectionEquality() + .equals(other.enableUPnP, enableUPnP)) && + (identical(other.enableIPv4, enableIPv4) || + const DeepCollectionEquality() + .equals(other.enableIPv4, enableIPv4)) && + (identical(other.enableIPv6, enableIPv6) || + const DeepCollectionEquality() + .equals(other.enableIPv6, enableIPv6)) && + (identical(other.enableRemoteAccess, enableRemoteAccess) || + const DeepCollectionEquality() + .equals(other.enableRemoteAccess, enableRemoteAccess)) && + (identical(other.localNetworkSubnets, localNetworkSubnets) || + const DeepCollectionEquality() + .equals(other.localNetworkSubnets, localNetworkSubnets)) && + (identical(other.localNetworkAddresses, localNetworkAddresses) || + const DeepCollectionEquality().equals( + other.localNetworkAddresses, localNetworkAddresses)) && + (identical(other.knownProxies, knownProxies) || + const DeepCollectionEquality() + .equals(other.knownProxies, knownProxies)) && + (identical(other.ignoreVirtualInterfaces, ignoreVirtualInterfaces) || + const DeepCollectionEquality().equals( + other.ignoreVirtualInterfaces, ignoreVirtualInterfaces)) && + (identical(other.virtualInterfaceNames, virtualInterfaceNames) || + const DeepCollectionEquality().equals( + other.virtualInterfaceNames, virtualInterfaceNames)) && + (identical(other.enablePublishedServerUriByRequest, enablePublishedServerUriByRequest) || + const DeepCollectionEquality().equals( + other.enablePublishedServerUriByRequest, + enablePublishedServerUriByRequest)) && + (identical(other.publishedServerUriBySubnet, publishedServerUriBySubnet) || const DeepCollectionEquality().equals(other.publishedServerUriBySubnet, publishedServerUriBySubnet)) && + (identical(other.remoteIPFilter, remoteIPFilter) || const DeepCollectionEquality().equals(other.remoteIPFilter, remoteIPFilter)) && + (identical(other.isRemoteIPFilterBlacklist, isRemoteIPFilterBlacklist) || const DeepCollectionEquality().equals(other.isRemoteIPFilterBlacklist, isRemoteIPFilterBlacklist))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(baseUrl) ^ + const DeepCollectionEquality().hash(enableHttps) ^ + const DeepCollectionEquality().hash(requireHttps) ^ + const DeepCollectionEquality().hash(certificatePath) ^ + const DeepCollectionEquality().hash(certificatePassword) ^ + const DeepCollectionEquality().hash(internalHttpPort) ^ + const DeepCollectionEquality().hash(internalHttpsPort) ^ + const DeepCollectionEquality().hash(publicHttpPort) ^ + const DeepCollectionEquality().hash(publicHttpsPort) ^ + const DeepCollectionEquality().hash(autoDiscovery) ^ + const DeepCollectionEquality().hash(enableUPnP) ^ + const DeepCollectionEquality().hash(enableIPv4) ^ + const DeepCollectionEquality().hash(enableIPv6) ^ + const DeepCollectionEquality().hash(enableRemoteAccess) ^ + const DeepCollectionEquality().hash(localNetworkSubnets) ^ + const DeepCollectionEquality().hash(localNetworkAddresses) ^ + const DeepCollectionEquality().hash(knownProxies) ^ + const DeepCollectionEquality().hash(ignoreVirtualInterfaces) ^ + const DeepCollectionEquality().hash(virtualInterfaceNames) ^ + const DeepCollectionEquality().hash(enablePublishedServerUriByRequest) ^ + const DeepCollectionEquality().hash(publishedServerUriBySubnet) ^ + const DeepCollectionEquality().hash(remoteIPFilter) ^ + const DeepCollectionEquality().hash(isRemoteIPFilterBlacklist) ^ + runtimeType.hashCode; +} + +extension $NetworkConfigurationExtension on NetworkConfiguration { + NetworkConfiguration copyWith( + {String? baseUrl, + bool? enableHttps, + bool? requireHttps, + String? certificatePath, + String? certificatePassword, + int? internalHttpPort, + int? internalHttpsPort, + int? publicHttpPort, + int? publicHttpsPort, + bool? autoDiscovery, + bool? enableUPnP, + bool? enableIPv4, + bool? enableIPv6, + bool? enableRemoteAccess, + List? localNetworkSubnets, + List? localNetworkAddresses, + List? knownProxies, + bool? ignoreVirtualInterfaces, + List? virtualInterfaceNames, + bool? enablePublishedServerUriByRequest, + List? publishedServerUriBySubnet, + List? remoteIPFilter, + bool? isRemoteIPFilterBlacklist}) { + return NetworkConfiguration( + baseUrl: baseUrl ?? this.baseUrl, + enableHttps: enableHttps ?? this.enableHttps, + requireHttps: requireHttps ?? this.requireHttps, + certificatePath: certificatePath ?? this.certificatePath, + certificatePassword: certificatePassword ?? this.certificatePassword, + internalHttpPort: internalHttpPort ?? this.internalHttpPort, + internalHttpsPort: internalHttpsPort ?? this.internalHttpsPort, + publicHttpPort: publicHttpPort ?? this.publicHttpPort, + publicHttpsPort: publicHttpsPort ?? this.publicHttpsPort, + autoDiscovery: autoDiscovery ?? this.autoDiscovery, + enableUPnP: enableUPnP ?? this.enableUPnP, + enableIPv4: enableIPv4 ?? this.enableIPv4, + enableIPv6: enableIPv6 ?? this.enableIPv6, + enableRemoteAccess: enableRemoteAccess ?? this.enableRemoteAccess, + localNetworkSubnets: localNetworkSubnets ?? this.localNetworkSubnets, + localNetworkAddresses: + localNetworkAddresses ?? this.localNetworkAddresses, + knownProxies: knownProxies ?? this.knownProxies, + ignoreVirtualInterfaces: + ignoreVirtualInterfaces ?? this.ignoreVirtualInterfaces, + virtualInterfaceNames: + virtualInterfaceNames ?? this.virtualInterfaceNames, + enablePublishedServerUriByRequest: enablePublishedServerUriByRequest ?? + this.enablePublishedServerUriByRequest, + publishedServerUriBySubnet: + publishedServerUriBySubnet ?? this.publishedServerUriBySubnet, + remoteIPFilter: remoteIPFilter ?? this.remoteIPFilter, + isRemoteIPFilterBlacklist: + isRemoteIPFilterBlacklist ?? this.isRemoteIPFilterBlacklist); + } + + NetworkConfiguration copyWithWrapped( + {Wrapped? baseUrl, + Wrapped? enableHttps, + Wrapped? requireHttps, + Wrapped? certificatePath, + Wrapped? certificatePassword, + Wrapped? internalHttpPort, + Wrapped? internalHttpsPort, + Wrapped? publicHttpPort, + Wrapped? publicHttpsPort, + Wrapped? autoDiscovery, + Wrapped? enableUPnP, + Wrapped? enableIPv4, + Wrapped? enableIPv6, + Wrapped? enableRemoteAccess, + Wrapped?>? localNetworkSubnets, + Wrapped?>? localNetworkAddresses, + Wrapped?>? knownProxies, + Wrapped? ignoreVirtualInterfaces, + Wrapped?>? virtualInterfaceNames, + Wrapped? enablePublishedServerUriByRequest, + Wrapped?>? publishedServerUriBySubnet, + Wrapped?>? remoteIPFilter, + Wrapped? isRemoteIPFilterBlacklist}) { + return NetworkConfiguration( + baseUrl: (baseUrl != null ? baseUrl.value : this.baseUrl), + enableHttps: + (enableHttps != null ? enableHttps.value : this.enableHttps), + requireHttps: + (requireHttps != null ? requireHttps.value : this.requireHttps), + certificatePath: (certificatePath != null + ? certificatePath.value + : this.certificatePath), + certificatePassword: (certificatePassword != null + ? certificatePassword.value + : this.certificatePassword), + internalHttpPort: (internalHttpPort != null + ? internalHttpPort.value + : this.internalHttpPort), + internalHttpsPort: (internalHttpsPort != null + ? internalHttpsPort.value + : this.internalHttpsPort), + publicHttpPort: (publicHttpPort != null + ? publicHttpPort.value + : this.publicHttpPort), + publicHttpsPort: (publicHttpsPort != null + ? publicHttpsPort.value + : this.publicHttpsPort), + autoDiscovery: + (autoDiscovery != null ? autoDiscovery.value : this.autoDiscovery), + enableUPnP: (enableUPnP != null ? enableUPnP.value : this.enableUPnP), + enableIPv4: (enableIPv4 != null ? enableIPv4.value : this.enableIPv4), + enableIPv6: (enableIPv6 != null ? enableIPv6.value : this.enableIPv6), + enableRemoteAccess: (enableRemoteAccess != null + ? enableRemoteAccess.value + : this.enableRemoteAccess), + localNetworkSubnets: (localNetworkSubnets != null + ? localNetworkSubnets.value + : this.localNetworkSubnets), + localNetworkAddresses: (localNetworkAddresses != null + ? localNetworkAddresses.value + : this.localNetworkAddresses), + knownProxies: + (knownProxies != null ? knownProxies.value : this.knownProxies), + ignoreVirtualInterfaces: (ignoreVirtualInterfaces != null + ? ignoreVirtualInterfaces.value + : this.ignoreVirtualInterfaces), + virtualInterfaceNames: (virtualInterfaceNames != null + ? virtualInterfaceNames.value + : this.virtualInterfaceNames), + enablePublishedServerUriByRequest: + (enablePublishedServerUriByRequest != null + ? enablePublishedServerUriByRequest.value + : this.enablePublishedServerUriByRequest), + publishedServerUriBySubnet: (publishedServerUriBySubnet != null + ? publishedServerUriBySubnet.value + : this.publishedServerUriBySubnet), + remoteIPFilter: (remoteIPFilter != null + ? remoteIPFilter.value + : this.remoteIPFilter), + isRemoteIPFilterBlacklist: (isRemoteIPFilterBlacklist != null + ? isRemoteIPFilterBlacklist.value + : this.isRemoteIPFilterBlacklist)); + } +} + +@JsonSerializable(explicitToJson: true) +class NewGroupRequestDto { + const NewGroupRequestDto({ + this.groupName, + }); + + factory NewGroupRequestDto.fromJson(Map json) => + _$NewGroupRequestDtoFromJson(json); + + static const toJsonFactory = _$NewGroupRequestDtoToJson; + Map toJson() => _$NewGroupRequestDtoToJson(this); + + @JsonKey(name: 'GroupName', includeIfNull: false) + final String? groupName; + static const fromJsonFactory = _$NewGroupRequestDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is NewGroupRequestDto && + (identical(other.groupName, groupName) || + const DeepCollectionEquality() + .equals(other.groupName, groupName))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(groupName) ^ runtimeType.hashCode; +} + +extension $NewGroupRequestDtoExtension on NewGroupRequestDto { + NewGroupRequestDto copyWith({String? groupName}) { + return NewGroupRequestDto(groupName: groupName ?? this.groupName); + } + + NewGroupRequestDto copyWithWrapped({Wrapped? groupName}) { + return NewGroupRequestDto( + groupName: (groupName != null ? groupName.value : this.groupName)); + } +} + +@JsonSerializable(explicitToJson: true) +class NextItemRequestDto { + const NextItemRequestDto({ + this.playlistItemId, + }); + + factory NextItemRequestDto.fromJson(Map json) => + _$NextItemRequestDtoFromJson(json); + + static const toJsonFactory = _$NextItemRequestDtoToJson; + Map toJson() => _$NextItemRequestDtoToJson(this); + + @JsonKey(name: 'PlaylistItemId', includeIfNull: false) + final String? playlistItemId; + static const fromJsonFactory = _$NextItemRequestDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is NextItemRequestDto && + (identical(other.playlistItemId, playlistItemId) || + const DeepCollectionEquality() + .equals(other.playlistItemId, playlistItemId))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(playlistItemId) ^ + runtimeType.hashCode; +} + +extension $NextItemRequestDtoExtension on NextItemRequestDto { + NextItemRequestDto copyWith({String? playlistItemId}) { + return NextItemRequestDto( + playlistItemId: playlistItemId ?? this.playlistItemId); + } + + NextItemRequestDto copyWithWrapped({Wrapped? playlistItemId}) { + return NextItemRequestDto( + playlistItemId: (playlistItemId != null + ? playlistItemId.value + : this.playlistItemId)); + } +} + +@JsonSerializable(explicitToJson: true) +class NotFoundObjects { + const NotFoundObjects({ + this.movies, + this.shows, + this.episodes, + this.seasons, + this.people, + }); + + factory NotFoundObjects.fromJson(Map json) => + _$NotFoundObjectsFromJson(json); + + static const toJsonFactory = _$NotFoundObjectsToJson; + Map toJson() => _$NotFoundObjectsToJson(this); + + @JsonKey(name: 'movies', includeIfNull: false, defaultValue: []) + final List? movies; + @JsonKey(name: 'shows', includeIfNull: false, defaultValue: []) + final List? shows; + @JsonKey( + name: 'episodes', includeIfNull: false, defaultValue: []) + final List? episodes; + @JsonKey(name: 'seasons', includeIfNull: false, defaultValue: []) + final List? seasons; + @JsonKey(name: 'people', includeIfNull: false, defaultValue: []) + final List? people; + static const fromJsonFactory = _$NotFoundObjectsFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is NotFoundObjects && + (identical(other.movies, movies) || + const DeepCollectionEquality().equals(other.movies, movies)) && + (identical(other.shows, shows) || + const DeepCollectionEquality().equals(other.shows, shows)) && + (identical(other.episodes, episodes) || + const DeepCollectionEquality() + .equals(other.episodes, episodes)) && + (identical(other.seasons, seasons) || + const DeepCollectionEquality() + .equals(other.seasons, seasons)) && + (identical(other.people, people) || + const DeepCollectionEquality().equals(other.people, people))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(movies) ^ + const DeepCollectionEquality().hash(shows) ^ + const DeepCollectionEquality().hash(episodes) ^ + const DeepCollectionEquality().hash(seasons) ^ + const DeepCollectionEquality().hash(people) ^ + runtimeType.hashCode; +} + +extension $NotFoundObjectsExtension on NotFoundObjects { + NotFoundObjects copyWith( + {List? movies, + List? shows, + List? episodes, + List? seasons, + List? people}) { + return NotFoundObjects( + movies: movies ?? this.movies, + shows: shows ?? this.shows, + episodes: episodes ?? this.episodes, + seasons: seasons ?? this.seasons, + people: people ?? this.people); + } + + NotFoundObjects copyWithWrapped( + {Wrapped?>? movies, + Wrapped?>? shows, + Wrapped?>? episodes, + Wrapped?>? seasons, + Wrapped?>? people}) { + return NotFoundObjects( + movies: (movies != null ? movies.value : this.movies), + shows: (shows != null ? shows.value : this.shows), + episodes: (episodes != null ? episodes.value : this.episodes), + seasons: (seasons != null ? seasons.value : this.seasons), + people: (people != null ? people.value : this.people)); + } +} + +@JsonSerializable(explicitToJson: true) +class OpenLiveStreamDto { + const OpenLiveStreamDto({ + this.openToken, + this.userId, + this.playSessionId, + this.maxStreamingBitrate, + this.startTimeTicks, + this.audioStreamIndex, + this.subtitleStreamIndex, + this.maxAudioChannels, + this.itemId, + this.enableDirectPlay, + this.enableDirectStream, + this.deviceProfile, + this.directPlayProtocols, + }); + + factory OpenLiveStreamDto.fromJson(Map json) => + _$OpenLiveStreamDtoFromJson(json); + + static const toJsonFactory = _$OpenLiveStreamDtoToJson; + Map toJson() => _$OpenLiveStreamDtoToJson(this); + + @JsonKey(name: 'OpenToken', includeIfNull: false) + final String? openToken; + @JsonKey(name: 'UserId', includeIfNull: false) + final String? userId; + @JsonKey(name: 'PlaySessionId', includeIfNull: false) + final String? playSessionId; + @JsonKey(name: 'MaxStreamingBitrate', includeIfNull: false) + final int? maxStreamingBitrate; + @JsonKey(name: 'StartTimeTicks', includeIfNull: false) + final int? startTimeTicks; + @JsonKey(name: 'AudioStreamIndex', includeIfNull: false) + final int? audioStreamIndex; + @JsonKey(name: 'SubtitleStreamIndex', includeIfNull: false) + final int? subtitleStreamIndex; + @JsonKey(name: 'MaxAudioChannels', includeIfNull: false) + final int? maxAudioChannels; + @JsonKey(name: 'ItemId', includeIfNull: false) + final String? itemId; + @JsonKey(name: 'EnableDirectPlay', includeIfNull: false) + final bool? enableDirectPlay; + @JsonKey(name: 'EnableDirectStream', includeIfNull: false) + final bool? enableDirectStream; + @JsonKey(name: 'DeviceProfile', includeIfNull: false) + final DeviceProfile? deviceProfile; + @JsonKey( + name: 'DirectPlayProtocols', + includeIfNull: false, + toJson: mediaProtocolListToJson, + fromJson: mediaProtocolListFromJson, + ) + final List? directPlayProtocols; + static const fromJsonFactory = _$OpenLiveStreamDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is OpenLiveStreamDto && + (identical(other.openToken, openToken) || + const DeepCollectionEquality() + .equals(other.openToken, openToken)) && + (identical(other.userId, userId) || + const DeepCollectionEquality().equals(other.userId, userId)) && + (identical(other.playSessionId, playSessionId) || + const DeepCollectionEquality() + .equals(other.playSessionId, playSessionId)) && + (identical(other.maxStreamingBitrate, maxStreamingBitrate) || + const DeepCollectionEquality() + .equals(other.maxStreamingBitrate, maxStreamingBitrate)) && + (identical(other.startTimeTicks, startTimeTicks) || + const DeepCollectionEquality() + .equals(other.startTimeTicks, startTimeTicks)) && + (identical(other.audioStreamIndex, audioStreamIndex) || + const DeepCollectionEquality() + .equals(other.audioStreamIndex, audioStreamIndex)) && + (identical(other.subtitleStreamIndex, subtitleStreamIndex) || + const DeepCollectionEquality() + .equals(other.subtitleStreamIndex, subtitleStreamIndex)) && + (identical(other.maxAudioChannels, maxAudioChannels) || + const DeepCollectionEquality() + .equals(other.maxAudioChannels, maxAudioChannels)) && + (identical(other.itemId, itemId) || + const DeepCollectionEquality().equals(other.itemId, itemId)) && + (identical(other.enableDirectPlay, enableDirectPlay) || + const DeepCollectionEquality() + .equals(other.enableDirectPlay, enableDirectPlay)) && + (identical(other.enableDirectStream, enableDirectStream) || + const DeepCollectionEquality() + .equals(other.enableDirectStream, enableDirectStream)) && + (identical(other.deviceProfile, deviceProfile) || + const DeepCollectionEquality() + .equals(other.deviceProfile, deviceProfile)) && + (identical(other.directPlayProtocols, directPlayProtocols) || + const DeepCollectionEquality() + .equals(other.directPlayProtocols, directPlayProtocols))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(openToken) ^ + const DeepCollectionEquality().hash(userId) ^ + const DeepCollectionEquality().hash(playSessionId) ^ + const DeepCollectionEquality().hash(maxStreamingBitrate) ^ + const DeepCollectionEquality().hash(startTimeTicks) ^ + const DeepCollectionEquality().hash(audioStreamIndex) ^ + const DeepCollectionEquality().hash(subtitleStreamIndex) ^ + const DeepCollectionEquality().hash(maxAudioChannels) ^ + const DeepCollectionEquality().hash(itemId) ^ + const DeepCollectionEquality().hash(enableDirectPlay) ^ + const DeepCollectionEquality().hash(enableDirectStream) ^ + const DeepCollectionEquality().hash(deviceProfile) ^ + const DeepCollectionEquality().hash(directPlayProtocols) ^ + runtimeType.hashCode; +} + +extension $OpenLiveStreamDtoExtension on OpenLiveStreamDto { + OpenLiveStreamDto copyWith( + {String? openToken, + String? userId, + String? playSessionId, + int? maxStreamingBitrate, + int? startTimeTicks, + int? audioStreamIndex, + int? subtitleStreamIndex, + int? maxAudioChannels, + String? itemId, + bool? enableDirectPlay, + bool? enableDirectStream, + DeviceProfile? deviceProfile, + List? directPlayProtocols}) { + return OpenLiveStreamDto( + openToken: openToken ?? this.openToken, + userId: userId ?? this.userId, + playSessionId: playSessionId ?? this.playSessionId, + maxStreamingBitrate: maxStreamingBitrate ?? this.maxStreamingBitrate, + startTimeTicks: startTimeTicks ?? this.startTimeTicks, + audioStreamIndex: audioStreamIndex ?? this.audioStreamIndex, + subtitleStreamIndex: subtitleStreamIndex ?? this.subtitleStreamIndex, + maxAudioChannels: maxAudioChannels ?? this.maxAudioChannels, + itemId: itemId ?? this.itemId, + enableDirectPlay: enableDirectPlay ?? this.enableDirectPlay, + enableDirectStream: enableDirectStream ?? this.enableDirectStream, + deviceProfile: deviceProfile ?? this.deviceProfile, + directPlayProtocols: directPlayProtocols ?? this.directPlayProtocols); + } + + OpenLiveStreamDto copyWithWrapped( + {Wrapped? openToken, + Wrapped? userId, + Wrapped? playSessionId, + Wrapped? maxStreamingBitrate, + Wrapped? startTimeTicks, + Wrapped? audioStreamIndex, + Wrapped? subtitleStreamIndex, + Wrapped? maxAudioChannels, + Wrapped? itemId, + Wrapped? enableDirectPlay, + Wrapped? enableDirectStream, + Wrapped? deviceProfile, + Wrapped?>? directPlayProtocols}) { + return OpenLiveStreamDto( + openToken: (openToken != null ? openToken.value : this.openToken), + userId: (userId != null ? userId.value : this.userId), + playSessionId: + (playSessionId != null ? playSessionId.value : this.playSessionId), + maxStreamingBitrate: (maxStreamingBitrate != null + ? maxStreamingBitrate.value + : this.maxStreamingBitrate), + startTimeTicks: (startTimeTicks != null + ? startTimeTicks.value + : this.startTimeTicks), + audioStreamIndex: (audioStreamIndex != null + ? audioStreamIndex.value + : this.audioStreamIndex), + subtitleStreamIndex: (subtitleStreamIndex != null + ? subtitleStreamIndex.value + : this.subtitleStreamIndex), + maxAudioChannels: (maxAudioChannels != null + ? maxAudioChannels.value + : this.maxAudioChannels), + itemId: (itemId != null ? itemId.value : this.itemId), + enableDirectPlay: (enableDirectPlay != null + ? enableDirectPlay.value + : this.enableDirectPlay), + enableDirectStream: (enableDirectStream != null + ? enableDirectStream.value + : this.enableDirectStream), + deviceProfile: + (deviceProfile != null ? deviceProfile.value : this.deviceProfile), + directPlayProtocols: (directPlayProtocols != null + ? directPlayProtocols.value + : this.directPlayProtocols)); + } +} + +@JsonSerializable(explicitToJson: true) +class OutboundKeepAliveMessage { + const OutboundKeepAliveMessage({ + this.messageId, + this.messageType, + }); + + factory OutboundKeepAliveMessage.fromJson(Map json) => + _$OutboundKeepAliveMessageFromJson(json); + + static const toJsonFactory = _$OutboundKeepAliveMessageToJson; + Map toJson() => _$OutboundKeepAliveMessageToJson(this); + + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.keepalive); + + static const fromJsonFactory = _$OutboundKeepAliveMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is OutboundKeepAliveMessage && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $OutboundKeepAliveMessageExtension on OutboundKeepAliveMessage { + OutboundKeepAliveMessage copyWith( + {String? messageId, enums.SessionMessageType? messageType}) { + return OutboundKeepAliveMessage( + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + OutboundKeepAliveMessage copyWithWrapped( + {Wrapped? messageId, + Wrapped? messageType}) { + return OutboundKeepAliveMessage( + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class OutboundWebSocketMessage { + const OutboundWebSocketMessage(); + + factory OutboundWebSocketMessage.fromJson(Map json) => + _$OutboundWebSocketMessageFromJson(json); + + static const toJsonFactory = _$OutboundWebSocketMessageToJson; + Map toJson() => _$OutboundWebSocketMessageToJson(this); + + static const fromJsonFactory = _$OutboundWebSocketMessageFromJson; + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => runtimeType.hashCode; +} + +@JsonSerializable(explicitToJson: true) +class PackageInfo { + const PackageInfo({ + this.name, + this.description, + this.overview, + this.owner, + this.category, + this.guid, + this.versions, + this.imageUrl, + }); + + factory PackageInfo.fromJson(Map json) => + _$PackageInfoFromJson(json); + + static const toJsonFactory = _$PackageInfoToJson; + Map toJson() => _$PackageInfoToJson(this); + + @JsonKey(name: 'name', includeIfNull: false) + final String? name; + @JsonKey(name: 'description', includeIfNull: false) + final String? description; + @JsonKey(name: 'overview', includeIfNull: false) + final String? overview; + @JsonKey(name: 'owner', includeIfNull: false) + final String? owner; + @JsonKey(name: 'category', includeIfNull: false) + final String? category; + @JsonKey(name: 'guid', includeIfNull: false) + final String? guid; + @JsonKey( + name: 'versions', includeIfNull: false, defaultValue: []) + final List? versions; + @JsonKey(name: 'imageUrl', includeIfNull: false) + final String? imageUrl; + static const fromJsonFactory = _$PackageInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PackageInfo && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.description, description) || + const DeepCollectionEquality() + .equals(other.description, description)) && + (identical(other.overview, overview) || + const DeepCollectionEquality() + .equals(other.overview, overview)) && + (identical(other.owner, owner) || + const DeepCollectionEquality().equals(other.owner, owner)) && + (identical(other.category, category) || + const DeepCollectionEquality() + .equals(other.category, category)) && + (identical(other.guid, guid) || + const DeepCollectionEquality().equals(other.guid, guid)) && + (identical(other.versions, versions) || + const DeepCollectionEquality() + .equals(other.versions, versions)) && + (identical(other.imageUrl, imageUrl) || + const DeepCollectionEquality() + .equals(other.imageUrl, imageUrl))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(description) ^ + const DeepCollectionEquality().hash(overview) ^ + const DeepCollectionEquality().hash(owner) ^ + const DeepCollectionEquality().hash(category) ^ + const DeepCollectionEquality().hash(guid) ^ + const DeepCollectionEquality().hash(versions) ^ + const DeepCollectionEquality().hash(imageUrl) ^ + runtimeType.hashCode; +} + +extension $PackageInfoExtension on PackageInfo { + PackageInfo copyWith( + {String? name, + String? description, + String? overview, + String? owner, + String? category, + String? guid, + List? versions, + String? imageUrl}) { + return PackageInfo( + name: name ?? this.name, + description: description ?? this.description, + overview: overview ?? this.overview, + owner: owner ?? this.owner, + category: category ?? this.category, + guid: guid ?? this.guid, + versions: versions ?? this.versions, + imageUrl: imageUrl ?? this.imageUrl); + } + + PackageInfo copyWithWrapped( + {Wrapped? name, + Wrapped? description, + Wrapped? overview, + Wrapped? owner, + Wrapped? category, + Wrapped? guid, + Wrapped?>? versions, + Wrapped? imageUrl}) { + return PackageInfo( + name: (name != null ? name.value : this.name), + description: + (description != null ? description.value : this.description), + overview: (overview != null ? overview.value : this.overview), + owner: (owner != null ? owner.value : this.owner), + category: (category != null ? category.value : this.category), + guid: (guid != null ? guid.value : this.guid), + versions: (versions != null ? versions.value : this.versions), + imageUrl: (imageUrl != null ? imageUrl.value : this.imageUrl)); + } +} + +@JsonSerializable(explicitToJson: true) +class ParentalRating { + const ParentalRating({ + this.name, + this.$Value, + }); + + factory ParentalRating.fromJson(Map json) => + _$ParentalRatingFromJson(json); + + static const toJsonFactory = _$ParentalRatingToJson; + Map toJson() => _$ParentalRatingToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'Value', includeIfNull: false) + final int? $Value; + static const fromJsonFactory = _$ParentalRatingFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ParentalRating && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.$Value, $Value) || + const DeepCollectionEquality().equals(other.$Value, $Value))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash($Value) ^ + runtimeType.hashCode; +} + +extension $ParentalRatingExtension on ParentalRating { + ParentalRating copyWith({String? name, int? $Value}) { + return ParentalRating( + name: name ?? this.name, $Value: $Value ?? this.$Value); + } + + ParentalRating copyWithWrapped( + {Wrapped? name, Wrapped? $Value}) { + return ParentalRating( + name: (name != null ? name.value : this.name), + $Value: ($Value != null ? $Value.value : this.$Value)); + } +} + +@JsonSerializable(explicitToJson: true) +class PathSubstitution { + const PathSubstitution({ + this.from, + this.to, + }); + + factory PathSubstitution.fromJson(Map json) => + _$PathSubstitutionFromJson(json); + + static const toJsonFactory = _$PathSubstitutionToJson; + Map toJson() => _$PathSubstitutionToJson(this); + + @JsonKey(name: 'From', includeIfNull: false) + final String? from; + @JsonKey(name: 'To', includeIfNull: false) + final String? to; + static const fromJsonFactory = _$PathSubstitutionFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PathSubstitution && + (identical(other.from, from) || + const DeepCollectionEquality().equals(other.from, from)) && + (identical(other.to, to) || + const DeepCollectionEquality().equals(other.to, to))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(from) ^ + const DeepCollectionEquality().hash(to) ^ + runtimeType.hashCode; +} + +extension $PathSubstitutionExtension on PathSubstitution { + PathSubstitution copyWith({String? from, String? to}) { + return PathSubstitution(from: from ?? this.from, to: to ?? this.to); + } + + PathSubstitution copyWithWrapped( + {Wrapped? from, Wrapped? to}) { + return PathSubstitution( + from: (from != null ? from.value : this.from), + to: (to != null ? to.value : this.to)); + } +} + +@JsonSerializable(explicitToJson: true) +class PersonLookupInfo { + const PersonLookupInfo({ + this.name, + this.originalTitle, + this.path, + this.metadataLanguage, + this.metadataCountryCode, + this.providerIds, + this.year, + this.indexNumber, + this.parentIndexNumber, + this.premiereDate, + this.isAutomated, + }); + + factory PersonLookupInfo.fromJson(Map json) => + _$PersonLookupInfoFromJson(json); + + static const toJsonFactory = _$PersonLookupInfoToJson; + Map toJson() => _$PersonLookupInfoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'OriginalTitle', includeIfNull: false) + final String? originalTitle; + @JsonKey(name: 'Path', includeIfNull: false) + final String? path; + @JsonKey(name: 'MetadataLanguage', includeIfNull: false) + final String? metadataLanguage; + @JsonKey(name: 'MetadataCountryCode', includeIfNull: false) + final String? metadataCountryCode; + @JsonKey(name: 'ProviderIds', includeIfNull: false) + final Map? providerIds; + @JsonKey(name: 'Year', includeIfNull: false) + final int? year; + @JsonKey(name: 'IndexNumber', includeIfNull: false) + final int? indexNumber; + @JsonKey(name: 'ParentIndexNumber', includeIfNull: false) + final int? parentIndexNumber; + @JsonKey(name: 'PremiereDate', includeIfNull: false) + final DateTime? premiereDate; + @JsonKey(name: 'IsAutomated', includeIfNull: false) + final bool? isAutomated; + static const fromJsonFactory = _$PersonLookupInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PersonLookupInfo && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.originalTitle, originalTitle) || + const DeepCollectionEquality() + .equals(other.originalTitle, originalTitle)) && + (identical(other.path, path) || + const DeepCollectionEquality().equals(other.path, path)) && + (identical(other.metadataLanguage, metadataLanguage) || + const DeepCollectionEquality() + .equals(other.metadataLanguage, metadataLanguage)) && + (identical(other.metadataCountryCode, metadataCountryCode) || + const DeepCollectionEquality() + .equals(other.metadataCountryCode, metadataCountryCode)) && + (identical(other.providerIds, providerIds) || + const DeepCollectionEquality() + .equals(other.providerIds, providerIds)) && + (identical(other.year, year) || + const DeepCollectionEquality().equals(other.year, year)) && + (identical(other.indexNumber, indexNumber) || + const DeepCollectionEquality() + .equals(other.indexNumber, indexNumber)) && + (identical(other.parentIndexNumber, parentIndexNumber) || + const DeepCollectionEquality() + .equals(other.parentIndexNumber, parentIndexNumber)) && + (identical(other.premiereDate, premiereDate) || + const DeepCollectionEquality() + .equals(other.premiereDate, premiereDate)) && + (identical(other.isAutomated, isAutomated) || + const DeepCollectionEquality() + .equals(other.isAutomated, isAutomated))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(originalTitle) ^ + const DeepCollectionEquality().hash(path) ^ + const DeepCollectionEquality().hash(metadataLanguage) ^ + const DeepCollectionEquality().hash(metadataCountryCode) ^ + const DeepCollectionEquality().hash(providerIds) ^ + const DeepCollectionEquality().hash(year) ^ + const DeepCollectionEquality().hash(indexNumber) ^ + const DeepCollectionEquality().hash(parentIndexNumber) ^ + const DeepCollectionEquality().hash(premiereDate) ^ + const DeepCollectionEquality().hash(isAutomated) ^ + runtimeType.hashCode; +} + +extension $PersonLookupInfoExtension on PersonLookupInfo { + PersonLookupInfo copyWith( + {String? name, + String? originalTitle, + String? path, + String? metadataLanguage, + String? metadataCountryCode, + Map? providerIds, + int? year, + int? indexNumber, + int? parentIndexNumber, + DateTime? premiereDate, + bool? isAutomated}) { + return PersonLookupInfo( + name: name ?? this.name, + originalTitle: originalTitle ?? this.originalTitle, + path: path ?? this.path, + metadataLanguage: metadataLanguage ?? this.metadataLanguage, + metadataCountryCode: metadataCountryCode ?? this.metadataCountryCode, + providerIds: providerIds ?? this.providerIds, + year: year ?? this.year, + indexNumber: indexNumber ?? this.indexNumber, + parentIndexNumber: parentIndexNumber ?? this.parentIndexNumber, + premiereDate: premiereDate ?? this.premiereDate, + isAutomated: isAutomated ?? this.isAutomated); + } + + PersonLookupInfo copyWithWrapped( + {Wrapped? name, + Wrapped? originalTitle, + Wrapped? path, + Wrapped? metadataLanguage, + Wrapped? metadataCountryCode, + Wrapped?>? providerIds, + Wrapped? year, + Wrapped? indexNumber, + Wrapped? parentIndexNumber, + Wrapped? premiereDate, + Wrapped? isAutomated}) { + return PersonLookupInfo( + name: (name != null ? name.value : this.name), + originalTitle: + (originalTitle != null ? originalTitle.value : this.originalTitle), + path: (path != null ? path.value : this.path), + metadataLanguage: (metadataLanguage != null + ? metadataLanguage.value + : this.metadataLanguage), + metadataCountryCode: (metadataCountryCode != null + ? metadataCountryCode.value + : this.metadataCountryCode), + providerIds: + (providerIds != null ? providerIds.value : this.providerIds), + year: (year != null ? year.value : this.year), + indexNumber: + (indexNumber != null ? indexNumber.value : this.indexNumber), + parentIndexNumber: (parentIndexNumber != null + ? parentIndexNumber.value + : this.parentIndexNumber), + premiereDate: + (premiereDate != null ? premiereDate.value : this.premiereDate), + isAutomated: + (isAutomated != null ? isAutomated.value : this.isAutomated)); + } +} + +@JsonSerializable(explicitToJson: true) +class PersonLookupInfoRemoteSearchQuery { + const PersonLookupInfoRemoteSearchQuery({ + this.searchInfo, + this.itemId, + this.searchProviderName, + this.includeDisabledProviders, + }); + + factory PersonLookupInfoRemoteSearchQuery.fromJson( + Map json) => + _$PersonLookupInfoRemoteSearchQueryFromJson(json); + + static const toJsonFactory = _$PersonLookupInfoRemoteSearchQueryToJson; + Map toJson() => + _$PersonLookupInfoRemoteSearchQueryToJson(this); + + @JsonKey(name: 'SearchInfo', includeIfNull: false) + final PersonLookupInfo? searchInfo; + @JsonKey(name: 'ItemId', includeIfNull: false) + final String? itemId; + @JsonKey(name: 'SearchProviderName', includeIfNull: false) + final String? searchProviderName; + @JsonKey(name: 'IncludeDisabledProviders', includeIfNull: false) + final bool? includeDisabledProviders; + static const fromJsonFactory = _$PersonLookupInfoRemoteSearchQueryFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PersonLookupInfoRemoteSearchQuery && + (identical(other.searchInfo, searchInfo) || + const DeepCollectionEquality() + .equals(other.searchInfo, searchInfo)) && + (identical(other.itemId, itemId) || + const DeepCollectionEquality().equals(other.itemId, itemId)) && + (identical(other.searchProviderName, searchProviderName) || + const DeepCollectionEquality() + .equals(other.searchProviderName, searchProviderName)) && + (identical( + other.includeDisabledProviders, includeDisabledProviders) || + const DeepCollectionEquality().equals( + other.includeDisabledProviders, includeDisabledProviders))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(searchInfo) ^ + const DeepCollectionEquality().hash(itemId) ^ + const DeepCollectionEquality().hash(searchProviderName) ^ + const DeepCollectionEquality().hash(includeDisabledProviders) ^ + runtimeType.hashCode; +} + +extension $PersonLookupInfoRemoteSearchQueryExtension + on PersonLookupInfoRemoteSearchQuery { + PersonLookupInfoRemoteSearchQuery copyWith( + {PersonLookupInfo? searchInfo, + String? itemId, + String? searchProviderName, + bool? includeDisabledProviders}) { + return PersonLookupInfoRemoteSearchQuery( + searchInfo: searchInfo ?? this.searchInfo, + itemId: itemId ?? this.itemId, + searchProviderName: searchProviderName ?? this.searchProviderName, + includeDisabledProviders: + includeDisabledProviders ?? this.includeDisabledProviders); + } + + PersonLookupInfoRemoteSearchQuery copyWithWrapped( + {Wrapped? searchInfo, + Wrapped? itemId, + Wrapped? searchProviderName, + Wrapped? includeDisabledProviders}) { + return PersonLookupInfoRemoteSearchQuery( + searchInfo: (searchInfo != null ? searchInfo.value : this.searchInfo), + itemId: (itemId != null ? itemId.value : this.itemId), + searchProviderName: (searchProviderName != null + ? searchProviderName.value + : this.searchProviderName), + includeDisabledProviders: (includeDisabledProviders != null + ? includeDisabledProviders.value + : this.includeDisabledProviders)); + } +} + +@JsonSerializable(explicitToJson: true) +class PingRequestDto { + const PingRequestDto({ + this.ping, + }); + + factory PingRequestDto.fromJson(Map json) => + _$PingRequestDtoFromJson(json); + + static const toJsonFactory = _$PingRequestDtoToJson; + Map toJson() => _$PingRequestDtoToJson(this); + + @JsonKey(name: 'Ping', includeIfNull: false) + final int? ping; + static const fromJsonFactory = _$PingRequestDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PingRequestDto && + (identical(other.ping, ping) || + const DeepCollectionEquality().equals(other.ping, ping))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(ping) ^ runtimeType.hashCode; +} + +extension $PingRequestDtoExtension on PingRequestDto { + PingRequestDto copyWith({int? ping}) { + return PingRequestDto(ping: ping ?? this.ping); + } + + PingRequestDto copyWithWrapped({Wrapped? ping}) { + return PingRequestDto(ping: (ping != null ? ping.value : this.ping)); + } +} + +@JsonSerializable(explicitToJson: true) +class PinRedeemResult { + const PinRedeemResult({ + this.success, + this.usersReset, + }); + + factory PinRedeemResult.fromJson(Map json) => + _$PinRedeemResultFromJson(json); + + static const toJsonFactory = _$PinRedeemResultToJson; + Map toJson() => _$PinRedeemResultToJson(this); + + @JsonKey(name: 'Success', includeIfNull: false) + final bool? success; + @JsonKey(name: 'UsersReset', includeIfNull: false, defaultValue: []) + final List? usersReset; + static const fromJsonFactory = _$PinRedeemResultFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PinRedeemResult && + (identical(other.success, success) || + const DeepCollectionEquality() + .equals(other.success, success)) && + (identical(other.usersReset, usersReset) || + const DeepCollectionEquality() + .equals(other.usersReset, usersReset))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(success) ^ + const DeepCollectionEquality().hash(usersReset) ^ + runtimeType.hashCode; +} + +extension $PinRedeemResultExtension on PinRedeemResult { + PinRedeemResult copyWith({bool? success, List? usersReset}) { + return PinRedeemResult( + success: success ?? this.success, + usersReset: usersReset ?? this.usersReset); + } + + PinRedeemResult copyWithWrapped( + {Wrapped? success, Wrapped?>? usersReset}) { + return PinRedeemResult( + success: (success != null ? success.value : this.success), + usersReset: (usersReset != null ? usersReset.value : this.usersReset)); + } +} + +@JsonSerializable(explicitToJson: true) +class PlaybackInfoDto { + const PlaybackInfoDto({ + this.userId, + this.maxStreamingBitrate, + this.startTimeTicks, + this.audioStreamIndex, + this.subtitleStreamIndex, + this.maxAudioChannels, + this.mediaSourceId, + this.liveStreamId, + this.deviceProfile, + this.enableDirectPlay, + this.enableDirectStream, + this.enableTranscoding, + this.allowVideoStreamCopy, + this.allowAudioStreamCopy, + this.autoOpenLiveStream, + }); + + factory PlaybackInfoDto.fromJson(Map json) => + _$PlaybackInfoDtoFromJson(json); + + static const toJsonFactory = _$PlaybackInfoDtoToJson; + Map toJson() => _$PlaybackInfoDtoToJson(this); + + @JsonKey(name: 'UserId', includeIfNull: false) + final String? userId; + @JsonKey(name: 'MaxStreamingBitrate', includeIfNull: false) + final int? maxStreamingBitrate; + @JsonKey(name: 'StartTimeTicks', includeIfNull: false) + final int? startTimeTicks; + @JsonKey(name: 'AudioStreamIndex', includeIfNull: false) + final int? audioStreamIndex; + @JsonKey(name: 'SubtitleStreamIndex', includeIfNull: false) + final int? subtitleStreamIndex; + @JsonKey(name: 'MaxAudioChannels', includeIfNull: false) + final int? maxAudioChannels; + @JsonKey(name: 'MediaSourceId', includeIfNull: false) + final String? mediaSourceId; + @JsonKey(name: 'LiveStreamId', includeIfNull: false) + final String? liveStreamId; + @JsonKey(name: 'DeviceProfile', includeIfNull: false) + final DeviceProfile? deviceProfile; + @JsonKey(name: 'EnableDirectPlay', includeIfNull: false) + final bool? enableDirectPlay; + @JsonKey(name: 'EnableDirectStream', includeIfNull: false) + final bool? enableDirectStream; + @JsonKey(name: 'EnableTranscoding', includeIfNull: false) + final bool? enableTranscoding; + @JsonKey(name: 'AllowVideoStreamCopy', includeIfNull: false) + final bool? allowVideoStreamCopy; + @JsonKey(name: 'AllowAudioStreamCopy', includeIfNull: false) + final bool? allowAudioStreamCopy; + @JsonKey(name: 'AutoOpenLiveStream', includeIfNull: false) + final bool? autoOpenLiveStream; + static const fromJsonFactory = _$PlaybackInfoDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PlaybackInfoDto && + (identical(other.userId, userId) || + const DeepCollectionEquality().equals(other.userId, userId)) && + (identical(other.maxStreamingBitrate, maxStreamingBitrate) || + const DeepCollectionEquality() + .equals(other.maxStreamingBitrate, maxStreamingBitrate)) && + (identical(other.startTimeTicks, startTimeTicks) || + const DeepCollectionEquality() + .equals(other.startTimeTicks, startTimeTicks)) && + (identical(other.audioStreamIndex, audioStreamIndex) || + const DeepCollectionEquality() + .equals(other.audioStreamIndex, audioStreamIndex)) && + (identical(other.subtitleStreamIndex, subtitleStreamIndex) || + const DeepCollectionEquality() + .equals(other.subtitleStreamIndex, subtitleStreamIndex)) && + (identical(other.maxAudioChannels, maxAudioChannels) || + const DeepCollectionEquality() + .equals(other.maxAudioChannels, maxAudioChannels)) && + (identical(other.mediaSourceId, mediaSourceId) || + const DeepCollectionEquality() + .equals(other.mediaSourceId, mediaSourceId)) && + (identical(other.liveStreamId, liveStreamId) || + const DeepCollectionEquality() + .equals(other.liveStreamId, liveStreamId)) && + (identical(other.deviceProfile, deviceProfile) || + const DeepCollectionEquality() + .equals(other.deviceProfile, deviceProfile)) && + (identical(other.enableDirectPlay, enableDirectPlay) || + const DeepCollectionEquality() + .equals(other.enableDirectPlay, enableDirectPlay)) && + (identical(other.enableDirectStream, enableDirectStream) || + const DeepCollectionEquality() + .equals(other.enableDirectStream, enableDirectStream)) && + (identical(other.enableTranscoding, enableTranscoding) || + const DeepCollectionEquality() + .equals(other.enableTranscoding, enableTranscoding)) && + (identical(other.allowVideoStreamCopy, allowVideoStreamCopy) || + const DeepCollectionEquality().equals( + other.allowVideoStreamCopy, allowVideoStreamCopy)) && + (identical(other.allowAudioStreamCopy, allowAudioStreamCopy) || + const DeepCollectionEquality().equals( + other.allowAudioStreamCopy, allowAudioStreamCopy)) && + (identical(other.autoOpenLiveStream, autoOpenLiveStream) || + const DeepCollectionEquality() + .equals(other.autoOpenLiveStream, autoOpenLiveStream))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(userId) ^ + const DeepCollectionEquality().hash(maxStreamingBitrate) ^ + const DeepCollectionEquality().hash(startTimeTicks) ^ + const DeepCollectionEquality().hash(audioStreamIndex) ^ + const DeepCollectionEquality().hash(subtitleStreamIndex) ^ + const DeepCollectionEquality().hash(maxAudioChannels) ^ + const DeepCollectionEquality().hash(mediaSourceId) ^ + const DeepCollectionEquality().hash(liveStreamId) ^ + const DeepCollectionEquality().hash(deviceProfile) ^ + const DeepCollectionEquality().hash(enableDirectPlay) ^ + const DeepCollectionEquality().hash(enableDirectStream) ^ + const DeepCollectionEquality().hash(enableTranscoding) ^ + const DeepCollectionEquality().hash(allowVideoStreamCopy) ^ + const DeepCollectionEquality().hash(allowAudioStreamCopy) ^ + const DeepCollectionEquality().hash(autoOpenLiveStream) ^ + runtimeType.hashCode; +} + +extension $PlaybackInfoDtoExtension on PlaybackInfoDto { + PlaybackInfoDto copyWith( + {String? userId, + int? maxStreamingBitrate, + int? startTimeTicks, + int? audioStreamIndex, + int? subtitleStreamIndex, + int? maxAudioChannels, + String? mediaSourceId, + String? liveStreamId, + DeviceProfile? deviceProfile, + bool? enableDirectPlay, + bool? enableDirectStream, + bool? enableTranscoding, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + bool? autoOpenLiveStream}) { + return PlaybackInfoDto( + userId: userId ?? this.userId, + maxStreamingBitrate: maxStreamingBitrate ?? this.maxStreamingBitrate, + startTimeTicks: startTimeTicks ?? this.startTimeTicks, + audioStreamIndex: audioStreamIndex ?? this.audioStreamIndex, + subtitleStreamIndex: subtitleStreamIndex ?? this.subtitleStreamIndex, + maxAudioChannels: maxAudioChannels ?? this.maxAudioChannels, + mediaSourceId: mediaSourceId ?? this.mediaSourceId, + liveStreamId: liveStreamId ?? this.liveStreamId, + deviceProfile: deviceProfile ?? this.deviceProfile, + enableDirectPlay: enableDirectPlay ?? this.enableDirectPlay, + enableDirectStream: enableDirectStream ?? this.enableDirectStream, + enableTranscoding: enableTranscoding ?? this.enableTranscoding, + allowVideoStreamCopy: allowVideoStreamCopy ?? this.allowVideoStreamCopy, + allowAudioStreamCopy: allowAudioStreamCopy ?? this.allowAudioStreamCopy, + autoOpenLiveStream: autoOpenLiveStream ?? this.autoOpenLiveStream); + } + + PlaybackInfoDto copyWithWrapped( + {Wrapped? userId, + Wrapped? maxStreamingBitrate, + Wrapped? startTimeTicks, + Wrapped? audioStreamIndex, + Wrapped? subtitleStreamIndex, + Wrapped? maxAudioChannels, + Wrapped? mediaSourceId, + Wrapped? liveStreamId, + Wrapped? deviceProfile, + Wrapped? enableDirectPlay, + Wrapped? enableDirectStream, + Wrapped? enableTranscoding, + Wrapped? allowVideoStreamCopy, + Wrapped? allowAudioStreamCopy, + Wrapped? autoOpenLiveStream}) { + return PlaybackInfoDto( + userId: (userId != null ? userId.value : this.userId), + maxStreamingBitrate: (maxStreamingBitrate != null + ? maxStreamingBitrate.value + : this.maxStreamingBitrate), + startTimeTicks: (startTimeTicks != null + ? startTimeTicks.value + : this.startTimeTicks), + audioStreamIndex: (audioStreamIndex != null + ? audioStreamIndex.value + : this.audioStreamIndex), + subtitleStreamIndex: (subtitleStreamIndex != null + ? subtitleStreamIndex.value + : this.subtitleStreamIndex), + maxAudioChannels: (maxAudioChannels != null + ? maxAudioChannels.value + : this.maxAudioChannels), + mediaSourceId: + (mediaSourceId != null ? mediaSourceId.value : this.mediaSourceId), + liveStreamId: + (liveStreamId != null ? liveStreamId.value : this.liveStreamId), + deviceProfile: + (deviceProfile != null ? deviceProfile.value : this.deviceProfile), + enableDirectPlay: (enableDirectPlay != null + ? enableDirectPlay.value + : this.enableDirectPlay), + enableDirectStream: (enableDirectStream != null + ? enableDirectStream.value + : this.enableDirectStream), + enableTranscoding: (enableTranscoding != null + ? enableTranscoding.value + : this.enableTranscoding), + allowVideoStreamCopy: (allowVideoStreamCopy != null + ? allowVideoStreamCopy.value + : this.allowVideoStreamCopy), + allowAudioStreamCopy: (allowAudioStreamCopy != null + ? allowAudioStreamCopy.value + : this.allowAudioStreamCopy), + autoOpenLiveStream: (autoOpenLiveStream != null + ? autoOpenLiveStream.value + : this.autoOpenLiveStream)); + } +} + +@JsonSerializable(explicitToJson: true) +class PlaybackInfoResponse { + const PlaybackInfoResponse({ + this.mediaSources, + this.playSessionId, + this.errorCode, + }); + + factory PlaybackInfoResponse.fromJson(Map json) => + _$PlaybackInfoResponseFromJson(json); + + static const toJsonFactory = _$PlaybackInfoResponseToJson; + Map toJson() => _$PlaybackInfoResponseToJson(this); + + @JsonKey( + name: 'MediaSources', + includeIfNull: false, + defaultValue: []) + final List? mediaSources; + @JsonKey(name: 'PlaySessionId', includeIfNull: false) + final String? playSessionId; + @JsonKey( + name: 'ErrorCode', + includeIfNull: false, + toJson: playbackErrorCodeNullableToJson, + fromJson: playbackErrorCodeNullableFromJson, + ) + final enums.PlaybackErrorCode? errorCode; + static const fromJsonFactory = _$PlaybackInfoResponseFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PlaybackInfoResponse && + (identical(other.mediaSources, mediaSources) || + const DeepCollectionEquality() + .equals(other.mediaSources, mediaSources)) && + (identical(other.playSessionId, playSessionId) || + const DeepCollectionEquality() + .equals(other.playSessionId, playSessionId)) && + (identical(other.errorCode, errorCode) || + const DeepCollectionEquality() + .equals(other.errorCode, errorCode))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(mediaSources) ^ + const DeepCollectionEquality().hash(playSessionId) ^ + const DeepCollectionEquality().hash(errorCode) ^ + runtimeType.hashCode; +} + +extension $PlaybackInfoResponseExtension on PlaybackInfoResponse { + PlaybackInfoResponse copyWith( + {List? mediaSources, + String? playSessionId, + enums.PlaybackErrorCode? errorCode}) { + return PlaybackInfoResponse( + mediaSources: mediaSources ?? this.mediaSources, + playSessionId: playSessionId ?? this.playSessionId, + errorCode: errorCode ?? this.errorCode); + } + + PlaybackInfoResponse copyWithWrapped( + {Wrapped?>? mediaSources, + Wrapped? playSessionId, + Wrapped? errorCode}) { + return PlaybackInfoResponse( + mediaSources: + (mediaSources != null ? mediaSources.value : this.mediaSources), + playSessionId: + (playSessionId != null ? playSessionId.value : this.playSessionId), + errorCode: (errorCode != null ? errorCode.value : this.errorCode)); + } +} + +@JsonSerializable(explicitToJson: true) +class PlaybackProgressInfo { + const PlaybackProgressInfo({ + this.canSeek, + this.item, + this.itemId, + this.sessionId, + this.mediaSourceId, + this.audioStreamIndex, + this.subtitleStreamIndex, + this.isPaused, + this.isMuted, + this.positionTicks, + this.playbackStartTimeTicks, + this.volumeLevel, + this.brightness, + this.aspectRatio, + this.playMethod, + this.liveStreamId, + this.playSessionId, + this.repeatMode, + this.playbackOrder, + this.nowPlayingQueue, + this.playlistItemId, + }); + + factory PlaybackProgressInfo.fromJson(Map json) => + _$PlaybackProgressInfoFromJson(json); + + static const toJsonFactory = _$PlaybackProgressInfoToJson; + Map toJson() => _$PlaybackProgressInfoToJson(this); + + @JsonKey(name: 'CanSeek', includeIfNull: false) + final bool? canSeek; + @JsonKey(name: 'Item', includeIfNull: false) + final BaseItemDto? item; + @JsonKey(name: 'ItemId', includeIfNull: false) + final String? itemId; + @JsonKey(name: 'SessionId', includeIfNull: false) + final String? sessionId; + @JsonKey(name: 'MediaSourceId', includeIfNull: false) + final String? mediaSourceId; + @JsonKey(name: 'AudioStreamIndex', includeIfNull: false) + final int? audioStreamIndex; + @JsonKey(name: 'SubtitleStreamIndex', includeIfNull: false) + final int? subtitleStreamIndex; + @JsonKey(name: 'IsPaused', includeIfNull: false) + final bool? isPaused; + @JsonKey(name: 'IsMuted', includeIfNull: false) + final bool? isMuted; + @JsonKey(name: 'PositionTicks', includeIfNull: false) + final int? positionTicks; + @JsonKey(name: 'PlaybackStartTimeTicks', includeIfNull: false) + final int? playbackStartTimeTicks; + @JsonKey(name: 'VolumeLevel', includeIfNull: false) + final int? volumeLevel; + @JsonKey(name: 'Brightness', includeIfNull: false) + final int? brightness; + @JsonKey(name: 'AspectRatio', includeIfNull: false) + final String? aspectRatio; + @JsonKey( + name: 'PlayMethod', + includeIfNull: false, + toJson: playMethodNullableToJson, + fromJson: playMethodNullableFromJson, + ) + final enums.PlayMethod? playMethod; + @JsonKey(name: 'LiveStreamId', includeIfNull: false) + final String? liveStreamId; + @JsonKey(name: 'PlaySessionId', includeIfNull: false) + final String? playSessionId; + @JsonKey( + name: 'RepeatMode', + includeIfNull: false, + toJson: repeatModeNullableToJson, + fromJson: repeatModeNullableFromJson, + ) + final enums.RepeatMode? repeatMode; + @JsonKey( + name: 'PlaybackOrder', + includeIfNull: false, + toJson: playbackOrderNullableToJson, + fromJson: playbackOrderNullableFromJson, + ) + final enums.PlaybackOrder? playbackOrder; + @JsonKey( + name: 'NowPlayingQueue', + includeIfNull: false, + defaultValue: []) + final List? nowPlayingQueue; + @JsonKey(name: 'PlaylistItemId', includeIfNull: false) + final String? playlistItemId; + static const fromJsonFactory = _$PlaybackProgressInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PlaybackProgressInfo && + (identical(other.canSeek, canSeek) || + const DeepCollectionEquality() + .equals(other.canSeek, canSeek)) && + (identical(other.item, item) || + const DeepCollectionEquality().equals(other.item, item)) && + (identical(other.itemId, itemId) || + const DeepCollectionEquality().equals(other.itemId, itemId)) && + (identical(other.sessionId, sessionId) || + const DeepCollectionEquality() + .equals(other.sessionId, sessionId)) && + (identical(other.mediaSourceId, mediaSourceId) || + const DeepCollectionEquality() + .equals(other.mediaSourceId, mediaSourceId)) && + (identical(other.audioStreamIndex, audioStreamIndex) || + const DeepCollectionEquality() + .equals(other.audioStreamIndex, audioStreamIndex)) && + (identical(other.subtitleStreamIndex, subtitleStreamIndex) || + const DeepCollectionEquality() + .equals(other.subtitleStreamIndex, subtitleStreamIndex)) && + (identical(other.isPaused, isPaused) || + const DeepCollectionEquality() + .equals(other.isPaused, isPaused)) && + (identical(other.isMuted, isMuted) || + const DeepCollectionEquality() + .equals(other.isMuted, isMuted)) && + (identical(other.positionTicks, positionTicks) || + const DeepCollectionEquality() + .equals(other.positionTicks, positionTicks)) && + (identical(other.playbackStartTimeTicks, playbackStartTimeTicks) || + const DeepCollectionEquality().equals( + other.playbackStartTimeTicks, playbackStartTimeTicks)) && + (identical(other.volumeLevel, volumeLevel) || + const DeepCollectionEquality() + .equals(other.volumeLevel, volumeLevel)) && + (identical(other.brightness, brightness) || + const DeepCollectionEquality() + .equals(other.brightness, brightness)) && + (identical(other.aspectRatio, aspectRatio) || + const DeepCollectionEquality() + .equals(other.aspectRatio, aspectRatio)) && + (identical(other.playMethod, playMethod) || + const DeepCollectionEquality() + .equals(other.playMethod, playMethod)) && + (identical(other.liveStreamId, liveStreamId) || + const DeepCollectionEquality() + .equals(other.liveStreamId, liveStreamId)) && + (identical(other.playSessionId, playSessionId) || + const DeepCollectionEquality() + .equals(other.playSessionId, playSessionId)) && + (identical(other.repeatMode, repeatMode) || + const DeepCollectionEquality() + .equals(other.repeatMode, repeatMode)) && + (identical(other.playbackOrder, playbackOrder) || + const DeepCollectionEquality() + .equals(other.playbackOrder, playbackOrder)) && + (identical(other.nowPlayingQueue, nowPlayingQueue) || + const DeepCollectionEquality() + .equals(other.nowPlayingQueue, nowPlayingQueue)) && + (identical(other.playlistItemId, playlistItemId) || + const DeepCollectionEquality() + .equals(other.playlistItemId, playlistItemId))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(canSeek) ^ + const DeepCollectionEquality().hash(item) ^ + const DeepCollectionEquality().hash(itemId) ^ + const DeepCollectionEquality().hash(sessionId) ^ + const DeepCollectionEquality().hash(mediaSourceId) ^ + const DeepCollectionEquality().hash(audioStreamIndex) ^ + const DeepCollectionEquality().hash(subtitleStreamIndex) ^ + const DeepCollectionEquality().hash(isPaused) ^ + const DeepCollectionEquality().hash(isMuted) ^ + const DeepCollectionEquality().hash(positionTicks) ^ + const DeepCollectionEquality().hash(playbackStartTimeTicks) ^ + const DeepCollectionEquality().hash(volumeLevel) ^ + const DeepCollectionEquality().hash(brightness) ^ + const DeepCollectionEquality().hash(aspectRatio) ^ + const DeepCollectionEquality().hash(playMethod) ^ + const DeepCollectionEquality().hash(liveStreamId) ^ + const DeepCollectionEquality().hash(playSessionId) ^ + const DeepCollectionEquality().hash(repeatMode) ^ + const DeepCollectionEquality().hash(playbackOrder) ^ + const DeepCollectionEquality().hash(nowPlayingQueue) ^ + const DeepCollectionEquality().hash(playlistItemId) ^ + runtimeType.hashCode; +} + +extension $PlaybackProgressInfoExtension on PlaybackProgressInfo { + PlaybackProgressInfo copyWith( + {bool? canSeek, + BaseItemDto? item, + String? itemId, + String? sessionId, + String? mediaSourceId, + int? audioStreamIndex, + int? subtitleStreamIndex, + bool? isPaused, + bool? isMuted, + int? positionTicks, + int? playbackStartTimeTicks, + int? volumeLevel, + int? brightness, + String? aspectRatio, + enums.PlayMethod? playMethod, + String? liveStreamId, + String? playSessionId, + enums.RepeatMode? repeatMode, + enums.PlaybackOrder? playbackOrder, + List? nowPlayingQueue, + String? playlistItemId}) { + return PlaybackProgressInfo( + canSeek: canSeek ?? this.canSeek, + item: item ?? this.item, + itemId: itemId ?? this.itemId, + sessionId: sessionId ?? this.sessionId, + mediaSourceId: mediaSourceId ?? this.mediaSourceId, + audioStreamIndex: audioStreamIndex ?? this.audioStreamIndex, + subtitleStreamIndex: subtitleStreamIndex ?? this.subtitleStreamIndex, + isPaused: isPaused ?? this.isPaused, + isMuted: isMuted ?? this.isMuted, + positionTicks: positionTicks ?? this.positionTicks, + playbackStartTimeTicks: + playbackStartTimeTicks ?? this.playbackStartTimeTicks, + volumeLevel: volumeLevel ?? this.volumeLevel, + brightness: brightness ?? this.brightness, + aspectRatio: aspectRatio ?? this.aspectRatio, + playMethod: playMethod ?? this.playMethod, + liveStreamId: liveStreamId ?? this.liveStreamId, + playSessionId: playSessionId ?? this.playSessionId, + repeatMode: repeatMode ?? this.repeatMode, + playbackOrder: playbackOrder ?? this.playbackOrder, + nowPlayingQueue: nowPlayingQueue ?? this.nowPlayingQueue, + playlistItemId: playlistItemId ?? this.playlistItemId); + } + + PlaybackProgressInfo copyWithWrapped( + {Wrapped? canSeek, + Wrapped? item, + Wrapped? itemId, + Wrapped? sessionId, + Wrapped? mediaSourceId, + Wrapped? audioStreamIndex, + Wrapped? subtitleStreamIndex, + Wrapped? isPaused, + Wrapped? isMuted, + Wrapped? positionTicks, + Wrapped? playbackStartTimeTicks, + Wrapped? volumeLevel, + Wrapped? brightness, + Wrapped? aspectRatio, + Wrapped? playMethod, + Wrapped? liveStreamId, + Wrapped? playSessionId, + Wrapped? repeatMode, + Wrapped? playbackOrder, + Wrapped?>? nowPlayingQueue, + Wrapped? playlistItemId}) { + return PlaybackProgressInfo( + canSeek: (canSeek != null ? canSeek.value : this.canSeek), + item: (item != null ? item.value : this.item), + itemId: (itemId != null ? itemId.value : this.itemId), + sessionId: (sessionId != null ? sessionId.value : this.sessionId), + mediaSourceId: + (mediaSourceId != null ? mediaSourceId.value : this.mediaSourceId), + audioStreamIndex: (audioStreamIndex != null + ? audioStreamIndex.value + : this.audioStreamIndex), + subtitleStreamIndex: (subtitleStreamIndex != null + ? subtitleStreamIndex.value + : this.subtitleStreamIndex), + isPaused: (isPaused != null ? isPaused.value : this.isPaused), + isMuted: (isMuted != null ? isMuted.value : this.isMuted), + positionTicks: + (positionTicks != null ? positionTicks.value : this.positionTicks), + playbackStartTimeTicks: (playbackStartTimeTicks != null + ? playbackStartTimeTicks.value + : this.playbackStartTimeTicks), + volumeLevel: + (volumeLevel != null ? volumeLevel.value : this.volumeLevel), + brightness: (brightness != null ? brightness.value : this.brightness), + aspectRatio: + (aspectRatio != null ? aspectRatio.value : this.aspectRatio), + playMethod: (playMethod != null ? playMethod.value : this.playMethod), + liveStreamId: + (liveStreamId != null ? liveStreamId.value : this.liveStreamId), + playSessionId: + (playSessionId != null ? playSessionId.value : this.playSessionId), + repeatMode: (repeatMode != null ? repeatMode.value : this.repeatMode), + playbackOrder: + (playbackOrder != null ? playbackOrder.value : this.playbackOrder), + nowPlayingQueue: (nowPlayingQueue != null + ? nowPlayingQueue.value + : this.nowPlayingQueue), + playlistItemId: (playlistItemId != null + ? playlistItemId.value + : this.playlistItemId)); + } +} + +@JsonSerializable(explicitToJson: true) +class PlaybackStartInfo { + const PlaybackStartInfo({ + this.canSeek, + this.item, + this.itemId, + this.sessionId, + this.mediaSourceId, + this.audioStreamIndex, + this.subtitleStreamIndex, + this.isPaused, + this.isMuted, + this.positionTicks, + this.playbackStartTimeTicks, + this.volumeLevel, + this.brightness, + this.aspectRatio, + this.playMethod, + this.liveStreamId, + this.playSessionId, + this.repeatMode, + this.playbackOrder, + this.nowPlayingQueue, + this.playlistItemId, + }); + + factory PlaybackStartInfo.fromJson(Map json) => + _$PlaybackStartInfoFromJson(json); + + static const toJsonFactory = _$PlaybackStartInfoToJson; + Map toJson() => _$PlaybackStartInfoToJson(this); + + @JsonKey(name: 'CanSeek', includeIfNull: false) + final bool? canSeek; + @JsonKey(name: 'Item', includeIfNull: false) + final BaseItemDto? item; + @JsonKey(name: 'ItemId', includeIfNull: false) + final String? itemId; + @JsonKey(name: 'SessionId', includeIfNull: false) + final String? sessionId; + @JsonKey(name: 'MediaSourceId', includeIfNull: false) + final String? mediaSourceId; + @JsonKey(name: 'AudioStreamIndex', includeIfNull: false) + final int? audioStreamIndex; + @JsonKey(name: 'SubtitleStreamIndex', includeIfNull: false) + final int? subtitleStreamIndex; + @JsonKey(name: 'IsPaused', includeIfNull: false) + final bool? isPaused; + @JsonKey(name: 'IsMuted', includeIfNull: false) + final bool? isMuted; + @JsonKey(name: 'PositionTicks', includeIfNull: false) + final int? positionTicks; + @JsonKey(name: 'PlaybackStartTimeTicks', includeIfNull: false) + final int? playbackStartTimeTicks; + @JsonKey(name: 'VolumeLevel', includeIfNull: false) + final int? volumeLevel; + @JsonKey(name: 'Brightness', includeIfNull: false) + final int? brightness; + @JsonKey(name: 'AspectRatio', includeIfNull: false) + final String? aspectRatio; + @JsonKey( + name: 'PlayMethod', + includeIfNull: false, + toJson: playMethodNullableToJson, + fromJson: playMethodNullableFromJson, + ) + final enums.PlayMethod? playMethod; + @JsonKey(name: 'LiveStreamId', includeIfNull: false) + final String? liveStreamId; + @JsonKey(name: 'PlaySessionId', includeIfNull: false) + final String? playSessionId; + @JsonKey( + name: 'RepeatMode', + includeIfNull: false, + toJson: repeatModeNullableToJson, + fromJson: repeatModeNullableFromJson, + ) + final enums.RepeatMode? repeatMode; + @JsonKey( + name: 'PlaybackOrder', + includeIfNull: false, + toJson: playbackOrderNullableToJson, + fromJson: playbackOrderNullableFromJson, + ) + final enums.PlaybackOrder? playbackOrder; + @JsonKey( + name: 'NowPlayingQueue', + includeIfNull: false, + defaultValue: []) + final List? nowPlayingQueue; + @JsonKey(name: 'PlaylistItemId', includeIfNull: false) + final String? playlistItemId; + static const fromJsonFactory = _$PlaybackStartInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PlaybackStartInfo && + (identical(other.canSeek, canSeek) || + const DeepCollectionEquality() + .equals(other.canSeek, canSeek)) && + (identical(other.item, item) || + const DeepCollectionEquality().equals(other.item, item)) && + (identical(other.itemId, itemId) || + const DeepCollectionEquality().equals(other.itemId, itemId)) && + (identical(other.sessionId, sessionId) || + const DeepCollectionEquality() + .equals(other.sessionId, sessionId)) && + (identical(other.mediaSourceId, mediaSourceId) || + const DeepCollectionEquality() + .equals(other.mediaSourceId, mediaSourceId)) && + (identical(other.audioStreamIndex, audioStreamIndex) || + const DeepCollectionEquality() + .equals(other.audioStreamIndex, audioStreamIndex)) && + (identical(other.subtitleStreamIndex, subtitleStreamIndex) || + const DeepCollectionEquality() + .equals(other.subtitleStreamIndex, subtitleStreamIndex)) && + (identical(other.isPaused, isPaused) || + const DeepCollectionEquality() + .equals(other.isPaused, isPaused)) && + (identical(other.isMuted, isMuted) || + const DeepCollectionEquality() + .equals(other.isMuted, isMuted)) && + (identical(other.positionTicks, positionTicks) || + const DeepCollectionEquality() + .equals(other.positionTicks, positionTicks)) && + (identical(other.playbackStartTimeTicks, playbackStartTimeTicks) || + const DeepCollectionEquality().equals( + other.playbackStartTimeTicks, playbackStartTimeTicks)) && + (identical(other.volumeLevel, volumeLevel) || + const DeepCollectionEquality() + .equals(other.volumeLevel, volumeLevel)) && + (identical(other.brightness, brightness) || + const DeepCollectionEquality() + .equals(other.brightness, brightness)) && + (identical(other.aspectRatio, aspectRatio) || + const DeepCollectionEquality() + .equals(other.aspectRatio, aspectRatio)) && + (identical(other.playMethod, playMethod) || + const DeepCollectionEquality() + .equals(other.playMethod, playMethod)) && + (identical(other.liveStreamId, liveStreamId) || + const DeepCollectionEquality() + .equals(other.liveStreamId, liveStreamId)) && + (identical(other.playSessionId, playSessionId) || + const DeepCollectionEquality() + .equals(other.playSessionId, playSessionId)) && + (identical(other.repeatMode, repeatMode) || + const DeepCollectionEquality() + .equals(other.repeatMode, repeatMode)) && + (identical(other.playbackOrder, playbackOrder) || + const DeepCollectionEquality() + .equals(other.playbackOrder, playbackOrder)) && + (identical(other.nowPlayingQueue, nowPlayingQueue) || + const DeepCollectionEquality() + .equals(other.nowPlayingQueue, nowPlayingQueue)) && + (identical(other.playlistItemId, playlistItemId) || + const DeepCollectionEquality() + .equals(other.playlistItemId, playlistItemId))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(canSeek) ^ + const DeepCollectionEquality().hash(item) ^ + const DeepCollectionEquality().hash(itemId) ^ + const DeepCollectionEquality().hash(sessionId) ^ + const DeepCollectionEquality().hash(mediaSourceId) ^ + const DeepCollectionEquality().hash(audioStreamIndex) ^ + const DeepCollectionEquality().hash(subtitleStreamIndex) ^ + const DeepCollectionEquality().hash(isPaused) ^ + const DeepCollectionEquality().hash(isMuted) ^ + const DeepCollectionEquality().hash(positionTicks) ^ + const DeepCollectionEquality().hash(playbackStartTimeTicks) ^ + const DeepCollectionEquality().hash(volumeLevel) ^ + const DeepCollectionEquality().hash(brightness) ^ + const DeepCollectionEquality().hash(aspectRatio) ^ + const DeepCollectionEquality().hash(playMethod) ^ + const DeepCollectionEquality().hash(liveStreamId) ^ + const DeepCollectionEquality().hash(playSessionId) ^ + const DeepCollectionEquality().hash(repeatMode) ^ + const DeepCollectionEquality().hash(playbackOrder) ^ + const DeepCollectionEquality().hash(nowPlayingQueue) ^ + const DeepCollectionEquality().hash(playlistItemId) ^ + runtimeType.hashCode; +} + +extension $PlaybackStartInfoExtension on PlaybackStartInfo { + PlaybackStartInfo copyWith( + {bool? canSeek, + BaseItemDto? item, + String? itemId, + String? sessionId, + String? mediaSourceId, + int? audioStreamIndex, + int? subtitleStreamIndex, + bool? isPaused, + bool? isMuted, + int? positionTicks, + int? playbackStartTimeTicks, + int? volumeLevel, + int? brightness, + String? aspectRatio, + enums.PlayMethod? playMethod, + String? liveStreamId, + String? playSessionId, + enums.RepeatMode? repeatMode, + enums.PlaybackOrder? playbackOrder, + List? nowPlayingQueue, + String? playlistItemId}) { + return PlaybackStartInfo( + canSeek: canSeek ?? this.canSeek, + item: item ?? this.item, + itemId: itemId ?? this.itemId, + sessionId: sessionId ?? this.sessionId, + mediaSourceId: mediaSourceId ?? this.mediaSourceId, + audioStreamIndex: audioStreamIndex ?? this.audioStreamIndex, + subtitleStreamIndex: subtitleStreamIndex ?? this.subtitleStreamIndex, + isPaused: isPaused ?? this.isPaused, + isMuted: isMuted ?? this.isMuted, + positionTicks: positionTicks ?? this.positionTicks, + playbackStartTimeTicks: + playbackStartTimeTicks ?? this.playbackStartTimeTicks, + volumeLevel: volumeLevel ?? this.volumeLevel, + brightness: brightness ?? this.brightness, + aspectRatio: aspectRatio ?? this.aspectRatio, + playMethod: playMethod ?? this.playMethod, + liveStreamId: liveStreamId ?? this.liveStreamId, + playSessionId: playSessionId ?? this.playSessionId, + repeatMode: repeatMode ?? this.repeatMode, + playbackOrder: playbackOrder ?? this.playbackOrder, + nowPlayingQueue: nowPlayingQueue ?? this.nowPlayingQueue, + playlistItemId: playlistItemId ?? this.playlistItemId); + } + + PlaybackStartInfo copyWithWrapped( + {Wrapped? canSeek, + Wrapped? item, + Wrapped? itemId, + Wrapped? sessionId, + Wrapped? mediaSourceId, + Wrapped? audioStreamIndex, + Wrapped? subtitleStreamIndex, + Wrapped? isPaused, + Wrapped? isMuted, + Wrapped? positionTicks, + Wrapped? playbackStartTimeTicks, + Wrapped? volumeLevel, + Wrapped? brightness, + Wrapped? aspectRatio, + Wrapped? playMethod, + Wrapped? liveStreamId, + Wrapped? playSessionId, + Wrapped? repeatMode, + Wrapped? playbackOrder, + Wrapped?>? nowPlayingQueue, + Wrapped? playlistItemId}) { + return PlaybackStartInfo( + canSeek: (canSeek != null ? canSeek.value : this.canSeek), + item: (item != null ? item.value : this.item), + itemId: (itemId != null ? itemId.value : this.itemId), + sessionId: (sessionId != null ? sessionId.value : this.sessionId), + mediaSourceId: + (mediaSourceId != null ? mediaSourceId.value : this.mediaSourceId), + audioStreamIndex: (audioStreamIndex != null + ? audioStreamIndex.value + : this.audioStreamIndex), + subtitleStreamIndex: (subtitleStreamIndex != null + ? subtitleStreamIndex.value + : this.subtitleStreamIndex), + isPaused: (isPaused != null ? isPaused.value : this.isPaused), + isMuted: (isMuted != null ? isMuted.value : this.isMuted), + positionTicks: + (positionTicks != null ? positionTicks.value : this.positionTicks), + playbackStartTimeTicks: (playbackStartTimeTicks != null + ? playbackStartTimeTicks.value + : this.playbackStartTimeTicks), + volumeLevel: + (volumeLevel != null ? volumeLevel.value : this.volumeLevel), + brightness: (brightness != null ? brightness.value : this.brightness), + aspectRatio: + (aspectRatio != null ? aspectRatio.value : this.aspectRatio), + playMethod: (playMethod != null ? playMethod.value : this.playMethod), + liveStreamId: + (liveStreamId != null ? liveStreamId.value : this.liveStreamId), + playSessionId: + (playSessionId != null ? playSessionId.value : this.playSessionId), + repeatMode: (repeatMode != null ? repeatMode.value : this.repeatMode), + playbackOrder: + (playbackOrder != null ? playbackOrder.value : this.playbackOrder), + nowPlayingQueue: (nowPlayingQueue != null + ? nowPlayingQueue.value + : this.nowPlayingQueue), + playlistItemId: (playlistItemId != null + ? playlistItemId.value + : this.playlistItemId)); + } +} + +@JsonSerializable(explicitToJson: true) +class PlaybackStopInfo { + const PlaybackStopInfo({ + this.item, + this.itemId, + this.sessionId, + this.mediaSourceId, + this.positionTicks, + this.liveStreamId, + this.playSessionId, + this.failed, + this.nextMediaType, + this.playlistItemId, + this.nowPlayingQueue, + }); + + factory PlaybackStopInfo.fromJson(Map json) => + _$PlaybackStopInfoFromJson(json); + + static const toJsonFactory = _$PlaybackStopInfoToJson; + Map toJson() => _$PlaybackStopInfoToJson(this); + + @JsonKey(name: 'Item', includeIfNull: false) + final BaseItemDto? item; + @JsonKey(name: 'ItemId', includeIfNull: false) + final String? itemId; + @JsonKey(name: 'SessionId', includeIfNull: false) + final String? sessionId; + @JsonKey(name: 'MediaSourceId', includeIfNull: false) + final String? mediaSourceId; + @JsonKey(name: 'PositionTicks', includeIfNull: false) + final int? positionTicks; + @JsonKey(name: 'LiveStreamId', includeIfNull: false) + final String? liveStreamId; + @JsonKey(name: 'PlaySessionId', includeIfNull: false) + final String? playSessionId; + @JsonKey(name: 'Failed', includeIfNull: false) + final bool? failed; + @JsonKey(name: 'NextMediaType', includeIfNull: false) + final String? nextMediaType; + @JsonKey(name: 'PlaylistItemId', includeIfNull: false) + final String? playlistItemId; + @JsonKey( + name: 'NowPlayingQueue', + includeIfNull: false, + defaultValue: []) + final List? nowPlayingQueue; + static const fromJsonFactory = _$PlaybackStopInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PlaybackStopInfo && + (identical(other.item, item) || + const DeepCollectionEquality().equals(other.item, item)) && + (identical(other.itemId, itemId) || + const DeepCollectionEquality().equals(other.itemId, itemId)) && + (identical(other.sessionId, sessionId) || + const DeepCollectionEquality() + .equals(other.sessionId, sessionId)) && + (identical(other.mediaSourceId, mediaSourceId) || + const DeepCollectionEquality() + .equals(other.mediaSourceId, mediaSourceId)) && + (identical(other.positionTicks, positionTicks) || + const DeepCollectionEquality() + .equals(other.positionTicks, positionTicks)) && + (identical(other.liveStreamId, liveStreamId) || + const DeepCollectionEquality() + .equals(other.liveStreamId, liveStreamId)) && + (identical(other.playSessionId, playSessionId) || + const DeepCollectionEquality() + .equals(other.playSessionId, playSessionId)) && + (identical(other.failed, failed) || + const DeepCollectionEquality().equals(other.failed, failed)) && + (identical(other.nextMediaType, nextMediaType) || + const DeepCollectionEquality() + .equals(other.nextMediaType, nextMediaType)) && + (identical(other.playlistItemId, playlistItemId) || + const DeepCollectionEquality() + .equals(other.playlistItemId, playlistItemId)) && + (identical(other.nowPlayingQueue, nowPlayingQueue) || + const DeepCollectionEquality() + .equals(other.nowPlayingQueue, nowPlayingQueue))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(item) ^ + const DeepCollectionEquality().hash(itemId) ^ + const DeepCollectionEquality().hash(sessionId) ^ + const DeepCollectionEquality().hash(mediaSourceId) ^ + const DeepCollectionEquality().hash(positionTicks) ^ + const DeepCollectionEquality().hash(liveStreamId) ^ + const DeepCollectionEquality().hash(playSessionId) ^ + const DeepCollectionEquality().hash(failed) ^ + const DeepCollectionEquality().hash(nextMediaType) ^ + const DeepCollectionEquality().hash(playlistItemId) ^ + const DeepCollectionEquality().hash(nowPlayingQueue) ^ + runtimeType.hashCode; +} + +extension $PlaybackStopInfoExtension on PlaybackStopInfo { + PlaybackStopInfo copyWith( + {BaseItemDto? item, + String? itemId, + String? sessionId, + String? mediaSourceId, + int? positionTicks, + String? liveStreamId, + String? playSessionId, + bool? failed, + String? nextMediaType, + String? playlistItemId, + List? nowPlayingQueue}) { + return PlaybackStopInfo( + item: item ?? this.item, + itemId: itemId ?? this.itemId, + sessionId: sessionId ?? this.sessionId, + mediaSourceId: mediaSourceId ?? this.mediaSourceId, + positionTicks: positionTicks ?? this.positionTicks, + liveStreamId: liveStreamId ?? this.liveStreamId, + playSessionId: playSessionId ?? this.playSessionId, + failed: failed ?? this.failed, + nextMediaType: nextMediaType ?? this.nextMediaType, + playlistItemId: playlistItemId ?? this.playlistItemId, + nowPlayingQueue: nowPlayingQueue ?? this.nowPlayingQueue); + } + + PlaybackStopInfo copyWithWrapped( + {Wrapped? item, + Wrapped? itemId, + Wrapped? sessionId, + Wrapped? mediaSourceId, + Wrapped? positionTicks, + Wrapped? liveStreamId, + Wrapped? playSessionId, + Wrapped? failed, + Wrapped? nextMediaType, + Wrapped? playlistItemId, + Wrapped?>? nowPlayingQueue}) { + return PlaybackStopInfo( + item: (item != null ? item.value : this.item), + itemId: (itemId != null ? itemId.value : this.itemId), + sessionId: (sessionId != null ? sessionId.value : this.sessionId), + mediaSourceId: + (mediaSourceId != null ? mediaSourceId.value : this.mediaSourceId), + positionTicks: + (positionTicks != null ? positionTicks.value : this.positionTicks), + liveStreamId: + (liveStreamId != null ? liveStreamId.value : this.liveStreamId), + playSessionId: + (playSessionId != null ? playSessionId.value : this.playSessionId), + failed: (failed != null ? failed.value : this.failed), + nextMediaType: + (nextMediaType != null ? nextMediaType.value : this.nextMediaType), + playlistItemId: (playlistItemId != null + ? playlistItemId.value + : this.playlistItemId), + nowPlayingQueue: (nowPlayingQueue != null + ? nowPlayingQueue.value + : this.nowPlayingQueue)); + } +} + +@JsonSerializable(explicitToJson: true) +class PlayerStateInfo { + const PlayerStateInfo({ + this.positionTicks, + this.canSeek, + this.isPaused, + this.isMuted, + this.volumeLevel, + this.audioStreamIndex, + this.subtitleStreamIndex, + this.mediaSourceId, + this.playMethod, + this.repeatMode, + this.playbackOrder, + this.liveStreamId, + }); + + factory PlayerStateInfo.fromJson(Map json) => + _$PlayerStateInfoFromJson(json); + + static const toJsonFactory = _$PlayerStateInfoToJson; + Map toJson() => _$PlayerStateInfoToJson(this); + + @JsonKey(name: 'PositionTicks', includeIfNull: false) + final int? positionTicks; + @JsonKey(name: 'CanSeek', includeIfNull: false) + final bool? canSeek; + @JsonKey(name: 'IsPaused', includeIfNull: false) + final bool? isPaused; + @JsonKey(name: 'IsMuted', includeIfNull: false) + final bool? isMuted; + @JsonKey(name: 'VolumeLevel', includeIfNull: false) + final int? volumeLevel; + @JsonKey(name: 'AudioStreamIndex', includeIfNull: false) + final int? audioStreamIndex; + @JsonKey(name: 'SubtitleStreamIndex', includeIfNull: false) + final int? subtitleStreamIndex; + @JsonKey(name: 'MediaSourceId', includeIfNull: false) + final String? mediaSourceId; + @JsonKey( + name: 'PlayMethod', + includeIfNull: false, + toJson: playMethodNullableToJson, + fromJson: playMethodNullableFromJson, + ) + final enums.PlayMethod? playMethod; + @JsonKey( + name: 'RepeatMode', + includeIfNull: false, + toJson: repeatModeNullableToJson, + fromJson: repeatModeNullableFromJson, + ) + final enums.RepeatMode? repeatMode; + @JsonKey( + name: 'PlaybackOrder', + includeIfNull: false, + toJson: playbackOrderNullableToJson, + fromJson: playbackOrderNullableFromJson, + ) + final enums.PlaybackOrder? playbackOrder; + @JsonKey(name: 'LiveStreamId', includeIfNull: false) + final String? liveStreamId; + static const fromJsonFactory = _$PlayerStateInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PlayerStateInfo && + (identical(other.positionTicks, positionTicks) || + const DeepCollectionEquality() + .equals(other.positionTicks, positionTicks)) && + (identical(other.canSeek, canSeek) || + const DeepCollectionEquality() + .equals(other.canSeek, canSeek)) && + (identical(other.isPaused, isPaused) || + const DeepCollectionEquality() + .equals(other.isPaused, isPaused)) && + (identical(other.isMuted, isMuted) || + const DeepCollectionEquality() + .equals(other.isMuted, isMuted)) && + (identical(other.volumeLevel, volumeLevel) || + const DeepCollectionEquality() + .equals(other.volumeLevel, volumeLevel)) && + (identical(other.audioStreamIndex, audioStreamIndex) || + const DeepCollectionEquality() + .equals(other.audioStreamIndex, audioStreamIndex)) && + (identical(other.subtitleStreamIndex, subtitleStreamIndex) || + const DeepCollectionEquality() + .equals(other.subtitleStreamIndex, subtitleStreamIndex)) && + (identical(other.mediaSourceId, mediaSourceId) || + const DeepCollectionEquality() + .equals(other.mediaSourceId, mediaSourceId)) && + (identical(other.playMethod, playMethod) || + const DeepCollectionEquality() + .equals(other.playMethod, playMethod)) && + (identical(other.repeatMode, repeatMode) || + const DeepCollectionEquality() + .equals(other.repeatMode, repeatMode)) && + (identical(other.playbackOrder, playbackOrder) || + const DeepCollectionEquality() + .equals(other.playbackOrder, playbackOrder)) && + (identical(other.liveStreamId, liveStreamId) || + const DeepCollectionEquality() + .equals(other.liveStreamId, liveStreamId))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(positionTicks) ^ + const DeepCollectionEquality().hash(canSeek) ^ + const DeepCollectionEquality().hash(isPaused) ^ + const DeepCollectionEquality().hash(isMuted) ^ + const DeepCollectionEquality().hash(volumeLevel) ^ + const DeepCollectionEquality().hash(audioStreamIndex) ^ + const DeepCollectionEquality().hash(subtitleStreamIndex) ^ + const DeepCollectionEquality().hash(mediaSourceId) ^ + const DeepCollectionEquality().hash(playMethod) ^ + const DeepCollectionEquality().hash(repeatMode) ^ + const DeepCollectionEquality().hash(playbackOrder) ^ + const DeepCollectionEquality().hash(liveStreamId) ^ + runtimeType.hashCode; +} + +extension $PlayerStateInfoExtension on PlayerStateInfo { + PlayerStateInfo copyWith( + {int? positionTicks, + bool? canSeek, + bool? isPaused, + bool? isMuted, + int? volumeLevel, + int? audioStreamIndex, + int? subtitleStreamIndex, + String? mediaSourceId, + enums.PlayMethod? playMethod, + enums.RepeatMode? repeatMode, + enums.PlaybackOrder? playbackOrder, + String? liveStreamId}) { + return PlayerStateInfo( + positionTicks: positionTicks ?? this.positionTicks, + canSeek: canSeek ?? this.canSeek, + isPaused: isPaused ?? this.isPaused, + isMuted: isMuted ?? this.isMuted, + volumeLevel: volumeLevel ?? this.volumeLevel, + audioStreamIndex: audioStreamIndex ?? this.audioStreamIndex, + subtitleStreamIndex: subtitleStreamIndex ?? this.subtitleStreamIndex, + mediaSourceId: mediaSourceId ?? this.mediaSourceId, + playMethod: playMethod ?? this.playMethod, + repeatMode: repeatMode ?? this.repeatMode, + playbackOrder: playbackOrder ?? this.playbackOrder, + liveStreamId: liveStreamId ?? this.liveStreamId); + } + + PlayerStateInfo copyWithWrapped( + {Wrapped? positionTicks, + Wrapped? canSeek, + Wrapped? isPaused, + Wrapped? isMuted, + Wrapped? volumeLevel, + Wrapped? audioStreamIndex, + Wrapped? subtitleStreamIndex, + Wrapped? mediaSourceId, + Wrapped? playMethod, + Wrapped? repeatMode, + Wrapped? playbackOrder, + Wrapped? liveStreamId}) { + return PlayerStateInfo( + positionTicks: + (positionTicks != null ? positionTicks.value : this.positionTicks), + canSeek: (canSeek != null ? canSeek.value : this.canSeek), + isPaused: (isPaused != null ? isPaused.value : this.isPaused), + isMuted: (isMuted != null ? isMuted.value : this.isMuted), + volumeLevel: + (volumeLevel != null ? volumeLevel.value : this.volumeLevel), + audioStreamIndex: (audioStreamIndex != null + ? audioStreamIndex.value + : this.audioStreamIndex), + subtitleStreamIndex: (subtitleStreamIndex != null + ? subtitleStreamIndex.value + : this.subtitleStreamIndex), + mediaSourceId: + (mediaSourceId != null ? mediaSourceId.value : this.mediaSourceId), + playMethod: (playMethod != null ? playMethod.value : this.playMethod), + repeatMode: (repeatMode != null ? repeatMode.value : this.repeatMode), + playbackOrder: + (playbackOrder != null ? playbackOrder.value : this.playbackOrder), + liveStreamId: + (liveStreamId != null ? liveStreamId.value : this.liveStreamId)); + } +} + +@JsonSerializable(explicitToJson: true) +class PlaylistCreationResult { + const PlaylistCreationResult({ + this.id, + }); + + factory PlaylistCreationResult.fromJson(Map json) => + _$PlaylistCreationResultFromJson(json); + + static const toJsonFactory = _$PlaylistCreationResultToJson; + Map toJson() => _$PlaylistCreationResultToJson(this); + + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + static const fromJsonFactory = _$PlaylistCreationResultFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PlaylistCreationResult && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(id) ^ runtimeType.hashCode; +} + +extension $PlaylistCreationResultExtension on PlaylistCreationResult { + PlaylistCreationResult copyWith({String? id}) { + return PlaylistCreationResult(id: id ?? this.id); + } + + PlaylistCreationResult copyWithWrapped({Wrapped? id}) { + return PlaylistCreationResult(id: (id != null ? id.value : this.id)); + } +} + +@JsonSerializable(explicitToJson: true) +class PlaylistUserPermissions { + const PlaylistUserPermissions({ + this.userId, + this.canEdit, + }); + + factory PlaylistUserPermissions.fromJson(Map json) => + _$PlaylistUserPermissionsFromJson(json); + + static const toJsonFactory = _$PlaylistUserPermissionsToJson; + Map toJson() => _$PlaylistUserPermissionsToJson(this); + + @JsonKey(name: 'UserId', includeIfNull: false) + final String? userId; + @JsonKey(name: 'CanEdit', includeIfNull: false) + final bool? canEdit; + static const fromJsonFactory = _$PlaylistUserPermissionsFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PlaylistUserPermissions && + (identical(other.userId, userId) || + const DeepCollectionEquality().equals(other.userId, userId)) && + (identical(other.canEdit, canEdit) || + const DeepCollectionEquality().equals(other.canEdit, canEdit))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(userId) ^ + const DeepCollectionEquality().hash(canEdit) ^ + runtimeType.hashCode; +} + +extension $PlaylistUserPermissionsExtension on PlaylistUserPermissions { + PlaylistUserPermissions copyWith({String? userId, bool? canEdit}) { + return PlaylistUserPermissions( + userId: userId ?? this.userId, canEdit: canEdit ?? this.canEdit); + } + + PlaylistUserPermissions copyWithWrapped( + {Wrapped? userId, Wrapped? canEdit}) { + return PlaylistUserPermissions( + userId: (userId != null ? userId.value : this.userId), + canEdit: (canEdit != null ? canEdit.value : this.canEdit)); + } +} + +@JsonSerializable(explicitToJson: true) +class PlayMessage { + const PlayMessage({ + this.data, + this.messageId, + this.messageType, + }); + + factory PlayMessage.fromJson(Map json) => + _$PlayMessageFromJson(json); + + static const toJsonFactory = _$PlayMessageToJson; + Map toJson() => _$PlayMessageToJson(this); + + @JsonKey(name: 'Data', includeIfNull: false) + final PlayRequest? data; + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.play); + + static const fromJsonFactory = _$PlayMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PlayMessage && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data)) && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(data) ^ + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $PlayMessageExtension on PlayMessage { + PlayMessage copyWith( + {PlayRequest? data, + String? messageId, + enums.SessionMessageType? messageType}) { + return PlayMessage( + data: data ?? this.data, + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + PlayMessage copyWithWrapped( + {Wrapped? data, + Wrapped? messageId, + Wrapped? messageType}) { + return PlayMessage( + data: (data != null ? data.value : this.data), + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class PlayQueueUpdate { + const PlayQueueUpdate({ + this.reason, + this.lastUpdate, + this.playlist, + this.playingItemIndex, + this.startPositionTicks, + this.isPlaying, + this.shuffleMode, + this.repeatMode, + }); + + factory PlayQueueUpdate.fromJson(Map json) => + _$PlayQueueUpdateFromJson(json); + + static const toJsonFactory = _$PlayQueueUpdateToJson; + Map toJson() => _$PlayQueueUpdateToJson(this); + + @JsonKey( + name: 'Reason', + includeIfNull: false, + toJson: playQueueUpdateReasonNullableToJson, + fromJson: playQueueUpdateReasonNullableFromJson, + ) + final enums.PlayQueueUpdateReason? reason; + @JsonKey(name: 'LastUpdate', includeIfNull: false) + final DateTime? lastUpdate; + @JsonKey( + name: 'Playlist', + includeIfNull: false, + defaultValue: []) + final List? playlist; + @JsonKey(name: 'PlayingItemIndex', includeIfNull: false) + final int? playingItemIndex; + @JsonKey(name: 'StartPositionTicks', includeIfNull: false) + final int? startPositionTicks; + @JsonKey(name: 'IsPlaying', includeIfNull: false) + final bool? isPlaying; + @JsonKey( + name: 'ShuffleMode', + includeIfNull: false, + toJson: groupShuffleModeNullableToJson, + fromJson: groupShuffleModeNullableFromJson, + ) + final enums.GroupShuffleMode? shuffleMode; + @JsonKey( + name: 'RepeatMode', + includeIfNull: false, + toJson: groupRepeatModeNullableToJson, + fromJson: groupRepeatModeNullableFromJson, + ) + final enums.GroupRepeatMode? repeatMode; + static const fromJsonFactory = _$PlayQueueUpdateFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PlayQueueUpdate && + (identical(other.reason, reason) || + const DeepCollectionEquality().equals(other.reason, reason)) && + (identical(other.lastUpdate, lastUpdate) || + const DeepCollectionEquality() + .equals(other.lastUpdate, lastUpdate)) && + (identical(other.playlist, playlist) || + const DeepCollectionEquality() + .equals(other.playlist, playlist)) && + (identical(other.playingItemIndex, playingItemIndex) || + const DeepCollectionEquality() + .equals(other.playingItemIndex, playingItemIndex)) && + (identical(other.startPositionTicks, startPositionTicks) || + const DeepCollectionEquality() + .equals(other.startPositionTicks, startPositionTicks)) && + (identical(other.isPlaying, isPlaying) || + const DeepCollectionEquality() + .equals(other.isPlaying, isPlaying)) && + (identical(other.shuffleMode, shuffleMode) || + const DeepCollectionEquality() + .equals(other.shuffleMode, shuffleMode)) && + (identical(other.repeatMode, repeatMode) || + const DeepCollectionEquality() + .equals(other.repeatMode, repeatMode))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(reason) ^ + const DeepCollectionEquality().hash(lastUpdate) ^ + const DeepCollectionEquality().hash(playlist) ^ + const DeepCollectionEquality().hash(playingItemIndex) ^ + const DeepCollectionEquality().hash(startPositionTicks) ^ + const DeepCollectionEquality().hash(isPlaying) ^ + const DeepCollectionEquality().hash(shuffleMode) ^ + const DeepCollectionEquality().hash(repeatMode) ^ + runtimeType.hashCode; +} + +extension $PlayQueueUpdateExtension on PlayQueueUpdate { + PlayQueueUpdate copyWith( + {enums.PlayQueueUpdateReason? reason, + DateTime? lastUpdate, + List? playlist, + int? playingItemIndex, + int? startPositionTicks, + bool? isPlaying, + enums.GroupShuffleMode? shuffleMode, + enums.GroupRepeatMode? repeatMode}) { + return PlayQueueUpdate( + reason: reason ?? this.reason, + lastUpdate: lastUpdate ?? this.lastUpdate, + playlist: playlist ?? this.playlist, + playingItemIndex: playingItemIndex ?? this.playingItemIndex, + startPositionTicks: startPositionTicks ?? this.startPositionTicks, + isPlaying: isPlaying ?? this.isPlaying, + shuffleMode: shuffleMode ?? this.shuffleMode, + repeatMode: repeatMode ?? this.repeatMode); + } + + PlayQueueUpdate copyWithWrapped( + {Wrapped? reason, + Wrapped? lastUpdate, + Wrapped?>? playlist, + Wrapped? playingItemIndex, + Wrapped? startPositionTicks, + Wrapped? isPlaying, + Wrapped? shuffleMode, + Wrapped? repeatMode}) { + return PlayQueueUpdate( + reason: (reason != null ? reason.value : this.reason), + lastUpdate: (lastUpdate != null ? lastUpdate.value : this.lastUpdate), + playlist: (playlist != null ? playlist.value : this.playlist), + playingItemIndex: (playingItemIndex != null + ? playingItemIndex.value + : this.playingItemIndex), + startPositionTicks: (startPositionTicks != null + ? startPositionTicks.value + : this.startPositionTicks), + isPlaying: (isPlaying != null ? isPlaying.value : this.isPlaying), + shuffleMode: + (shuffleMode != null ? shuffleMode.value : this.shuffleMode), + repeatMode: (repeatMode != null ? repeatMode.value : this.repeatMode)); + } +} + +@JsonSerializable(explicitToJson: true) +class PlayQueueUpdateGroupUpdate { + const PlayQueueUpdateGroupUpdate({ + this.groupId, + this.type, + this.data, + }); + + factory PlayQueueUpdateGroupUpdate.fromJson(Map json) => + _$PlayQueueUpdateGroupUpdateFromJson(json); + + static const toJsonFactory = _$PlayQueueUpdateGroupUpdateToJson; + Map toJson() => _$PlayQueueUpdateGroupUpdateToJson(this); + + @JsonKey(name: 'GroupId', includeIfNull: false) + final String? groupId; + @JsonKey( + name: 'Type', + includeIfNull: false, + toJson: groupUpdateTypeNullableToJson, + fromJson: groupUpdateTypeNullableFromJson, + ) + final enums.GroupUpdateType? type; + @JsonKey(name: 'Data', includeIfNull: false) + final PlayQueueUpdate? data; + static const fromJsonFactory = _$PlayQueueUpdateGroupUpdateFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PlayQueueUpdateGroupUpdate && + (identical(other.groupId, groupId) || + const DeepCollectionEquality() + .equals(other.groupId, groupId)) && + (identical(other.type, type) || + const DeepCollectionEquality().equals(other.type, type)) && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(groupId) ^ + const DeepCollectionEquality().hash(type) ^ + const DeepCollectionEquality().hash(data) ^ + runtimeType.hashCode; +} + +extension $PlayQueueUpdateGroupUpdateExtension on PlayQueueUpdateGroupUpdate { + PlayQueueUpdateGroupUpdate copyWith( + {String? groupId, enums.GroupUpdateType? type, PlayQueueUpdate? data}) { + return PlayQueueUpdateGroupUpdate( + groupId: groupId ?? this.groupId, + type: type ?? this.type, + data: data ?? this.data); + } + + PlayQueueUpdateGroupUpdate copyWithWrapped( + {Wrapped? groupId, + Wrapped? type, + Wrapped? data}) { + return PlayQueueUpdateGroupUpdate( + groupId: (groupId != null ? groupId.value : this.groupId), + type: (type != null ? type.value : this.type), + data: (data != null ? data.value : this.data)); + } +} + +@JsonSerializable(explicitToJson: true) +class PlayRequest { + const PlayRequest({ + this.itemIds, + this.startPositionTicks, + this.playCommand, + this.controllingUserId, + this.subtitleStreamIndex, + this.audioStreamIndex, + this.mediaSourceId, + this.startIndex, + }); + + factory PlayRequest.fromJson(Map json) => + _$PlayRequestFromJson(json); + + static const toJsonFactory = _$PlayRequestToJson; + Map toJson() => _$PlayRequestToJson(this); + + @JsonKey(name: 'ItemIds', includeIfNull: false, defaultValue: []) + final List? itemIds; + @JsonKey(name: 'StartPositionTicks', includeIfNull: false) + final int? startPositionTicks; + @JsonKey( + name: 'PlayCommand', + includeIfNull: false, + toJson: playCommandNullableToJson, + fromJson: playCommandNullableFromJson, + ) + final enums.PlayCommand? playCommand; + @JsonKey(name: 'ControllingUserId', includeIfNull: false) + final String? controllingUserId; + @JsonKey(name: 'SubtitleStreamIndex', includeIfNull: false) + final int? subtitleStreamIndex; + @JsonKey(name: 'AudioStreamIndex', includeIfNull: false) + final int? audioStreamIndex; + @JsonKey(name: 'MediaSourceId', includeIfNull: false) + final String? mediaSourceId; + @JsonKey(name: 'StartIndex', includeIfNull: false) + final int? startIndex; + static const fromJsonFactory = _$PlayRequestFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PlayRequest && + (identical(other.itemIds, itemIds) || + const DeepCollectionEquality() + .equals(other.itemIds, itemIds)) && + (identical(other.startPositionTicks, startPositionTicks) || + const DeepCollectionEquality() + .equals(other.startPositionTicks, startPositionTicks)) && + (identical(other.playCommand, playCommand) || + const DeepCollectionEquality() + .equals(other.playCommand, playCommand)) && + (identical(other.controllingUserId, controllingUserId) || + const DeepCollectionEquality() + .equals(other.controllingUserId, controllingUserId)) && + (identical(other.subtitleStreamIndex, subtitleStreamIndex) || + const DeepCollectionEquality() + .equals(other.subtitleStreamIndex, subtitleStreamIndex)) && + (identical(other.audioStreamIndex, audioStreamIndex) || + const DeepCollectionEquality() + .equals(other.audioStreamIndex, audioStreamIndex)) && + (identical(other.mediaSourceId, mediaSourceId) || + const DeepCollectionEquality() + .equals(other.mediaSourceId, mediaSourceId)) && + (identical(other.startIndex, startIndex) || + const DeepCollectionEquality() + .equals(other.startIndex, startIndex))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(itemIds) ^ + const DeepCollectionEquality().hash(startPositionTicks) ^ + const DeepCollectionEquality().hash(playCommand) ^ + const DeepCollectionEquality().hash(controllingUserId) ^ + const DeepCollectionEquality().hash(subtitleStreamIndex) ^ + const DeepCollectionEquality().hash(audioStreamIndex) ^ + const DeepCollectionEquality().hash(mediaSourceId) ^ + const DeepCollectionEquality().hash(startIndex) ^ + runtimeType.hashCode; +} + +extension $PlayRequestExtension on PlayRequest { + PlayRequest copyWith( + {List? itemIds, + int? startPositionTicks, + enums.PlayCommand? playCommand, + String? controllingUserId, + int? subtitleStreamIndex, + int? audioStreamIndex, + String? mediaSourceId, + int? startIndex}) { + return PlayRequest( + itemIds: itemIds ?? this.itemIds, + startPositionTicks: startPositionTicks ?? this.startPositionTicks, + playCommand: playCommand ?? this.playCommand, + controllingUserId: controllingUserId ?? this.controllingUserId, + subtitleStreamIndex: subtitleStreamIndex ?? this.subtitleStreamIndex, + audioStreamIndex: audioStreamIndex ?? this.audioStreamIndex, + mediaSourceId: mediaSourceId ?? this.mediaSourceId, + startIndex: startIndex ?? this.startIndex); + } + + PlayRequest copyWithWrapped( + {Wrapped?>? itemIds, + Wrapped? startPositionTicks, + Wrapped? playCommand, + Wrapped? controllingUserId, + Wrapped? subtitleStreamIndex, + Wrapped? audioStreamIndex, + Wrapped? mediaSourceId, + Wrapped? startIndex}) { + return PlayRequest( + itemIds: (itemIds != null ? itemIds.value : this.itemIds), + startPositionTicks: (startPositionTicks != null + ? startPositionTicks.value + : this.startPositionTicks), + playCommand: + (playCommand != null ? playCommand.value : this.playCommand), + controllingUserId: (controllingUserId != null + ? controllingUserId.value + : this.controllingUserId), + subtitleStreamIndex: (subtitleStreamIndex != null + ? subtitleStreamIndex.value + : this.subtitleStreamIndex), + audioStreamIndex: (audioStreamIndex != null + ? audioStreamIndex.value + : this.audioStreamIndex), + mediaSourceId: + (mediaSourceId != null ? mediaSourceId.value : this.mediaSourceId), + startIndex: (startIndex != null ? startIndex.value : this.startIndex)); + } +} + +@JsonSerializable(explicitToJson: true) +class PlayRequestDto { + const PlayRequestDto({ + this.playingQueue, + this.playingItemPosition, + this.startPositionTicks, + }); + + factory PlayRequestDto.fromJson(Map json) => + _$PlayRequestDtoFromJson(json); + + static const toJsonFactory = _$PlayRequestDtoToJson; + Map toJson() => _$PlayRequestDtoToJson(this); + + @JsonKey(name: 'PlayingQueue', includeIfNull: false, defaultValue: []) + final List? playingQueue; + @JsonKey(name: 'PlayingItemPosition', includeIfNull: false) + final int? playingItemPosition; + @JsonKey(name: 'StartPositionTicks', includeIfNull: false) + final int? startPositionTicks; + static const fromJsonFactory = _$PlayRequestDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PlayRequestDto && + (identical(other.playingQueue, playingQueue) || + const DeepCollectionEquality() + .equals(other.playingQueue, playingQueue)) && + (identical(other.playingItemPosition, playingItemPosition) || + const DeepCollectionEquality() + .equals(other.playingItemPosition, playingItemPosition)) && + (identical(other.startPositionTicks, startPositionTicks) || + const DeepCollectionEquality() + .equals(other.startPositionTicks, startPositionTicks))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(playingQueue) ^ + const DeepCollectionEquality().hash(playingItemPosition) ^ + const DeepCollectionEquality().hash(startPositionTicks) ^ + runtimeType.hashCode; +} + +extension $PlayRequestDtoExtension on PlayRequestDto { + PlayRequestDto copyWith( + {List? playingQueue, + int? playingItemPosition, + int? startPositionTicks}) { + return PlayRequestDto( + playingQueue: playingQueue ?? this.playingQueue, + playingItemPosition: playingItemPosition ?? this.playingItemPosition, + startPositionTicks: startPositionTicks ?? this.startPositionTicks); + } + + PlayRequestDto copyWithWrapped( + {Wrapped?>? playingQueue, + Wrapped? playingItemPosition, + Wrapped? startPositionTicks}) { + return PlayRequestDto( + playingQueue: + (playingQueue != null ? playingQueue.value : this.playingQueue), + playingItemPosition: (playingItemPosition != null + ? playingItemPosition.value + : this.playingItemPosition), + startPositionTicks: (startPositionTicks != null + ? startPositionTicks.value + : this.startPositionTicks)); + } +} + +@JsonSerializable(explicitToJson: true) +class PlaystateMessage { + const PlaystateMessage({ + this.data, + this.messageId, + this.messageType, + }); + + factory PlaystateMessage.fromJson(Map json) => + _$PlaystateMessageFromJson(json); + + static const toJsonFactory = _$PlaystateMessageToJson; + Map toJson() => _$PlaystateMessageToJson(this); + + @JsonKey(name: 'Data', includeIfNull: false) + final PlaystateRequest? data; + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.playstate); + + static const fromJsonFactory = _$PlaystateMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PlaystateMessage && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data)) && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(data) ^ + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $PlaystateMessageExtension on PlaystateMessage { + PlaystateMessage copyWith( + {PlaystateRequest? data, + String? messageId, + enums.SessionMessageType? messageType}) { + return PlaystateMessage( + data: data ?? this.data, + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + PlaystateMessage copyWithWrapped( + {Wrapped? data, + Wrapped? messageId, + Wrapped? messageType}) { + return PlaystateMessage( + data: (data != null ? data.value : this.data), + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class PlaystateRequest { + const PlaystateRequest({ + this.command, + this.seekPositionTicks, + this.controllingUserId, + }); + + factory PlaystateRequest.fromJson(Map json) => + _$PlaystateRequestFromJson(json); + + static const toJsonFactory = _$PlaystateRequestToJson; + Map toJson() => _$PlaystateRequestToJson(this); + + @JsonKey( + name: 'Command', + includeIfNull: false, + toJson: playstateCommandNullableToJson, + fromJson: playstateCommandNullableFromJson, + ) + final enums.PlaystateCommand? command; + @JsonKey(name: 'SeekPositionTicks', includeIfNull: false) + final int? seekPositionTicks; + @JsonKey(name: 'ControllingUserId', includeIfNull: false) + final String? controllingUserId; + static const fromJsonFactory = _$PlaystateRequestFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PlaystateRequest && + (identical(other.command, command) || + const DeepCollectionEquality() + .equals(other.command, command)) && + (identical(other.seekPositionTicks, seekPositionTicks) || + const DeepCollectionEquality() + .equals(other.seekPositionTicks, seekPositionTicks)) && + (identical(other.controllingUserId, controllingUserId) || + const DeepCollectionEquality() + .equals(other.controllingUserId, controllingUserId))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(command) ^ + const DeepCollectionEquality().hash(seekPositionTicks) ^ + const DeepCollectionEquality().hash(controllingUserId) ^ + runtimeType.hashCode; +} + +extension $PlaystateRequestExtension on PlaystateRequest { + PlaystateRequest copyWith( + {enums.PlaystateCommand? command, + int? seekPositionTicks, + String? controllingUserId}) { + return PlaystateRequest( + command: command ?? this.command, + seekPositionTicks: seekPositionTicks ?? this.seekPositionTicks, + controllingUserId: controllingUserId ?? this.controllingUserId); + } + + PlaystateRequest copyWithWrapped( + {Wrapped? command, + Wrapped? seekPositionTicks, + Wrapped? controllingUserId}) { + return PlaystateRequest( + command: (command != null ? command.value : this.command), + seekPositionTicks: (seekPositionTicks != null + ? seekPositionTicks.value + : this.seekPositionTicks), + controllingUserId: (controllingUserId != null + ? controllingUserId.value + : this.controllingUserId)); + } +} + +@JsonSerializable(explicitToJson: true) +class PluginInfo { + const PluginInfo({ + this.name, + this.version, + this.configurationFileName, + this.description, + this.id, + this.canUninstall, + this.hasImage, + this.status, + }); + + factory PluginInfo.fromJson(Map json) => + _$PluginInfoFromJson(json); + + static const toJsonFactory = _$PluginInfoToJson; + Map toJson() => _$PluginInfoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'Version', includeIfNull: false) + final String? version; + @JsonKey(name: 'ConfigurationFileName', includeIfNull: false) + final String? configurationFileName; + @JsonKey(name: 'Description', includeIfNull: false) + final String? description; + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'CanUninstall', includeIfNull: false) + final bool? canUninstall; + @JsonKey(name: 'HasImage', includeIfNull: false) + final bool? hasImage; + @JsonKey( + name: 'Status', + includeIfNull: false, + toJson: pluginStatusNullableToJson, + fromJson: pluginStatusNullableFromJson, + ) + final enums.PluginStatus? status; + static const fromJsonFactory = _$PluginInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PluginInfo && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.version, version) || + const DeepCollectionEquality() + .equals(other.version, version)) && + (identical(other.configurationFileName, configurationFileName) || + const DeepCollectionEquality().equals( + other.configurationFileName, configurationFileName)) && + (identical(other.description, description) || + const DeepCollectionEquality() + .equals(other.description, description)) && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.canUninstall, canUninstall) || + const DeepCollectionEquality() + .equals(other.canUninstall, canUninstall)) && + (identical(other.hasImage, hasImage) || + const DeepCollectionEquality() + .equals(other.hasImage, hasImage)) && + (identical(other.status, status) || + const DeepCollectionEquality().equals(other.status, status))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(version) ^ + const DeepCollectionEquality().hash(configurationFileName) ^ + const DeepCollectionEquality().hash(description) ^ + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(canUninstall) ^ + const DeepCollectionEquality().hash(hasImage) ^ + const DeepCollectionEquality().hash(status) ^ + runtimeType.hashCode; +} + +extension $PluginInfoExtension on PluginInfo { + PluginInfo copyWith( + {String? name, + String? version, + String? configurationFileName, + String? description, + String? id, + bool? canUninstall, + bool? hasImage, + enums.PluginStatus? status}) { + return PluginInfo( + name: name ?? this.name, + version: version ?? this.version, + configurationFileName: + configurationFileName ?? this.configurationFileName, + description: description ?? this.description, + id: id ?? this.id, + canUninstall: canUninstall ?? this.canUninstall, + hasImage: hasImage ?? this.hasImage, + status: status ?? this.status); + } + + PluginInfo copyWithWrapped( + {Wrapped? name, + Wrapped? version, + Wrapped? configurationFileName, + Wrapped? description, + Wrapped? id, + Wrapped? canUninstall, + Wrapped? hasImage, + Wrapped? status}) { + return PluginInfo( + name: (name != null ? name.value : this.name), + version: (version != null ? version.value : this.version), + configurationFileName: (configurationFileName != null + ? configurationFileName.value + : this.configurationFileName), + description: + (description != null ? description.value : this.description), + id: (id != null ? id.value : this.id), + canUninstall: + (canUninstall != null ? canUninstall.value : this.canUninstall), + hasImage: (hasImage != null ? hasImage.value : this.hasImage), + status: (status != null ? status.value : this.status)); + } +} + +@JsonSerializable(explicitToJson: true) +class PluginInstallationCancelledMessage { + const PluginInstallationCancelledMessage({ + this.data, + this.messageId, + this.messageType, + }); + + factory PluginInstallationCancelledMessage.fromJson( + Map json) => + _$PluginInstallationCancelledMessageFromJson(json); + + static const toJsonFactory = _$PluginInstallationCancelledMessageToJson; + Map toJson() => + _$PluginInstallationCancelledMessageToJson(this); + + @JsonKey(name: 'Data', includeIfNull: false) + final InstallationInfo? data; + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.packageinstallationcancelled); + + static const fromJsonFactory = _$PluginInstallationCancelledMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PluginInstallationCancelledMessage && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data)) && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(data) ^ + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $PluginInstallationCancelledMessageExtension + on PluginInstallationCancelledMessage { + PluginInstallationCancelledMessage copyWith( + {InstallationInfo? data, + String? messageId, + enums.SessionMessageType? messageType}) { + return PluginInstallationCancelledMessage( + data: data ?? this.data, + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + PluginInstallationCancelledMessage copyWithWrapped( + {Wrapped? data, + Wrapped? messageId, + Wrapped? messageType}) { + return PluginInstallationCancelledMessage( + data: (data != null ? data.value : this.data), + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class PluginInstallationCompletedMessage { + const PluginInstallationCompletedMessage({ + this.data, + this.messageId, + this.messageType, + }); + + factory PluginInstallationCompletedMessage.fromJson( + Map json) => + _$PluginInstallationCompletedMessageFromJson(json); + + static const toJsonFactory = _$PluginInstallationCompletedMessageToJson; + Map toJson() => + _$PluginInstallationCompletedMessageToJson(this); + + @JsonKey(name: 'Data', includeIfNull: false) + final InstallationInfo? data; + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.packageinstallationcompleted); + + static const fromJsonFactory = _$PluginInstallationCompletedMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PluginInstallationCompletedMessage && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data)) && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(data) ^ + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $PluginInstallationCompletedMessageExtension + on PluginInstallationCompletedMessage { + PluginInstallationCompletedMessage copyWith( + {InstallationInfo? data, + String? messageId, + enums.SessionMessageType? messageType}) { + return PluginInstallationCompletedMessage( + data: data ?? this.data, + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + PluginInstallationCompletedMessage copyWithWrapped( + {Wrapped? data, + Wrapped? messageId, + Wrapped? messageType}) { + return PluginInstallationCompletedMessage( + data: (data != null ? data.value : this.data), + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class PluginInstallationFailedMessage { + const PluginInstallationFailedMessage({ + this.data, + this.messageId, + this.messageType, + }); + + factory PluginInstallationFailedMessage.fromJson(Map json) => + _$PluginInstallationFailedMessageFromJson(json); + + static const toJsonFactory = _$PluginInstallationFailedMessageToJson; + Map toJson() => + _$PluginInstallationFailedMessageToJson(this); + + @JsonKey(name: 'Data', includeIfNull: false) + final InstallationInfo? data; + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.packageinstallationfailed); + + static const fromJsonFactory = _$PluginInstallationFailedMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PluginInstallationFailedMessage && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data)) && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(data) ^ + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $PluginInstallationFailedMessageExtension + on PluginInstallationFailedMessage { + PluginInstallationFailedMessage copyWith( + {InstallationInfo? data, + String? messageId, + enums.SessionMessageType? messageType}) { + return PluginInstallationFailedMessage( + data: data ?? this.data, + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + PluginInstallationFailedMessage copyWithWrapped( + {Wrapped? data, + Wrapped? messageId, + Wrapped? messageType}) { + return PluginInstallationFailedMessage( + data: (data != null ? data.value : this.data), + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class PluginInstallingMessage { + const PluginInstallingMessage({ + this.data, + this.messageId, + this.messageType, + }); + + factory PluginInstallingMessage.fromJson(Map json) => + _$PluginInstallingMessageFromJson(json); + + static const toJsonFactory = _$PluginInstallingMessageToJson; + Map toJson() => _$PluginInstallingMessageToJson(this); + + @JsonKey(name: 'Data', includeIfNull: false) + final InstallationInfo? data; + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.packageinstalling); + + static const fromJsonFactory = _$PluginInstallingMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PluginInstallingMessage && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data)) && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(data) ^ + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $PluginInstallingMessageExtension on PluginInstallingMessage { + PluginInstallingMessage copyWith( + {InstallationInfo? data, + String? messageId, + enums.SessionMessageType? messageType}) { + return PluginInstallingMessage( + data: data ?? this.data, + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + PluginInstallingMessage copyWithWrapped( + {Wrapped? data, + Wrapped? messageId, + Wrapped? messageType}) { + return PluginInstallingMessage( + data: (data != null ? data.value : this.data), + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class PluginUninstalledMessage { + const PluginUninstalledMessage({ + this.data, + this.messageId, + this.messageType, + }); + + factory PluginUninstalledMessage.fromJson(Map json) => + _$PluginUninstalledMessageFromJson(json); + + static const toJsonFactory = _$PluginUninstalledMessageToJson; + Map toJson() => _$PluginUninstalledMessageToJson(this); + + @JsonKey(name: 'Data', includeIfNull: false) + final PluginInfo? data; + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.packageuninstalled); + + static const fromJsonFactory = _$PluginUninstalledMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PluginUninstalledMessage && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data)) && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(data) ^ + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $PluginUninstalledMessageExtension on PluginUninstalledMessage { + PluginUninstalledMessage copyWith( + {PluginInfo? data, + String? messageId, + enums.SessionMessageType? messageType}) { + return PluginUninstalledMessage( + data: data ?? this.data, + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + PluginUninstalledMessage copyWithWrapped( + {Wrapped? data, + Wrapped? messageId, + Wrapped? messageType}) { + return PluginUninstalledMessage( + data: (data != null ? data.value : this.data), + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class PreviousItemRequestDto { + const PreviousItemRequestDto({ + this.playlistItemId, + }); + + factory PreviousItemRequestDto.fromJson(Map json) => + _$PreviousItemRequestDtoFromJson(json); + + static const toJsonFactory = _$PreviousItemRequestDtoToJson; + Map toJson() => _$PreviousItemRequestDtoToJson(this); + + @JsonKey(name: 'PlaylistItemId', includeIfNull: false) + final String? playlistItemId; + static const fromJsonFactory = _$PreviousItemRequestDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PreviousItemRequestDto && + (identical(other.playlistItemId, playlistItemId) || + const DeepCollectionEquality() + .equals(other.playlistItemId, playlistItemId))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(playlistItemId) ^ + runtimeType.hashCode; +} + +extension $PreviousItemRequestDtoExtension on PreviousItemRequestDto { + PreviousItemRequestDto copyWith({String? playlistItemId}) { + return PreviousItemRequestDto( + playlistItemId: playlistItemId ?? this.playlistItemId); + } + + PreviousItemRequestDto copyWithWrapped({Wrapped? playlistItemId}) { + return PreviousItemRequestDto( + playlistItemId: (playlistItemId != null + ? playlistItemId.value + : this.playlistItemId)); + } +} + +@JsonSerializable(explicitToJson: true) +class ProblemDetails { + const ProblemDetails({ + this.type, + this.title, + this.status, + this.detail, + this.instance, + }); + + factory ProblemDetails.fromJson(Map json) => + _$ProblemDetailsFromJson(json); + + static const toJsonFactory = _$ProblemDetailsToJson; + Map toJson() => _$ProblemDetailsToJson(this); + + @JsonKey(name: 'type', includeIfNull: false) + final String? type; + @JsonKey(name: 'title', includeIfNull: false) + final String? title; + @JsonKey(name: 'status', includeIfNull: false) + final int? status; + @JsonKey(name: 'detail', includeIfNull: false) + final String? detail; + @JsonKey(name: 'instance', includeIfNull: false) + final String? instance; + static const fromJsonFactory = _$ProblemDetailsFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ProblemDetails && + (identical(other.type, type) || + const DeepCollectionEquality().equals(other.type, type)) && + (identical(other.title, title) || + const DeepCollectionEquality().equals(other.title, title)) && + (identical(other.status, status) || + const DeepCollectionEquality().equals(other.status, status)) && + (identical(other.detail, detail) || + const DeepCollectionEquality().equals(other.detail, detail)) && + (identical(other.instance, instance) || + const DeepCollectionEquality() + .equals(other.instance, instance))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(type) ^ + const DeepCollectionEquality().hash(title) ^ + const DeepCollectionEquality().hash(status) ^ + const DeepCollectionEquality().hash(detail) ^ + const DeepCollectionEquality().hash(instance) ^ + runtimeType.hashCode; +} + +extension $ProblemDetailsExtension on ProblemDetails { + ProblemDetails copyWith( + {String? type, + String? title, + int? status, + String? detail, + String? instance}) { + return ProblemDetails( + type: type ?? this.type, + title: title ?? this.title, + status: status ?? this.status, + detail: detail ?? this.detail, + instance: instance ?? this.instance); + } + + ProblemDetails copyWithWrapped( + {Wrapped? type, + Wrapped? title, + Wrapped? status, + Wrapped? detail, + Wrapped? instance}) { + return ProblemDetails( + type: (type != null ? type.value : this.type), + title: (title != null ? title.value : this.title), + status: (status != null ? status.value : this.status), + detail: (detail != null ? detail.value : this.detail), + instance: (instance != null ? instance.value : this.instance)); + } +} + +@JsonSerializable(explicitToJson: true) +class ProfileCondition { + const ProfileCondition({ + this.condition, + this.property, + this.$Value, + this.isRequired, + }); + + factory ProfileCondition.fromJson(Map json) => + _$ProfileConditionFromJson(json); + + static const toJsonFactory = _$ProfileConditionToJson; + Map toJson() => _$ProfileConditionToJson(this); + + @JsonKey( + name: 'Condition', + includeIfNull: false, + toJson: profileConditionTypeNullableToJson, + fromJson: profileConditionTypeNullableFromJson, + ) + final enums.ProfileConditionType? condition; + @JsonKey( + name: 'Property', + includeIfNull: false, + toJson: profileConditionValueNullableToJson, + fromJson: profileConditionValueNullableFromJson, + ) + final enums.ProfileConditionValue? property; + @JsonKey(name: 'Value', includeIfNull: false) + final String? $Value; + @JsonKey(name: 'IsRequired', includeIfNull: false) + final bool? isRequired; + static const fromJsonFactory = _$ProfileConditionFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ProfileCondition && + (identical(other.condition, condition) || + const DeepCollectionEquality() + .equals(other.condition, condition)) && + (identical(other.property, property) || + const DeepCollectionEquality() + .equals(other.property, property)) && + (identical(other.$Value, $Value) || + const DeepCollectionEquality().equals(other.$Value, $Value)) && + (identical(other.isRequired, isRequired) || + const DeepCollectionEquality() + .equals(other.isRequired, isRequired))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(condition) ^ + const DeepCollectionEquality().hash(property) ^ + const DeepCollectionEquality().hash($Value) ^ + const DeepCollectionEquality().hash(isRequired) ^ + runtimeType.hashCode; +} + +extension $ProfileConditionExtension on ProfileCondition { + ProfileCondition copyWith( + {enums.ProfileConditionType? condition, + enums.ProfileConditionValue? property, + String? $Value, + bool? isRequired}) { + return ProfileCondition( + condition: condition ?? this.condition, + property: property ?? this.property, + $Value: $Value ?? this.$Value, + isRequired: isRequired ?? this.isRequired); + } + + ProfileCondition copyWithWrapped( + {Wrapped? condition, + Wrapped? property, + Wrapped? $Value, + Wrapped? isRequired}) { + return ProfileCondition( + condition: (condition != null ? condition.value : this.condition), + property: (property != null ? property.value : this.property), + $Value: ($Value != null ? $Value.value : this.$Value), + isRequired: (isRequired != null ? isRequired.value : this.isRequired)); + } +} + +@JsonSerializable(explicitToJson: true) +class PublicSystemInfo { + const PublicSystemInfo({ + this.localAddress, + this.serverName, + this.version, + this.productName, + this.operatingSystem, + this.id, + this.startupWizardCompleted, + }); + + factory PublicSystemInfo.fromJson(Map json) => + _$PublicSystemInfoFromJson(json); + + static const toJsonFactory = _$PublicSystemInfoToJson; + Map toJson() => _$PublicSystemInfoToJson(this); + + @JsonKey(name: 'LocalAddress', includeIfNull: false) + final String? localAddress; + @JsonKey(name: 'ServerName', includeIfNull: false) + final String? serverName; + @JsonKey(name: 'Version', includeIfNull: false) + final String? version; + @JsonKey(name: 'ProductName', includeIfNull: false) + final String? productName; + @JsonKey(name: 'OperatingSystem', includeIfNull: false) + @deprecated + final String? operatingSystem; + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'StartupWizardCompleted', includeIfNull: false) + final bool? startupWizardCompleted; + static const fromJsonFactory = _$PublicSystemInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is PublicSystemInfo && + (identical(other.localAddress, localAddress) || + const DeepCollectionEquality() + .equals(other.localAddress, localAddress)) && + (identical(other.serverName, serverName) || + const DeepCollectionEquality() + .equals(other.serverName, serverName)) && + (identical(other.version, version) || + const DeepCollectionEquality() + .equals(other.version, version)) && + (identical(other.productName, productName) || + const DeepCollectionEquality() + .equals(other.productName, productName)) && + (identical(other.operatingSystem, operatingSystem) || + const DeepCollectionEquality() + .equals(other.operatingSystem, operatingSystem)) && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.startupWizardCompleted, startupWizardCompleted) || + const DeepCollectionEquality().equals( + other.startupWizardCompleted, startupWizardCompleted))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(localAddress) ^ + const DeepCollectionEquality().hash(serverName) ^ + const DeepCollectionEquality().hash(version) ^ + const DeepCollectionEquality().hash(productName) ^ + const DeepCollectionEquality().hash(operatingSystem) ^ + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(startupWizardCompleted) ^ + runtimeType.hashCode; +} + +extension $PublicSystemInfoExtension on PublicSystemInfo { + PublicSystemInfo copyWith( + {String? localAddress, + String? serverName, + String? version, + String? productName, + String? operatingSystem, + String? id, + bool? startupWizardCompleted}) { + return PublicSystemInfo( + localAddress: localAddress ?? this.localAddress, + serverName: serverName ?? this.serverName, + version: version ?? this.version, + productName: productName ?? this.productName, + operatingSystem: operatingSystem ?? this.operatingSystem, + id: id ?? this.id, + startupWizardCompleted: + startupWizardCompleted ?? this.startupWizardCompleted); + } + + PublicSystemInfo copyWithWrapped( + {Wrapped? localAddress, + Wrapped? serverName, + Wrapped? version, + Wrapped? productName, + Wrapped? operatingSystem, + Wrapped? id, + Wrapped? startupWizardCompleted}) { + return PublicSystemInfo( + localAddress: + (localAddress != null ? localAddress.value : this.localAddress), + serverName: (serverName != null ? serverName.value : this.serverName), + version: (version != null ? version.value : this.version), + productName: + (productName != null ? productName.value : this.productName), + operatingSystem: (operatingSystem != null + ? operatingSystem.value + : this.operatingSystem), + id: (id != null ? id.value : this.id), + startupWizardCompleted: (startupWizardCompleted != null + ? startupWizardCompleted.value + : this.startupWizardCompleted)); + } +} + +@JsonSerializable(explicitToJson: true) +class QueryFilters { + const QueryFilters({ + this.genres, + this.tags, + }); + + factory QueryFilters.fromJson(Map json) => + _$QueryFiltersFromJson(json); + + static const toJsonFactory = _$QueryFiltersToJson; + Map toJson() => _$QueryFiltersToJson(this); + + @JsonKey(name: 'Genres', includeIfNull: false, defaultValue: []) + final List? genres; + @JsonKey(name: 'Tags', includeIfNull: false, defaultValue: []) + final List? tags; + static const fromJsonFactory = _$QueryFiltersFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is QueryFilters && + (identical(other.genres, genres) || + const DeepCollectionEquality().equals(other.genres, genres)) && + (identical(other.tags, tags) || + const DeepCollectionEquality().equals(other.tags, tags))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(genres) ^ + const DeepCollectionEquality().hash(tags) ^ + runtimeType.hashCode; +} + +extension $QueryFiltersExtension on QueryFilters { + QueryFilters copyWith({List? genres, List? tags}) { + return QueryFilters(genres: genres ?? this.genres, tags: tags ?? this.tags); + } + + QueryFilters copyWithWrapped( + {Wrapped?>? genres, Wrapped?>? tags}) { + return QueryFilters( + genres: (genres != null ? genres.value : this.genres), + tags: (tags != null ? tags.value : this.tags)); + } +} + +@JsonSerializable(explicitToJson: true) +class QueryFiltersLegacy { + const QueryFiltersLegacy({ + this.genres, + this.tags, + this.officialRatings, + this.years, + }); + + factory QueryFiltersLegacy.fromJson(Map json) => + _$QueryFiltersLegacyFromJson(json); + + static const toJsonFactory = _$QueryFiltersLegacyToJson; + Map toJson() => _$QueryFiltersLegacyToJson(this); + + @JsonKey(name: 'Genres', includeIfNull: false, defaultValue: []) + final List? genres; + @JsonKey(name: 'Tags', includeIfNull: false, defaultValue: []) + final List? tags; + @JsonKey( + name: 'OfficialRatings', includeIfNull: false, defaultValue: []) + final List? officialRatings; + @JsonKey(name: 'Years', includeIfNull: false, defaultValue: []) + final List? years; + static const fromJsonFactory = _$QueryFiltersLegacyFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is QueryFiltersLegacy && + (identical(other.genres, genres) || + const DeepCollectionEquality().equals(other.genres, genres)) && + (identical(other.tags, tags) || + const DeepCollectionEquality().equals(other.tags, tags)) && + (identical(other.officialRatings, officialRatings) || + const DeepCollectionEquality() + .equals(other.officialRatings, officialRatings)) && + (identical(other.years, years) || + const DeepCollectionEquality().equals(other.years, years))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(genres) ^ + const DeepCollectionEquality().hash(tags) ^ + const DeepCollectionEquality().hash(officialRatings) ^ + const DeepCollectionEquality().hash(years) ^ + runtimeType.hashCode; +} + +extension $QueryFiltersLegacyExtension on QueryFiltersLegacy { + QueryFiltersLegacy copyWith( + {List? genres, + List? tags, + List? officialRatings, + List? years}) { + return QueryFiltersLegacy( + genres: genres ?? this.genres, + tags: tags ?? this.tags, + officialRatings: officialRatings ?? this.officialRatings, + years: years ?? this.years); + } + + QueryFiltersLegacy copyWithWrapped( + {Wrapped?>? genres, + Wrapped?>? tags, + Wrapped?>? officialRatings, + Wrapped?>? years}) { + return QueryFiltersLegacy( + genres: (genres != null ? genres.value : this.genres), + tags: (tags != null ? tags.value : this.tags), + officialRatings: (officialRatings != null + ? officialRatings.value + : this.officialRatings), + years: (years != null ? years.value : this.years)); + } +} + +@JsonSerializable(explicitToJson: true) +class QueueItem { + const QueueItem({ + this.id, + this.playlistItemId, + }); + + factory QueueItem.fromJson(Map json) => + _$QueueItemFromJson(json); + + static const toJsonFactory = _$QueueItemToJson; + Map toJson() => _$QueueItemToJson(this); + + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'PlaylistItemId', includeIfNull: false) + final String? playlistItemId; + static const fromJsonFactory = _$QueueItemFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is QueueItem && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.playlistItemId, playlistItemId) || + const DeepCollectionEquality() + .equals(other.playlistItemId, playlistItemId))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(playlistItemId) ^ + runtimeType.hashCode; +} + +extension $QueueItemExtension on QueueItem { + QueueItem copyWith({String? id, String? playlistItemId}) { + return QueueItem( + id: id ?? this.id, + playlistItemId: playlistItemId ?? this.playlistItemId); + } + + QueueItem copyWithWrapped( + {Wrapped? id, Wrapped? playlistItemId}) { + return QueueItem( + id: (id != null ? id.value : this.id), + playlistItemId: (playlistItemId != null + ? playlistItemId.value + : this.playlistItemId)); + } +} + +@JsonSerializable(explicitToJson: true) +class QueueRequestDto { + const QueueRequestDto({ + this.itemIds, + this.mode, + }); + + factory QueueRequestDto.fromJson(Map json) => + _$QueueRequestDtoFromJson(json); + + static const toJsonFactory = _$QueueRequestDtoToJson; + Map toJson() => _$QueueRequestDtoToJson(this); + + @JsonKey(name: 'ItemIds', includeIfNull: false, defaultValue: []) + final List? itemIds; + @JsonKey( + name: 'Mode', + includeIfNull: false, + toJson: groupQueueModeNullableToJson, + fromJson: groupQueueModeNullableFromJson, + ) + final enums.GroupQueueMode? mode; + static const fromJsonFactory = _$QueueRequestDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is QueueRequestDto && + (identical(other.itemIds, itemIds) || + const DeepCollectionEquality() + .equals(other.itemIds, itemIds)) && + (identical(other.mode, mode) || + const DeepCollectionEquality().equals(other.mode, mode))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(itemIds) ^ + const DeepCollectionEquality().hash(mode) ^ + runtimeType.hashCode; +} + +extension $QueueRequestDtoExtension on QueueRequestDto { + QueueRequestDto copyWith( + {List? itemIds, enums.GroupQueueMode? mode}) { + return QueueRequestDto( + itemIds: itemIds ?? this.itemIds, mode: mode ?? this.mode); + } + + QueueRequestDto copyWithWrapped( + {Wrapped?>? itemIds, Wrapped? mode}) { + return QueueRequestDto( + itemIds: (itemIds != null ? itemIds.value : this.itemIds), + mode: (mode != null ? mode.value : this.mode)); + } +} + +@JsonSerializable(explicitToJson: true) +class QuickConnectDto { + const QuickConnectDto({ + required this.secret, + }); + + factory QuickConnectDto.fromJson(Map json) => + _$QuickConnectDtoFromJson(json); + + static const toJsonFactory = _$QuickConnectDtoToJson; + Map toJson() => _$QuickConnectDtoToJson(this); + + @JsonKey(name: 'Secret', includeIfNull: false) + final String secret; + static const fromJsonFactory = _$QuickConnectDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is QuickConnectDto && + (identical(other.secret, secret) || + const DeepCollectionEquality().equals(other.secret, secret))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(secret) ^ runtimeType.hashCode; +} + +extension $QuickConnectDtoExtension on QuickConnectDto { + QuickConnectDto copyWith({String? secret}) { + return QuickConnectDto(secret: secret ?? this.secret); + } + + QuickConnectDto copyWithWrapped({Wrapped? secret}) { + return QuickConnectDto( + secret: (secret != null ? secret.value : this.secret)); + } +} + +@JsonSerializable(explicitToJson: true) +class QuickConnectResult { + const QuickConnectResult({ + this.authenticated, + this.secret, + this.code, + this.deviceId, + this.deviceName, + this.appName, + this.appVersion, + this.dateAdded, + }); + + factory QuickConnectResult.fromJson(Map json) => + _$QuickConnectResultFromJson(json); + + static const toJsonFactory = _$QuickConnectResultToJson; + Map toJson() => _$QuickConnectResultToJson(this); + + @JsonKey(name: 'Authenticated', includeIfNull: false) + final bool? authenticated; + @JsonKey(name: 'Secret', includeIfNull: false) + final String? secret; + @JsonKey(name: 'Code', includeIfNull: false) + final String? code; + @JsonKey(name: 'DeviceId', includeIfNull: false) + final String? deviceId; + @JsonKey(name: 'DeviceName', includeIfNull: false) + final String? deviceName; + @JsonKey(name: 'AppName', includeIfNull: false) + final String? appName; + @JsonKey(name: 'AppVersion', includeIfNull: false) + final String? appVersion; + @JsonKey(name: 'DateAdded', includeIfNull: false) + final DateTime? dateAdded; + static const fromJsonFactory = _$QuickConnectResultFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is QuickConnectResult && + (identical(other.authenticated, authenticated) || + const DeepCollectionEquality() + .equals(other.authenticated, authenticated)) && + (identical(other.secret, secret) || + const DeepCollectionEquality().equals(other.secret, secret)) && + (identical(other.code, code) || + const DeepCollectionEquality().equals(other.code, code)) && + (identical(other.deviceId, deviceId) || + const DeepCollectionEquality() + .equals(other.deviceId, deviceId)) && + (identical(other.deviceName, deviceName) || + const DeepCollectionEquality() + .equals(other.deviceName, deviceName)) && + (identical(other.appName, appName) || + const DeepCollectionEquality() + .equals(other.appName, appName)) && + (identical(other.appVersion, appVersion) || + const DeepCollectionEquality() + .equals(other.appVersion, appVersion)) && + (identical(other.dateAdded, dateAdded) || + const DeepCollectionEquality() + .equals(other.dateAdded, dateAdded))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(authenticated) ^ + const DeepCollectionEquality().hash(secret) ^ + const DeepCollectionEquality().hash(code) ^ + const DeepCollectionEquality().hash(deviceId) ^ + const DeepCollectionEquality().hash(deviceName) ^ + const DeepCollectionEquality().hash(appName) ^ + const DeepCollectionEquality().hash(appVersion) ^ + const DeepCollectionEquality().hash(dateAdded) ^ + runtimeType.hashCode; +} + +extension $QuickConnectResultExtension on QuickConnectResult { + QuickConnectResult copyWith( + {bool? authenticated, + String? secret, + String? code, + String? deviceId, + String? deviceName, + String? appName, + String? appVersion, + DateTime? dateAdded}) { + return QuickConnectResult( + authenticated: authenticated ?? this.authenticated, + secret: secret ?? this.secret, + code: code ?? this.code, + deviceId: deviceId ?? this.deviceId, + deviceName: deviceName ?? this.deviceName, + appName: appName ?? this.appName, + appVersion: appVersion ?? this.appVersion, + dateAdded: dateAdded ?? this.dateAdded); + } + + QuickConnectResult copyWithWrapped( + {Wrapped? authenticated, + Wrapped? secret, + Wrapped? code, + Wrapped? deviceId, + Wrapped? deviceName, + Wrapped? appName, + Wrapped? appVersion, + Wrapped? dateAdded}) { + return QuickConnectResult( + authenticated: + (authenticated != null ? authenticated.value : this.authenticated), + secret: (secret != null ? secret.value : this.secret), + code: (code != null ? code.value : this.code), + deviceId: (deviceId != null ? deviceId.value : this.deviceId), + deviceName: (deviceName != null ? deviceName.value : this.deviceName), + appName: (appName != null ? appName.value : this.appName), + appVersion: (appVersion != null ? appVersion.value : this.appVersion), + dateAdded: (dateAdded != null ? dateAdded.value : this.dateAdded)); + } +} + +@JsonSerializable(explicitToJson: true) +class ReadyRequestDto { + const ReadyRequestDto({ + this.when, + this.positionTicks, + this.isPlaying, + this.playlistItemId, + }); + + factory ReadyRequestDto.fromJson(Map json) => + _$ReadyRequestDtoFromJson(json); + + static const toJsonFactory = _$ReadyRequestDtoToJson; + Map toJson() => _$ReadyRequestDtoToJson(this); + + @JsonKey(name: 'When', includeIfNull: false) + final DateTime? when; + @JsonKey(name: 'PositionTicks', includeIfNull: false) + final int? positionTicks; + @JsonKey(name: 'IsPlaying', includeIfNull: false) + final bool? isPlaying; + @JsonKey(name: 'PlaylistItemId', includeIfNull: false) + final String? playlistItemId; + static const fromJsonFactory = _$ReadyRequestDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ReadyRequestDto && + (identical(other.when, when) || + const DeepCollectionEquality().equals(other.when, when)) && + (identical(other.positionTicks, positionTicks) || + const DeepCollectionEquality() + .equals(other.positionTicks, positionTicks)) && + (identical(other.isPlaying, isPlaying) || + const DeepCollectionEquality() + .equals(other.isPlaying, isPlaying)) && + (identical(other.playlistItemId, playlistItemId) || + const DeepCollectionEquality() + .equals(other.playlistItemId, playlistItemId))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(when) ^ + const DeepCollectionEquality().hash(positionTicks) ^ + const DeepCollectionEquality().hash(isPlaying) ^ + const DeepCollectionEquality().hash(playlistItemId) ^ + runtimeType.hashCode; +} + +extension $ReadyRequestDtoExtension on ReadyRequestDto { + ReadyRequestDto copyWith( + {DateTime? when, + int? positionTicks, + bool? isPlaying, + String? playlistItemId}) { + return ReadyRequestDto( + when: when ?? this.when, + positionTicks: positionTicks ?? this.positionTicks, + isPlaying: isPlaying ?? this.isPlaying, + playlistItemId: playlistItemId ?? this.playlistItemId); + } + + ReadyRequestDto copyWithWrapped( + {Wrapped? when, + Wrapped? positionTicks, + Wrapped? isPlaying, + Wrapped? playlistItemId}) { + return ReadyRequestDto( + when: (when != null ? when.value : this.when), + positionTicks: + (positionTicks != null ? positionTicks.value : this.positionTicks), + isPlaying: (isPlaying != null ? isPlaying.value : this.isPlaying), + playlistItemId: (playlistItemId != null + ? playlistItemId.value + : this.playlistItemId)); + } +} + +@JsonSerializable(explicitToJson: true) +class RecommendationDto { + const RecommendationDto({ + this.items, + this.recommendationType, + this.baselineItemName, + this.categoryId, + }); + + factory RecommendationDto.fromJson(Map json) => + _$RecommendationDtoFromJson(json); + + static const toJsonFactory = _$RecommendationDtoToJson; + Map toJson() => _$RecommendationDtoToJson(this); + + @JsonKey(name: 'Items', includeIfNull: false, defaultValue: []) + final List? items; + @JsonKey( + name: 'RecommendationType', + includeIfNull: false, + toJson: recommendationTypeNullableToJson, + fromJson: recommendationTypeNullableFromJson, + ) + final enums.RecommendationType? recommendationType; + @JsonKey(name: 'BaselineItemName', includeIfNull: false) + final String? baselineItemName; + @JsonKey(name: 'CategoryId', includeIfNull: false) + final String? categoryId; + static const fromJsonFactory = _$RecommendationDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is RecommendationDto && + (identical(other.items, items) || + const DeepCollectionEquality().equals(other.items, items)) && + (identical(other.recommendationType, recommendationType) || + const DeepCollectionEquality() + .equals(other.recommendationType, recommendationType)) && + (identical(other.baselineItemName, baselineItemName) || + const DeepCollectionEquality() + .equals(other.baselineItemName, baselineItemName)) && + (identical(other.categoryId, categoryId) || + const DeepCollectionEquality() + .equals(other.categoryId, categoryId))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(items) ^ + const DeepCollectionEquality().hash(recommendationType) ^ + const DeepCollectionEquality().hash(baselineItemName) ^ + const DeepCollectionEquality().hash(categoryId) ^ + runtimeType.hashCode; +} + +extension $RecommendationDtoExtension on RecommendationDto { + RecommendationDto copyWith( + {List? items, + enums.RecommendationType? recommendationType, + String? baselineItemName, + String? categoryId}) { + return RecommendationDto( + items: items ?? this.items, + recommendationType: recommendationType ?? this.recommendationType, + baselineItemName: baselineItemName ?? this.baselineItemName, + categoryId: categoryId ?? this.categoryId); + } + + RecommendationDto copyWithWrapped( + {Wrapped?>? items, + Wrapped? recommendationType, + Wrapped? baselineItemName, + Wrapped? categoryId}) { + return RecommendationDto( + items: (items != null ? items.value : this.items), + recommendationType: (recommendationType != null + ? recommendationType.value + : this.recommendationType), + baselineItemName: (baselineItemName != null + ? baselineItemName.value + : this.baselineItemName), + categoryId: (categoryId != null ? categoryId.value : this.categoryId)); + } +} + +@JsonSerializable(explicitToJson: true) +class RefreshProgressMessage { + const RefreshProgressMessage({ + this.data, + this.messageId, + this.messageType, + }); + + factory RefreshProgressMessage.fromJson(Map json) => + _$RefreshProgressMessageFromJson(json); + + static const toJsonFactory = _$RefreshProgressMessageToJson; + Map toJson() => _$RefreshProgressMessageToJson(this); + + @JsonKey(name: 'Data', includeIfNull: false) + final Map? data; + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.refreshprogress); + + static const fromJsonFactory = _$RefreshProgressMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is RefreshProgressMessage && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data)) && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(data) ^ + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $RefreshProgressMessageExtension on RefreshProgressMessage { + RefreshProgressMessage copyWith( + {Map? data, + String? messageId, + enums.SessionMessageType? messageType}) { + return RefreshProgressMessage( + data: data ?? this.data, + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + RefreshProgressMessage copyWithWrapped( + {Wrapped?>? data, + Wrapped? messageId, + Wrapped? messageType}) { + return RefreshProgressMessage( + data: (data != null ? data.value : this.data), + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class RemoteImageInfo { + const RemoteImageInfo({ + this.providerName, + this.url, + this.thumbnailUrl, + this.height, + this.width, + this.communityRating, + this.voteCount, + this.language, + this.type, + this.ratingType, + }); + + factory RemoteImageInfo.fromJson(Map json) => + _$RemoteImageInfoFromJson(json); + + static const toJsonFactory = _$RemoteImageInfoToJson; + Map toJson() => _$RemoteImageInfoToJson(this); + + @JsonKey(name: 'ProviderName', includeIfNull: false) + final String? providerName; + @JsonKey(name: 'Url', includeIfNull: false) + final String? url; + @JsonKey(name: 'ThumbnailUrl', includeIfNull: false) + final String? thumbnailUrl; + @JsonKey(name: 'Height', includeIfNull: false) + final int? height; + @JsonKey(name: 'Width', includeIfNull: false) + final int? width; + @JsonKey(name: 'CommunityRating', includeIfNull: false) + final double? communityRating; + @JsonKey(name: 'VoteCount', includeIfNull: false) + final int? voteCount; + @JsonKey(name: 'Language', includeIfNull: false) + final String? language; + @JsonKey( + name: 'Type', + includeIfNull: false, + toJson: imageTypeNullableToJson, + fromJson: imageTypeNullableFromJson, + ) + final enums.ImageType? type; + @JsonKey( + name: 'RatingType', + includeIfNull: false, + toJson: ratingTypeNullableToJson, + fromJson: ratingTypeNullableFromJson, + ) + final enums.RatingType? ratingType; + static const fromJsonFactory = _$RemoteImageInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is RemoteImageInfo && + (identical(other.providerName, providerName) || + const DeepCollectionEquality() + .equals(other.providerName, providerName)) && + (identical(other.url, url) || + const DeepCollectionEquality().equals(other.url, url)) && + (identical(other.thumbnailUrl, thumbnailUrl) || + const DeepCollectionEquality() + .equals(other.thumbnailUrl, thumbnailUrl)) && + (identical(other.height, height) || + const DeepCollectionEquality().equals(other.height, height)) && + (identical(other.width, width) || + const DeepCollectionEquality().equals(other.width, width)) && + (identical(other.communityRating, communityRating) || + const DeepCollectionEquality() + .equals(other.communityRating, communityRating)) && + (identical(other.voteCount, voteCount) || + const DeepCollectionEquality() + .equals(other.voteCount, voteCount)) && + (identical(other.language, language) || + const DeepCollectionEquality() + .equals(other.language, language)) && + (identical(other.type, type) || + const DeepCollectionEquality().equals(other.type, type)) && + (identical(other.ratingType, ratingType) || + const DeepCollectionEquality() + .equals(other.ratingType, ratingType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(providerName) ^ + const DeepCollectionEquality().hash(url) ^ + const DeepCollectionEquality().hash(thumbnailUrl) ^ + const DeepCollectionEquality().hash(height) ^ + const DeepCollectionEquality().hash(width) ^ + const DeepCollectionEquality().hash(communityRating) ^ + const DeepCollectionEquality().hash(voteCount) ^ + const DeepCollectionEquality().hash(language) ^ + const DeepCollectionEquality().hash(type) ^ + const DeepCollectionEquality().hash(ratingType) ^ + runtimeType.hashCode; +} + +extension $RemoteImageInfoExtension on RemoteImageInfo { + RemoteImageInfo copyWith( + {String? providerName, + String? url, + String? thumbnailUrl, + int? height, + int? width, + double? communityRating, + int? voteCount, + String? language, + enums.ImageType? type, + enums.RatingType? ratingType}) { + return RemoteImageInfo( + providerName: providerName ?? this.providerName, + url: url ?? this.url, + thumbnailUrl: thumbnailUrl ?? this.thumbnailUrl, + height: height ?? this.height, + width: width ?? this.width, + communityRating: communityRating ?? this.communityRating, + voteCount: voteCount ?? this.voteCount, + language: language ?? this.language, + type: type ?? this.type, + ratingType: ratingType ?? this.ratingType); + } + + RemoteImageInfo copyWithWrapped( + {Wrapped? providerName, + Wrapped? url, + Wrapped? thumbnailUrl, + Wrapped? height, + Wrapped? width, + Wrapped? communityRating, + Wrapped? voteCount, + Wrapped? language, + Wrapped? type, + Wrapped? ratingType}) { + return RemoteImageInfo( + providerName: + (providerName != null ? providerName.value : this.providerName), + url: (url != null ? url.value : this.url), + thumbnailUrl: + (thumbnailUrl != null ? thumbnailUrl.value : this.thumbnailUrl), + height: (height != null ? height.value : this.height), + width: (width != null ? width.value : this.width), + communityRating: (communityRating != null + ? communityRating.value + : this.communityRating), + voteCount: (voteCount != null ? voteCount.value : this.voteCount), + language: (language != null ? language.value : this.language), + type: (type != null ? type.value : this.type), + ratingType: (ratingType != null ? ratingType.value : this.ratingType)); + } +} + +@JsonSerializable(explicitToJson: true) +class RemoteImageResult { + const RemoteImageResult({ + this.images, + this.totalRecordCount, + this.providers, + }); + + factory RemoteImageResult.fromJson(Map json) => + _$RemoteImageResultFromJson(json); + + static const toJsonFactory = _$RemoteImageResultToJson; + Map toJson() => _$RemoteImageResultToJson(this); + + @JsonKey( + name: 'Images', includeIfNull: false, defaultValue: []) + final List? images; + @JsonKey(name: 'TotalRecordCount', includeIfNull: false) + final int? totalRecordCount; + @JsonKey(name: 'Providers', includeIfNull: false, defaultValue: []) + final List? providers; + static const fromJsonFactory = _$RemoteImageResultFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is RemoteImageResult && + (identical(other.images, images) || + const DeepCollectionEquality().equals(other.images, images)) && + (identical(other.totalRecordCount, totalRecordCount) || + const DeepCollectionEquality() + .equals(other.totalRecordCount, totalRecordCount)) && + (identical(other.providers, providers) || + const DeepCollectionEquality() + .equals(other.providers, providers))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(images) ^ + const DeepCollectionEquality().hash(totalRecordCount) ^ + const DeepCollectionEquality().hash(providers) ^ + runtimeType.hashCode; +} + +extension $RemoteImageResultExtension on RemoteImageResult { + RemoteImageResult copyWith( + {List? images, + int? totalRecordCount, + List? providers}) { + return RemoteImageResult( + images: images ?? this.images, + totalRecordCount: totalRecordCount ?? this.totalRecordCount, + providers: providers ?? this.providers); + } + + RemoteImageResult copyWithWrapped( + {Wrapped?>? images, + Wrapped? totalRecordCount, + Wrapped?>? providers}) { + return RemoteImageResult( + images: (images != null ? images.value : this.images), + totalRecordCount: (totalRecordCount != null + ? totalRecordCount.value + : this.totalRecordCount), + providers: (providers != null ? providers.value : this.providers)); + } +} + +@JsonSerializable(explicitToJson: true) +class RemoteLyricInfoDto { + const RemoteLyricInfoDto({ + this.id, + this.providerName, + this.lyrics, + }); + + factory RemoteLyricInfoDto.fromJson(Map json) => + _$RemoteLyricInfoDtoFromJson(json); + + static const toJsonFactory = _$RemoteLyricInfoDtoToJson; + Map toJson() => _$RemoteLyricInfoDtoToJson(this); + + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'ProviderName', includeIfNull: false) + final String? providerName; + @JsonKey(name: 'Lyrics', includeIfNull: false) + final LyricDto? lyrics; + static const fromJsonFactory = _$RemoteLyricInfoDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is RemoteLyricInfoDto && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.providerName, providerName) || + const DeepCollectionEquality() + .equals(other.providerName, providerName)) && + (identical(other.lyrics, lyrics) || + const DeepCollectionEquality().equals(other.lyrics, lyrics))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(providerName) ^ + const DeepCollectionEquality().hash(lyrics) ^ + runtimeType.hashCode; +} + +extension $RemoteLyricInfoDtoExtension on RemoteLyricInfoDto { + RemoteLyricInfoDto copyWith( + {String? id, String? providerName, LyricDto? lyrics}) { + return RemoteLyricInfoDto( + id: id ?? this.id, + providerName: providerName ?? this.providerName, + lyrics: lyrics ?? this.lyrics); + } + + RemoteLyricInfoDto copyWithWrapped( + {Wrapped? id, + Wrapped? providerName, + Wrapped? lyrics}) { + return RemoteLyricInfoDto( + id: (id != null ? id.value : this.id), + providerName: + (providerName != null ? providerName.value : this.providerName), + lyrics: (lyrics != null ? lyrics.value : this.lyrics)); + } +} + +@JsonSerializable(explicitToJson: true) +class RemoteSearchResult { + const RemoteSearchResult({ + this.name, + this.providerIds, + this.productionYear, + this.indexNumber, + this.indexNumberEnd, + this.parentIndexNumber, + this.premiereDate, + this.imageUrl, + this.searchProviderName, + this.overview, + this.albumArtist, + this.artists, + }); + + factory RemoteSearchResult.fromJson(Map json) => + _$RemoteSearchResultFromJson(json); + + static const toJsonFactory = _$RemoteSearchResultToJson; + Map toJson() => _$RemoteSearchResultToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'ProviderIds', includeIfNull: false) + final Map? providerIds; + @JsonKey(name: 'ProductionYear', includeIfNull: false) + final int? productionYear; + @JsonKey(name: 'IndexNumber', includeIfNull: false) + final int? indexNumber; + @JsonKey(name: 'IndexNumberEnd', includeIfNull: false) + final int? indexNumberEnd; + @JsonKey(name: 'ParentIndexNumber', includeIfNull: false) + final int? parentIndexNumber; + @JsonKey(name: 'PremiereDate', includeIfNull: false) + final DateTime? premiereDate; + @JsonKey(name: 'ImageUrl', includeIfNull: false) + final String? imageUrl; + @JsonKey(name: 'SearchProviderName', includeIfNull: false) + final String? searchProviderName; + @JsonKey(name: 'Overview', includeIfNull: false) + final String? overview; + @JsonKey(name: 'AlbumArtist', includeIfNull: false) + final RemoteSearchResult? albumArtist; + @JsonKey( + name: 'Artists', + includeIfNull: false, + defaultValue: []) + final List? artists; + static const fromJsonFactory = _$RemoteSearchResultFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is RemoteSearchResult && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.providerIds, providerIds) || + const DeepCollectionEquality() + .equals(other.providerIds, providerIds)) && + (identical(other.productionYear, productionYear) || + const DeepCollectionEquality() + .equals(other.productionYear, productionYear)) && + (identical(other.indexNumber, indexNumber) || + const DeepCollectionEquality() + .equals(other.indexNumber, indexNumber)) && + (identical(other.indexNumberEnd, indexNumberEnd) || + const DeepCollectionEquality() + .equals(other.indexNumberEnd, indexNumberEnd)) && + (identical(other.parentIndexNumber, parentIndexNumber) || + const DeepCollectionEquality() + .equals(other.parentIndexNumber, parentIndexNumber)) && + (identical(other.premiereDate, premiereDate) || + const DeepCollectionEquality() + .equals(other.premiereDate, premiereDate)) && + (identical(other.imageUrl, imageUrl) || + const DeepCollectionEquality() + .equals(other.imageUrl, imageUrl)) && + (identical(other.searchProviderName, searchProviderName) || + const DeepCollectionEquality() + .equals(other.searchProviderName, searchProviderName)) && + (identical(other.overview, overview) || + const DeepCollectionEquality() + .equals(other.overview, overview)) && + (identical(other.albumArtist, albumArtist) || + const DeepCollectionEquality() + .equals(other.albumArtist, albumArtist)) && + (identical(other.artists, artists) || + const DeepCollectionEquality().equals(other.artists, artists))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(providerIds) ^ + const DeepCollectionEquality().hash(productionYear) ^ + const DeepCollectionEquality().hash(indexNumber) ^ + const DeepCollectionEquality().hash(indexNumberEnd) ^ + const DeepCollectionEquality().hash(parentIndexNumber) ^ + const DeepCollectionEquality().hash(premiereDate) ^ + const DeepCollectionEquality().hash(imageUrl) ^ + const DeepCollectionEquality().hash(searchProviderName) ^ + const DeepCollectionEquality().hash(overview) ^ + const DeepCollectionEquality().hash(albumArtist) ^ + const DeepCollectionEquality().hash(artists) ^ + runtimeType.hashCode; +} + +extension $RemoteSearchResultExtension on RemoteSearchResult { + RemoteSearchResult copyWith( + {String? name, + Map? providerIds, + int? productionYear, + int? indexNumber, + int? indexNumberEnd, + int? parentIndexNumber, + DateTime? premiereDate, + String? imageUrl, + String? searchProviderName, + String? overview, + RemoteSearchResult? albumArtist, + List? artists}) { + return RemoteSearchResult( + name: name ?? this.name, + providerIds: providerIds ?? this.providerIds, + productionYear: productionYear ?? this.productionYear, + indexNumber: indexNumber ?? this.indexNumber, + indexNumberEnd: indexNumberEnd ?? this.indexNumberEnd, + parentIndexNumber: parentIndexNumber ?? this.parentIndexNumber, + premiereDate: premiereDate ?? this.premiereDate, + imageUrl: imageUrl ?? this.imageUrl, + searchProviderName: searchProviderName ?? this.searchProviderName, + overview: overview ?? this.overview, + albumArtist: albumArtist ?? this.albumArtist, + artists: artists ?? this.artists); + } + + RemoteSearchResult copyWithWrapped( + {Wrapped? name, + Wrapped?>? providerIds, + Wrapped? productionYear, + Wrapped? indexNumber, + Wrapped? indexNumberEnd, + Wrapped? parentIndexNumber, + Wrapped? premiereDate, + Wrapped? imageUrl, + Wrapped? searchProviderName, + Wrapped? overview, + Wrapped? albumArtist, + Wrapped?>? artists}) { + return RemoteSearchResult( + name: (name != null ? name.value : this.name), + providerIds: + (providerIds != null ? providerIds.value : this.providerIds), + productionYear: (productionYear != null + ? productionYear.value + : this.productionYear), + indexNumber: + (indexNumber != null ? indexNumber.value : this.indexNumber), + indexNumberEnd: (indexNumberEnd != null + ? indexNumberEnd.value + : this.indexNumberEnd), + parentIndexNumber: (parentIndexNumber != null + ? parentIndexNumber.value + : this.parentIndexNumber), + premiereDate: + (premiereDate != null ? premiereDate.value : this.premiereDate), + imageUrl: (imageUrl != null ? imageUrl.value : this.imageUrl), + searchProviderName: (searchProviderName != null + ? searchProviderName.value + : this.searchProviderName), + overview: (overview != null ? overview.value : this.overview), + albumArtist: + (albumArtist != null ? albumArtist.value : this.albumArtist), + artists: (artists != null ? artists.value : this.artists)); + } +} + +@JsonSerializable(explicitToJson: true) +class RemoteSubtitleInfo { + const RemoteSubtitleInfo({ + this.threeLetterISOLanguageName, + this.id, + this.providerName, + this.name, + this.format, + this.author, + this.comment, + this.dateCreated, + this.communityRating, + this.frameRate, + this.downloadCount, + this.isHashMatch, + this.aiTranslated, + this.machineTranslated, + this.forced, + this.hearingImpaired, + }); + + factory RemoteSubtitleInfo.fromJson(Map json) => + _$RemoteSubtitleInfoFromJson(json); + + static const toJsonFactory = _$RemoteSubtitleInfoToJson; + Map toJson() => _$RemoteSubtitleInfoToJson(this); + + @JsonKey(name: 'ThreeLetterISOLanguageName', includeIfNull: false) + final String? threeLetterISOLanguageName; + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'ProviderName', includeIfNull: false) + final String? providerName; + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'Format', includeIfNull: false) + final String? format; + @JsonKey(name: 'Author', includeIfNull: false) + final String? author; + @JsonKey(name: 'Comment', includeIfNull: false) + final String? comment; + @JsonKey(name: 'DateCreated', includeIfNull: false) + final DateTime? dateCreated; + @JsonKey(name: 'CommunityRating', includeIfNull: false) + final double? communityRating; + @JsonKey(name: 'FrameRate', includeIfNull: false) + final double? frameRate; + @JsonKey(name: 'DownloadCount', includeIfNull: false) + final int? downloadCount; + @JsonKey(name: 'IsHashMatch', includeIfNull: false) + final bool? isHashMatch; + @JsonKey(name: 'AiTranslated', includeIfNull: false) + final bool? aiTranslated; + @JsonKey(name: 'MachineTranslated', includeIfNull: false) + final bool? machineTranslated; + @JsonKey(name: 'Forced', includeIfNull: false) + final bool? forced; + @JsonKey(name: 'HearingImpaired', includeIfNull: false) + final bool? hearingImpaired; + static const fromJsonFactory = _$RemoteSubtitleInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is RemoteSubtitleInfo && + (identical(other.threeLetterISOLanguageName, + threeLetterISOLanguageName) || + const DeepCollectionEquality().equals( + other.threeLetterISOLanguageName, + threeLetterISOLanguageName)) && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.providerName, providerName) || + const DeepCollectionEquality() + .equals(other.providerName, providerName)) && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.format, format) || + const DeepCollectionEquality().equals(other.format, format)) && + (identical(other.author, author) || + const DeepCollectionEquality().equals(other.author, author)) && + (identical(other.comment, comment) || + const DeepCollectionEquality() + .equals(other.comment, comment)) && + (identical(other.dateCreated, dateCreated) || + const DeepCollectionEquality() + .equals(other.dateCreated, dateCreated)) && + (identical(other.communityRating, communityRating) || + const DeepCollectionEquality() + .equals(other.communityRating, communityRating)) && + (identical(other.frameRate, frameRate) || + const DeepCollectionEquality() + .equals(other.frameRate, frameRate)) && + (identical(other.downloadCount, downloadCount) || + const DeepCollectionEquality() + .equals(other.downloadCount, downloadCount)) && + (identical(other.isHashMatch, isHashMatch) || + const DeepCollectionEquality() + .equals(other.isHashMatch, isHashMatch)) && + (identical(other.aiTranslated, aiTranslated) || + const DeepCollectionEquality() + .equals(other.aiTranslated, aiTranslated)) && + (identical(other.machineTranslated, machineTranslated) || + const DeepCollectionEquality() + .equals(other.machineTranslated, machineTranslated)) && + (identical(other.forced, forced) || + const DeepCollectionEquality().equals(other.forced, forced)) && + (identical(other.hearingImpaired, hearingImpaired) || + const DeepCollectionEquality() + .equals(other.hearingImpaired, hearingImpaired))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(threeLetterISOLanguageName) ^ + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(providerName) ^ + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(format) ^ + const DeepCollectionEquality().hash(author) ^ + const DeepCollectionEquality().hash(comment) ^ + const DeepCollectionEquality().hash(dateCreated) ^ + const DeepCollectionEquality().hash(communityRating) ^ + const DeepCollectionEquality().hash(frameRate) ^ + const DeepCollectionEquality().hash(downloadCount) ^ + const DeepCollectionEquality().hash(isHashMatch) ^ + const DeepCollectionEquality().hash(aiTranslated) ^ + const DeepCollectionEquality().hash(machineTranslated) ^ + const DeepCollectionEquality().hash(forced) ^ + const DeepCollectionEquality().hash(hearingImpaired) ^ + runtimeType.hashCode; +} + +extension $RemoteSubtitleInfoExtension on RemoteSubtitleInfo { + RemoteSubtitleInfo copyWith( + {String? threeLetterISOLanguageName, + String? id, + String? providerName, + String? name, + String? format, + String? author, + String? comment, + DateTime? dateCreated, + double? communityRating, + double? frameRate, + int? downloadCount, + bool? isHashMatch, + bool? aiTranslated, + bool? machineTranslated, + bool? forced, + bool? hearingImpaired}) { + return RemoteSubtitleInfo( + threeLetterISOLanguageName: + threeLetterISOLanguageName ?? this.threeLetterISOLanguageName, + id: id ?? this.id, + providerName: providerName ?? this.providerName, + name: name ?? this.name, + format: format ?? this.format, + author: author ?? this.author, + comment: comment ?? this.comment, + dateCreated: dateCreated ?? this.dateCreated, + communityRating: communityRating ?? this.communityRating, + frameRate: frameRate ?? this.frameRate, + downloadCount: downloadCount ?? this.downloadCount, + isHashMatch: isHashMatch ?? this.isHashMatch, + aiTranslated: aiTranslated ?? this.aiTranslated, + machineTranslated: machineTranslated ?? this.machineTranslated, + forced: forced ?? this.forced, + hearingImpaired: hearingImpaired ?? this.hearingImpaired); + } + + RemoteSubtitleInfo copyWithWrapped( + {Wrapped? threeLetterISOLanguageName, + Wrapped? id, + Wrapped? providerName, + Wrapped? name, + Wrapped? format, + Wrapped? author, + Wrapped? comment, + Wrapped? dateCreated, + Wrapped? communityRating, + Wrapped? frameRate, + Wrapped? downloadCount, + Wrapped? isHashMatch, + Wrapped? aiTranslated, + Wrapped? machineTranslated, + Wrapped? forced, + Wrapped? hearingImpaired}) { + return RemoteSubtitleInfo( + threeLetterISOLanguageName: (threeLetterISOLanguageName != null + ? threeLetterISOLanguageName.value + : this.threeLetterISOLanguageName), + id: (id != null ? id.value : this.id), + providerName: + (providerName != null ? providerName.value : this.providerName), + name: (name != null ? name.value : this.name), + format: (format != null ? format.value : this.format), + author: (author != null ? author.value : this.author), + comment: (comment != null ? comment.value : this.comment), + dateCreated: + (dateCreated != null ? dateCreated.value : this.dateCreated), + communityRating: (communityRating != null + ? communityRating.value + : this.communityRating), + frameRate: (frameRate != null ? frameRate.value : this.frameRate), + downloadCount: + (downloadCount != null ? downloadCount.value : this.downloadCount), + isHashMatch: + (isHashMatch != null ? isHashMatch.value : this.isHashMatch), + aiTranslated: + (aiTranslated != null ? aiTranslated.value : this.aiTranslated), + machineTranslated: (machineTranslated != null + ? machineTranslated.value + : this.machineTranslated), + forced: (forced != null ? forced.value : this.forced), + hearingImpaired: (hearingImpaired != null + ? hearingImpaired.value + : this.hearingImpaired)); + } +} + +@JsonSerializable(explicitToJson: true) +class RemoveFromPlaylistRequestDto { + const RemoveFromPlaylistRequestDto({ + this.playlistItemIds, + this.clearPlaylist, + this.clearPlayingItem, + }); + + factory RemoveFromPlaylistRequestDto.fromJson(Map json) => + _$RemoveFromPlaylistRequestDtoFromJson(json); + + static const toJsonFactory = _$RemoveFromPlaylistRequestDtoToJson; + Map toJson() => _$RemoveFromPlaylistRequestDtoToJson(this); + + @JsonKey( + name: 'PlaylistItemIds', includeIfNull: false, defaultValue: []) + final List? playlistItemIds; + @JsonKey(name: 'ClearPlaylist', includeIfNull: false) + final bool? clearPlaylist; + @JsonKey(name: 'ClearPlayingItem', includeIfNull: false) + final bool? clearPlayingItem; + static const fromJsonFactory = _$RemoveFromPlaylistRequestDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is RemoveFromPlaylistRequestDto && + (identical(other.playlistItemIds, playlistItemIds) || + const DeepCollectionEquality() + .equals(other.playlistItemIds, playlistItemIds)) && + (identical(other.clearPlaylist, clearPlaylist) || + const DeepCollectionEquality() + .equals(other.clearPlaylist, clearPlaylist)) && + (identical(other.clearPlayingItem, clearPlayingItem) || + const DeepCollectionEquality() + .equals(other.clearPlayingItem, clearPlayingItem))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(playlistItemIds) ^ + const DeepCollectionEquality().hash(clearPlaylist) ^ + const DeepCollectionEquality().hash(clearPlayingItem) ^ + runtimeType.hashCode; +} + +extension $RemoveFromPlaylistRequestDtoExtension + on RemoveFromPlaylistRequestDto { + RemoveFromPlaylistRequestDto copyWith( + {List? playlistItemIds, + bool? clearPlaylist, + bool? clearPlayingItem}) { + return RemoveFromPlaylistRequestDto( + playlistItemIds: playlistItemIds ?? this.playlistItemIds, + clearPlaylist: clearPlaylist ?? this.clearPlaylist, + clearPlayingItem: clearPlayingItem ?? this.clearPlayingItem); + } + + RemoveFromPlaylistRequestDto copyWithWrapped( + {Wrapped?>? playlistItemIds, + Wrapped? clearPlaylist, + Wrapped? clearPlayingItem}) { + return RemoveFromPlaylistRequestDto( + playlistItemIds: (playlistItemIds != null + ? playlistItemIds.value + : this.playlistItemIds), + clearPlaylist: + (clearPlaylist != null ? clearPlaylist.value : this.clearPlaylist), + clearPlayingItem: (clearPlayingItem != null + ? clearPlayingItem.value + : this.clearPlayingItem)); + } +} + +@JsonSerializable(explicitToJson: true) +class ReportPlaybackOptions { + const ReportPlaybackOptions({ + this.maxDataAge, + this.backupPath, + this.maxBackupFiles, + }); + + factory ReportPlaybackOptions.fromJson(Map json) => + _$ReportPlaybackOptionsFromJson(json); + + static const toJsonFactory = _$ReportPlaybackOptionsToJson; + Map toJson() => _$ReportPlaybackOptionsToJson(this); + + @JsonKey(name: 'MaxDataAge', includeIfNull: false) + final int? maxDataAge; + @JsonKey(name: 'BackupPath', includeIfNull: false) + final String? backupPath; + @JsonKey(name: 'MaxBackupFiles', includeIfNull: false) + final int? maxBackupFiles; + static const fromJsonFactory = _$ReportPlaybackOptionsFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ReportPlaybackOptions && + (identical(other.maxDataAge, maxDataAge) || + const DeepCollectionEquality() + .equals(other.maxDataAge, maxDataAge)) && + (identical(other.backupPath, backupPath) || + const DeepCollectionEquality() + .equals(other.backupPath, backupPath)) && + (identical(other.maxBackupFiles, maxBackupFiles) || + const DeepCollectionEquality() + .equals(other.maxBackupFiles, maxBackupFiles))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(maxDataAge) ^ + const DeepCollectionEquality().hash(backupPath) ^ + const DeepCollectionEquality().hash(maxBackupFiles) ^ + runtimeType.hashCode; +} + +extension $ReportPlaybackOptionsExtension on ReportPlaybackOptions { + ReportPlaybackOptions copyWith( + {int? maxDataAge, String? backupPath, int? maxBackupFiles}) { + return ReportPlaybackOptions( + maxDataAge: maxDataAge ?? this.maxDataAge, + backupPath: backupPath ?? this.backupPath, + maxBackupFiles: maxBackupFiles ?? this.maxBackupFiles); + } + + ReportPlaybackOptions copyWithWrapped( + {Wrapped? maxDataAge, + Wrapped? backupPath, + Wrapped? maxBackupFiles}) { + return ReportPlaybackOptions( + maxDataAge: (maxDataAge != null ? maxDataAge.value : this.maxDataAge), + backupPath: (backupPath != null ? backupPath.value : this.backupPath), + maxBackupFiles: (maxBackupFiles != null + ? maxBackupFiles.value + : this.maxBackupFiles)); + } +} + +@JsonSerializable(explicitToJson: true) +class RepositoryInfo { + const RepositoryInfo({ + this.name, + this.url, + this.enabled, + }); + + factory RepositoryInfo.fromJson(Map json) => + _$RepositoryInfoFromJson(json); + + static const toJsonFactory = _$RepositoryInfoToJson; + Map toJson() => _$RepositoryInfoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'Url', includeIfNull: false) + final String? url; + @JsonKey(name: 'Enabled', includeIfNull: false) + final bool? enabled; + static const fromJsonFactory = _$RepositoryInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is RepositoryInfo && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.url, url) || + const DeepCollectionEquality().equals(other.url, url)) && + (identical(other.enabled, enabled) || + const DeepCollectionEquality().equals(other.enabled, enabled))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(url) ^ + const DeepCollectionEquality().hash(enabled) ^ + runtimeType.hashCode; +} + +extension $RepositoryInfoExtension on RepositoryInfo { + RepositoryInfo copyWith({String? name, String? url, bool? enabled}) { + return RepositoryInfo( + name: name ?? this.name, + url: url ?? this.url, + enabled: enabled ?? this.enabled); + } + + RepositoryInfo copyWithWrapped( + {Wrapped? name, + Wrapped? url, + Wrapped? enabled}) { + return RepositoryInfo( + name: (name != null ? name.value : this.name), + url: (url != null ? url.value : this.url), + enabled: (enabled != null ? enabled.value : this.enabled)); + } +} + +@JsonSerializable(explicitToJson: true) +class RestartRequiredMessage { + const RestartRequiredMessage({ + this.messageId, + this.messageType, + }); + + factory RestartRequiredMessage.fromJson(Map json) => + _$RestartRequiredMessageFromJson(json); + + static const toJsonFactory = _$RestartRequiredMessageToJson; + Map toJson() => _$RestartRequiredMessageToJson(this); + + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.restartrequired); + + static const fromJsonFactory = _$RestartRequiredMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is RestartRequiredMessage && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $RestartRequiredMessageExtension on RestartRequiredMessage { + RestartRequiredMessage copyWith( + {String? messageId, enums.SessionMessageType? messageType}) { + return RestartRequiredMessage( + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + RestartRequiredMessage copyWithWrapped( + {Wrapped? messageId, + Wrapped? messageType}) { + return RestartRequiredMessage( + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class ScheduledTaskEndedMessage { + const ScheduledTaskEndedMessage({ + this.data, + this.messageId, + this.messageType, + }); + + factory ScheduledTaskEndedMessage.fromJson(Map json) => + _$ScheduledTaskEndedMessageFromJson(json); + + static const toJsonFactory = _$ScheduledTaskEndedMessageToJson; + Map toJson() => _$ScheduledTaskEndedMessageToJson(this); + + @JsonKey(name: 'Data', includeIfNull: false) + final TaskResult? data; + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.scheduledtaskended); + + static const fromJsonFactory = _$ScheduledTaskEndedMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ScheduledTaskEndedMessage && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data)) && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(data) ^ + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $ScheduledTaskEndedMessageExtension on ScheduledTaskEndedMessage { + ScheduledTaskEndedMessage copyWith( + {TaskResult? data, + String? messageId, + enums.SessionMessageType? messageType}) { + return ScheduledTaskEndedMessage( + data: data ?? this.data, + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + ScheduledTaskEndedMessage copyWithWrapped( + {Wrapped? data, + Wrapped? messageId, + Wrapped? messageType}) { + return ScheduledTaskEndedMessage( + data: (data != null ? data.value : this.data), + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class ScheduledTasksInfoMessage { + const ScheduledTasksInfoMessage({ + this.data, + this.messageId, + this.messageType, + }); + + factory ScheduledTasksInfoMessage.fromJson(Map json) => + _$ScheduledTasksInfoMessageFromJson(json); + + static const toJsonFactory = _$ScheduledTasksInfoMessageToJson; + Map toJson() => _$ScheduledTasksInfoMessageToJson(this); + + @JsonKey(name: 'Data', includeIfNull: false, defaultValue: []) + final List? data; + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.scheduledtasksinfo); + + static const fromJsonFactory = _$ScheduledTasksInfoMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ScheduledTasksInfoMessage && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data)) && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(data) ^ + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $ScheduledTasksInfoMessageExtension on ScheduledTasksInfoMessage { + ScheduledTasksInfoMessage copyWith( + {List? data, + String? messageId, + enums.SessionMessageType? messageType}) { + return ScheduledTasksInfoMessage( + data: data ?? this.data, + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + ScheduledTasksInfoMessage copyWithWrapped( + {Wrapped?>? data, + Wrapped? messageId, + Wrapped? messageType}) { + return ScheduledTasksInfoMessage( + data: (data != null ? data.value : this.data), + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class ScheduledTasksInfoStartMessage { + const ScheduledTasksInfoStartMessage({ + this.data, + this.messageType, + }); + + factory ScheduledTasksInfoStartMessage.fromJson(Map json) => + _$ScheduledTasksInfoStartMessageFromJson(json); + + static const toJsonFactory = _$ScheduledTasksInfoStartMessageToJson; + Map toJson() => _$ScheduledTasksInfoStartMessageToJson(this); + + @JsonKey(name: 'Data', includeIfNull: false) + final String? data; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.scheduledtasksinfostart); + + static const fromJsonFactory = _$ScheduledTasksInfoStartMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ScheduledTasksInfoStartMessage && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(data) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $ScheduledTasksInfoStartMessageExtension + on ScheduledTasksInfoStartMessage { + ScheduledTasksInfoStartMessage copyWith( + {String? data, enums.SessionMessageType? messageType}) { + return ScheduledTasksInfoStartMessage( + data: data ?? this.data, messageType: messageType ?? this.messageType); + } + + ScheduledTasksInfoStartMessage copyWithWrapped( + {Wrapped? data, + Wrapped? messageType}) { + return ScheduledTasksInfoStartMessage( + data: (data != null ? data.value : this.data), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class ScheduledTasksInfoStopMessage { + const ScheduledTasksInfoStopMessage({ + this.messageType, + }); + + factory ScheduledTasksInfoStopMessage.fromJson(Map json) => + _$ScheduledTasksInfoStopMessageFromJson(json); + + static const toJsonFactory = _$ScheduledTasksInfoStopMessageToJson; + Map toJson() => _$ScheduledTasksInfoStopMessageToJson(this); + + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.scheduledtasksinfostop); + + static const fromJsonFactory = _$ScheduledTasksInfoStopMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ScheduledTasksInfoStopMessage && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(messageType) ^ runtimeType.hashCode; +} + +extension $ScheduledTasksInfoStopMessageExtension + on ScheduledTasksInfoStopMessage { + ScheduledTasksInfoStopMessage copyWith( + {enums.SessionMessageType? messageType}) { + return ScheduledTasksInfoStopMessage( + messageType: messageType ?? this.messageType); + } + + ScheduledTasksInfoStopMessage copyWithWrapped( + {Wrapped? messageType}) { + return ScheduledTasksInfoStopMessage( + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class SearchHint { + const SearchHint({ + this.itemId, + this.id, + this.name, + this.matchedTerm, + this.indexNumber, + this.productionYear, + this.parentIndexNumber, + this.primaryImageTag, + this.thumbImageTag, + this.thumbImageItemId, + this.backdropImageTag, + this.backdropImageItemId, + this.type, + this.isFolder, + this.runTimeTicks, + this.mediaType, + this.startDate, + this.endDate, + this.series, + this.status, + this.album, + this.albumId, + this.albumArtist, + this.artists, + this.songCount, + this.episodeCount, + this.channelId, + this.channelName, + this.primaryImageAspectRatio, + }); + + factory SearchHint.fromJson(Map json) => + _$SearchHintFromJson(json); + + static const toJsonFactory = _$SearchHintToJson; + Map toJson() => _$SearchHintToJson(this); + + @JsonKey(name: 'ItemId', includeIfNull: false) + @deprecated + final String? itemId; + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'MatchedTerm', includeIfNull: false) + final String? matchedTerm; + @JsonKey(name: 'IndexNumber', includeIfNull: false) + final int? indexNumber; + @JsonKey(name: 'ProductionYear', includeIfNull: false) + final int? productionYear; + @JsonKey(name: 'ParentIndexNumber', includeIfNull: false) + final int? parentIndexNumber; + @JsonKey(name: 'PrimaryImageTag', includeIfNull: false) + final String? primaryImageTag; + @JsonKey(name: 'ThumbImageTag', includeIfNull: false) + final String? thumbImageTag; + @JsonKey(name: 'ThumbImageItemId', includeIfNull: false) + final String? thumbImageItemId; + @JsonKey(name: 'BackdropImageTag', includeIfNull: false) + final String? backdropImageTag; + @JsonKey(name: 'BackdropImageItemId', includeIfNull: false) + final String? backdropImageItemId; + @JsonKey( + name: 'Type', + includeIfNull: false, + toJson: baseItemKindNullableToJson, + fromJson: baseItemKindNullableFromJson, + ) + final enums.BaseItemKind? type; + @JsonKey(name: 'IsFolder', includeIfNull: false) + final bool? isFolder; + @JsonKey(name: 'RunTimeTicks', includeIfNull: false) + final int? runTimeTicks; + @JsonKey( + name: 'MediaType', + includeIfNull: false, + toJson: mediaTypeNullableToJson, + fromJson: mediaTypeNullableFromJson, + ) + final enums.MediaType? mediaType; + @JsonKey(name: 'StartDate', includeIfNull: false) + final DateTime? startDate; + @JsonKey(name: 'EndDate', includeIfNull: false) + final DateTime? endDate; + @JsonKey(name: 'Series', includeIfNull: false) + final String? series; + @JsonKey(name: 'Status', includeIfNull: false) + final String? status; + @JsonKey(name: 'Album', includeIfNull: false) + final String? album; + @JsonKey(name: 'AlbumId', includeIfNull: false) + final String? albumId; + @JsonKey(name: 'AlbumArtist', includeIfNull: false) + final String? albumArtist; + @JsonKey(name: 'Artists', includeIfNull: false, defaultValue: []) + final List? artists; + @JsonKey(name: 'SongCount', includeIfNull: false) + final int? songCount; + @JsonKey(name: 'EpisodeCount', includeIfNull: false) + final int? episodeCount; + @JsonKey(name: 'ChannelId', includeIfNull: false) + final String? channelId; + @JsonKey(name: 'ChannelName', includeIfNull: false) + final String? channelName; + @JsonKey(name: 'PrimaryImageAspectRatio', includeIfNull: false) + final double? primaryImageAspectRatio; + static const fromJsonFactory = _$SearchHintFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is SearchHint && + (identical(other.itemId, itemId) || + const DeepCollectionEquality().equals(other.itemId, itemId)) && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.matchedTerm, matchedTerm) || + const DeepCollectionEquality() + .equals(other.matchedTerm, matchedTerm)) && + (identical(other.indexNumber, indexNumber) || + const DeepCollectionEquality() + .equals(other.indexNumber, indexNumber)) && + (identical(other.productionYear, productionYear) || + const DeepCollectionEquality() + .equals(other.productionYear, productionYear)) && + (identical(other.parentIndexNumber, parentIndexNumber) || + const DeepCollectionEquality() + .equals(other.parentIndexNumber, parentIndexNumber)) && + (identical(other.primaryImageTag, primaryImageTag) || + const DeepCollectionEquality() + .equals(other.primaryImageTag, primaryImageTag)) && + (identical(other.thumbImageTag, thumbImageTag) || + const DeepCollectionEquality() + .equals(other.thumbImageTag, thumbImageTag)) && + (identical(other.thumbImageItemId, thumbImageItemId) || + const DeepCollectionEquality() + .equals(other.thumbImageItemId, thumbImageItemId)) && + (identical(other.backdropImageTag, backdropImageTag) || + const DeepCollectionEquality() + .equals(other.backdropImageTag, backdropImageTag)) && + (identical(other.backdropImageItemId, backdropImageItemId) || + const DeepCollectionEquality() + .equals(other.backdropImageItemId, backdropImageItemId)) && + (identical(other.type, type) || + const DeepCollectionEquality().equals(other.type, type)) && + (identical(other.isFolder, isFolder) || + const DeepCollectionEquality() + .equals(other.isFolder, isFolder)) && + (identical(other.runTimeTicks, runTimeTicks) || + const DeepCollectionEquality() + .equals(other.runTimeTicks, runTimeTicks)) && + (identical(other.mediaType, mediaType) || + const DeepCollectionEquality() + .equals(other.mediaType, mediaType)) && + (identical(other.startDate, startDate) || + const DeepCollectionEquality() + .equals(other.startDate, startDate)) && + (identical(other.endDate, endDate) || + const DeepCollectionEquality() + .equals(other.endDate, endDate)) && + (identical(other.series, series) || + const DeepCollectionEquality().equals(other.series, series)) && + (identical(other.status, status) || + const DeepCollectionEquality().equals(other.status, status)) && + (identical(other.album, album) || + const DeepCollectionEquality().equals(other.album, album)) && + (identical(other.albumId, albumId) || + const DeepCollectionEquality() + .equals(other.albumId, albumId)) && + (identical(other.albumArtist, albumArtist) || + const DeepCollectionEquality() + .equals(other.albumArtist, albumArtist)) && + (identical(other.artists, artists) || + const DeepCollectionEquality() + .equals(other.artists, artists)) && + (identical(other.songCount, songCount) || + const DeepCollectionEquality() + .equals(other.songCount, songCount)) && + (identical(other.episodeCount, episodeCount) || const DeepCollectionEquality().equals(other.episodeCount, episodeCount)) && + (identical(other.channelId, channelId) || const DeepCollectionEquality().equals(other.channelId, channelId)) && + (identical(other.channelName, channelName) || const DeepCollectionEquality().equals(other.channelName, channelName)) && + (identical(other.primaryImageAspectRatio, primaryImageAspectRatio) || const DeepCollectionEquality().equals(other.primaryImageAspectRatio, primaryImageAspectRatio))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(itemId) ^ + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(matchedTerm) ^ + const DeepCollectionEquality().hash(indexNumber) ^ + const DeepCollectionEquality().hash(productionYear) ^ + const DeepCollectionEquality().hash(parentIndexNumber) ^ + const DeepCollectionEquality().hash(primaryImageTag) ^ + const DeepCollectionEquality().hash(thumbImageTag) ^ + const DeepCollectionEquality().hash(thumbImageItemId) ^ + const DeepCollectionEquality().hash(backdropImageTag) ^ + const DeepCollectionEquality().hash(backdropImageItemId) ^ + const DeepCollectionEquality().hash(type) ^ + const DeepCollectionEquality().hash(isFolder) ^ + const DeepCollectionEquality().hash(runTimeTicks) ^ + const DeepCollectionEquality().hash(mediaType) ^ + const DeepCollectionEquality().hash(startDate) ^ + const DeepCollectionEquality().hash(endDate) ^ + const DeepCollectionEquality().hash(series) ^ + const DeepCollectionEquality().hash(status) ^ + const DeepCollectionEquality().hash(album) ^ + const DeepCollectionEquality().hash(albumId) ^ + const DeepCollectionEquality().hash(albumArtist) ^ + const DeepCollectionEquality().hash(artists) ^ + const DeepCollectionEquality().hash(songCount) ^ + const DeepCollectionEquality().hash(episodeCount) ^ + const DeepCollectionEquality().hash(channelId) ^ + const DeepCollectionEquality().hash(channelName) ^ + const DeepCollectionEquality().hash(primaryImageAspectRatio) ^ + runtimeType.hashCode; +} + +extension $SearchHintExtension on SearchHint { + SearchHint copyWith( + {String? itemId, + String? id, + String? name, + String? matchedTerm, + int? indexNumber, + int? productionYear, + int? parentIndexNumber, + String? primaryImageTag, + String? thumbImageTag, + String? thumbImageItemId, + String? backdropImageTag, + String? backdropImageItemId, + enums.BaseItemKind? type, + bool? isFolder, + int? runTimeTicks, + enums.MediaType? mediaType, + DateTime? startDate, + DateTime? endDate, + String? series, + String? status, + String? album, + String? albumId, + String? albumArtist, + List? artists, + int? songCount, + int? episodeCount, + String? channelId, + String? channelName, + double? primaryImageAspectRatio}) { + return SearchHint( + itemId: itemId ?? this.itemId, + id: id ?? this.id, + name: name ?? this.name, + matchedTerm: matchedTerm ?? this.matchedTerm, + indexNumber: indexNumber ?? this.indexNumber, + productionYear: productionYear ?? this.productionYear, + parentIndexNumber: parentIndexNumber ?? this.parentIndexNumber, + primaryImageTag: primaryImageTag ?? this.primaryImageTag, + thumbImageTag: thumbImageTag ?? this.thumbImageTag, + thumbImageItemId: thumbImageItemId ?? this.thumbImageItemId, + backdropImageTag: backdropImageTag ?? this.backdropImageTag, + backdropImageItemId: backdropImageItemId ?? this.backdropImageItemId, + type: type ?? this.type, + isFolder: isFolder ?? this.isFolder, + runTimeTicks: runTimeTicks ?? this.runTimeTicks, + mediaType: mediaType ?? this.mediaType, + startDate: startDate ?? this.startDate, + endDate: endDate ?? this.endDate, + series: series ?? this.series, + status: status ?? this.status, + album: album ?? this.album, + albumId: albumId ?? this.albumId, + albumArtist: albumArtist ?? this.albumArtist, + artists: artists ?? this.artists, + songCount: songCount ?? this.songCount, + episodeCount: episodeCount ?? this.episodeCount, + channelId: channelId ?? this.channelId, + channelName: channelName ?? this.channelName, + primaryImageAspectRatio: + primaryImageAspectRatio ?? this.primaryImageAspectRatio); + } + + SearchHint copyWithWrapped( + {Wrapped? itemId, + Wrapped? id, + Wrapped? name, + Wrapped? matchedTerm, + Wrapped? indexNumber, + Wrapped? productionYear, + Wrapped? parentIndexNumber, + Wrapped? primaryImageTag, + Wrapped? thumbImageTag, + Wrapped? thumbImageItemId, + Wrapped? backdropImageTag, + Wrapped? backdropImageItemId, + Wrapped? type, + Wrapped? isFolder, + Wrapped? runTimeTicks, + Wrapped? mediaType, + Wrapped? startDate, + Wrapped? endDate, + Wrapped? series, + Wrapped? status, + Wrapped? album, + Wrapped? albumId, + Wrapped? albumArtist, + Wrapped?>? artists, + Wrapped? songCount, + Wrapped? episodeCount, + Wrapped? channelId, + Wrapped? channelName, + Wrapped? primaryImageAspectRatio}) { + return SearchHint( + itemId: (itemId != null ? itemId.value : this.itemId), + id: (id != null ? id.value : this.id), + name: (name != null ? name.value : this.name), + matchedTerm: + (matchedTerm != null ? matchedTerm.value : this.matchedTerm), + indexNumber: + (indexNumber != null ? indexNumber.value : this.indexNumber), + productionYear: (productionYear != null + ? productionYear.value + : this.productionYear), + parentIndexNumber: (parentIndexNumber != null + ? parentIndexNumber.value + : this.parentIndexNumber), + primaryImageTag: (primaryImageTag != null + ? primaryImageTag.value + : this.primaryImageTag), + thumbImageTag: + (thumbImageTag != null ? thumbImageTag.value : this.thumbImageTag), + thumbImageItemId: (thumbImageItemId != null + ? thumbImageItemId.value + : this.thumbImageItemId), + backdropImageTag: (backdropImageTag != null + ? backdropImageTag.value + : this.backdropImageTag), + backdropImageItemId: (backdropImageItemId != null + ? backdropImageItemId.value + : this.backdropImageItemId), + type: (type != null ? type.value : this.type), + isFolder: (isFolder != null ? isFolder.value : this.isFolder), + runTimeTicks: + (runTimeTicks != null ? runTimeTicks.value : this.runTimeTicks), + mediaType: (mediaType != null ? mediaType.value : this.mediaType), + startDate: (startDate != null ? startDate.value : this.startDate), + endDate: (endDate != null ? endDate.value : this.endDate), + series: (series != null ? series.value : this.series), + status: (status != null ? status.value : this.status), + album: (album != null ? album.value : this.album), + albumId: (albumId != null ? albumId.value : this.albumId), + albumArtist: + (albumArtist != null ? albumArtist.value : this.albumArtist), + artists: (artists != null ? artists.value : this.artists), + songCount: (songCount != null ? songCount.value : this.songCount), + episodeCount: + (episodeCount != null ? episodeCount.value : this.episodeCount), + channelId: (channelId != null ? channelId.value : this.channelId), + channelName: + (channelName != null ? channelName.value : this.channelName), + primaryImageAspectRatio: (primaryImageAspectRatio != null + ? primaryImageAspectRatio.value + : this.primaryImageAspectRatio)); + } +} + +@JsonSerializable(explicitToJson: true) +class SearchHintResult { + const SearchHintResult({ + this.searchHints, + this.totalRecordCount, + }); + + factory SearchHintResult.fromJson(Map json) => + _$SearchHintResultFromJson(json); + + static const toJsonFactory = _$SearchHintResultToJson; + Map toJson() => _$SearchHintResultToJson(this); + + @JsonKey( + name: 'SearchHints', includeIfNull: false, defaultValue: []) + final List? searchHints; + @JsonKey(name: 'TotalRecordCount', includeIfNull: false) + final int? totalRecordCount; + static const fromJsonFactory = _$SearchHintResultFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is SearchHintResult && + (identical(other.searchHints, searchHints) || + const DeepCollectionEquality() + .equals(other.searchHints, searchHints)) && + (identical(other.totalRecordCount, totalRecordCount) || + const DeepCollectionEquality() + .equals(other.totalRecordCount, totalRecordCount))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(searchHints) ^ + const DeepCollectionEquality().hash(totalRecordCount) ^ + runtimeType.hashCode; +} + +extension $SearchHintResultExtension on SearchHintResult { + SearchHintResult copyWith( + {List? searchHints, int? totalRecordCount}) { + return SearchHintResult( + searchHints: searchHints ?? this.searchHints, + totalRecordCount: totalRecordCount ?? this.totalRecordCount); + } + + SearchHintResult copyWithWrapped( + {Wrapped?>? searchHints, + Wrapped? totalRecordCount}) { + return SearchHintResult( + searchHints: + (searchHints != null ? searchHints.value : this.searchHints), + totalRecordCount: (totalRecordCount != null + ? totalRecordCount.value + : this.totalRecordCount)); + } +} + +@JsonSerializable(explicitToJson: true) +class SeekRequestDto { + const SeekRequestDto({ + this.positionTicks, + }); + + factory SeekRequestDto.fromJson(Map json) => + _$SeekRequestDtoFromJson(json); + + static const toJsonFactory = _$SeekRequestDtoToJson; + Map toJson() => _$SeekRequestDtoToJson(this); + + @JsonKey(name: 'PositionTicks', includeIfNull: false) + final int? positionTicks; + static const fromJsonFactory = _$SeekRequestDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is SeekRequestDto && + (identical(other.positionTicks, positionTicks) || + const DeepCollectionEquality() + .equals(other.positionTicks, positionTicks))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(positionTicks) ^ runtimeType.hashCode; +} + +extension $SeekRequestDtoExtension on SeekRequestDto { + SeekRequestDto copyWith({int? positionTicks}) { + return SeekRequestDto(positionTicks: positionTicks ?? this.positionTicks); + } + + SeekRequestDto copyWithWrapped({Wrapped? positionTicks}) { + return SeekRequestDto( + positionTicks: + (positionTicks != null ? positionTicks.value : this.positionTicks)); + } +} + +@JsonSerializable(explicitToJson: true) +class SendCommand { + const SendCommand({ + this.groupId, + this.playlistItemId, + this.when, + this.positionTicks, + this.command, + this.emittedAt, + }); + + factory SendCommand.fromJson(Map json) => + _$SendCommandFromJson(json); + + static const toJsonFactory = _$SendCommandToJson; + Map toJson() => _$SendCommandToJson(this); + + @JsonKey(name: 'GroupId', includeIfNull: false) + final String? groupId; + @JsonKey(name: 'PlaylistItemId', includeIfNull: false) + final String? playlistItemId; + @JsonKey(name: 'When', includeIfNull: false) + final DateTime? when; + @JsonKey(name: 'PositionTicks', includeIfNull: false) + final int? positionTicks; + @JsonKey( + name: 'Command', + includeIfNull: false, + toJson: sendCommandTypeNullableToJson, + fromJson: sendCommandTypeNullableFromJson, + ) + final enums.SendCommandType? command; + @JsonKey(name: 'EmittedAt', includeIfNull: false) + final DateTime? emittedAt; + static const fromJsonFactory = _$SendCommandFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is SendCommand && + (identical(other.groupId, groupId) || + const DeepCollectionEquality() + .equals(other.groupId, groupId)) && + (identical(other.playlistItemId, playlistItemId) || + const DeepCollectionEquality() + .equals(other.playlistItemId, playlistItemId)) && + (identical(other.when, when) || + const DeepCollectionEquality().equals(other.when, when)) && + (identical(other.positionTicks, positionTicks) || + const DeepCollectionEquality() + .equals(other.positionTicks, positionTicks)) && + (identical(other.command, command) || + const DeepCollectionEquality() + .equals(other.command, command)) && + (identical(other.emittedAt, emittedAt) || + const DeepCollectionEquality() + .equals(other.emittedAt, emittedAt))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(groupId) ^ + const DeepCollectionEquality().hash(playlistItemId) ^ + const DeepCollectionEquality().hash(when) ^ + const DeepCollectionEquality().hash(positionTicks) ^ + const DeepCollectionEquality().hash(command) ^ + const DeepCollectionEquality().hash(emittedAt) ^ + runtimeType.hashCode; +} + +extension $SendCommandExtension on SendCommand { + SendCommand copyWith( + {String? groupId, + String? playlistItemId, + DateTime? when, + int? positionTicks, + enums.SendCommandType? command, + DateTime? emittedAt}) { + return SendCommand( + groupId: groupId ?? this.groupId, + playlistItemId: playlistItemId ?? this.playlistItemId, + when: when ?? this.when, + positionTicks: positionTicks ?? this.positionTicks, + command: command ?? this.command, + emittedAt: emittedAt ?? this.emittedAt); + } + + SendCommand copyWithWrapped( + {Wrapped? groupId, + Wrapped? playlistItemId, + Wrapped? when, + Wrapped? positionTicks, + Wrapped? command, + Wrapped? emittedAt}) { + return SendCommand( + groupId: (groupId != null ? groupId.value : this.groupId), + playlistItemId: (playlistItemId != null + ? playlistItemId.value + : this.playlistItemId), + when: (when != null ? when.value : this.when), + positionTicks: + (positionTicks != null ? positionTicks.value : this.positionTicks), + command: (command != null ? command.value : this.command), + emittedAt: (emittedAt != null ? emittedAt.value : this.emittedAt)); + } +} + +@JsonSerializable(explicitToJson: true) +class SeriesInfo { + const SeriesInfo({ + this.name, + this.originalTitle, + this.path, + this.metadataLanguage, + this.metadataCountryCode, + this.providerIds, + this.year, + this.indexNumber, + this.parentIndexNumber, + this.premiereDate, + this.isAutomated, + }); + + factory SeriesInfo.fromJson(Map json) => + _$SeriesInfoFromJson(json); + + static const toJsonFactory = _$SeriesInfoToJson; + Map toJson() => _$SeriesInfoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'OriginalTitle', includeIfNull: false) + final String? originalTitle; + @JsonKey(name: 'Path', includeIfNull: false) + final String? path; + @JsonKey(name: 'MetadataLanguage', includeIfNull: false) + final String? metadataLanguage; + @JsonKey(name: 'MetadataCountryCode', includeIfNull: false) + final String? metadataCountryCode; + @JsonKey(name: 'ProviderIds', includeIfNull: false) + final Map? providerIds; + @JsonKey(name: 'Year', includeIfNull: false) + final int? year; + @JsonKey(name: 'IndexNumber', includeIfNull: false) + final int? indexNumber; + @JsonKey(name: 'ParentIndexNumber', includeIfNull: false) + final int? parentIndexNumber; + @JsonKey(name: 'PremiereDate', includeIfNull: false) + final DateTime? premiereDate; + @JsonKey(name: 'IsAutomated', includeIfNull: false) + final bool? isAutomated; + static const fromJsonFactory = _$SeriesInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is SeriesInfo && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.originalTitle, originalTitle) || + const DeepCollectionEquality() + .equals(other.originalTitle, originalTitle)) && + (identical(other.path, path) || + const DeepCollectionEquality().equals(other.path, path)) && + (identical(other.metadataLanguage, metadataLanguage) || + const DeepCollectionEquality() + .equals(other.metadataLanguage, metadataLanguage)) && + (identical(other.metadataCountryCode, metadataCountryCode) || + const DeepCollectionEquality() + .equals(other.metadataCountryCode, metadataCountryCode)) && + (identical(other.providerIds, providerIds) || + const DeepCollectionEquality() + .equals(other.providerIds, providerIds)) && + (identical(other.year, year) || + const DeepCollectionEquality().equals(other.year, year)) && + (identical(other.indexNumber, indexNumber) || + const DeepCollectionEquality() + .equals(other.indexNumber, indexNumber)) && + (identical(other.parentIndexNumber, parentIndexNumber) || + const DeepCollectionEquality() + .equals(other.parentIndexNumber, parentIndexNumber)) && + (identical(other.premiereDate, premiereDate) || + const DeepCollectionEquality() + .equals(other.premiereDate, premiereDate)) && + (identical(other.isAutomated, isAutomated) || + const DeepCollectionEquality() + .equals(other.isAutomated, isAutomated))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(originalTitle) ^ + const DeepCollectionEquality().hash(path) ^ + const DeepCollectionEquality().hash(metadataLanguage) ^ + const DeepCollectionEquality().hash(metadataCountryCode) ^ + const DeepCollectionEquality().hash(providerIds) ^ + const DeepCollectionEquality().hash(year) ^ + const DeepCollectionEquality().hash(indexNumber) ^ + const DeepCollectionEquality().hash(parentIndexNumber) ^ + const DeepCollectionEquality().hash(premiereDate) ^ + const DeepCollectionEquality().hash(isAutomated) ^ + runtimeType.hashCode; +} + +extension $SeriesInfoExtension on SeriesInfo { + SeriesInfo copyWith( + {String? name, + String? originalTitle, + String? path, + String? metadataLanguage, + String? metadataCountryCode, + Map? providerIds, + int? year, + int? indexNumber, + int? parentIndexNumber, + DateTime? premiereDate, + bool? isAutomated}) { + return SeriesInfo( + name: name ?? this.name, + originalTitle: originalTitle ?? this.originalTitle, + path: path ?? this.path, + metadataLanguage: metadataLanguage ?? this.metadataLanguage, + metadataCountryCode: metadataCountryCode ?? this.metadataCountryCode, + providerIds: providerIds ?? this.providerIds, + year: year ?? this.year, + indexNumber: indexNumber ?? this.indexNumber, + parentIndexNumber: parentIndexNumber ?? this.parentIndexNumber, + premiereDate: premiereDate ?? this.premiereDate, + isAutomated: isAutomated ?? this.isAutomated); + } + + SeriesInfo copyWithWrapped( + {Wrapped? name, + Wrapped? originalTitle, + Wrapped? path, + Wrapped? metadataLanguage, + Wrapped? metadataCountryCode, + Wrapped?>? providerIds, + Wrapped? year, + Wrapped? indexNumber, + Wrapped? parentIndexNumber, + Wrapped? premiereDate, + Wrapped? isAutomated}) { + return SeriesInfo( + name: (name != null ? name.value : this.name), + originalTitle: + (originalTitle != null ? originalTitle.value : this.originalTitle), + path: (path != null ? path.value : this.path), + metadataLanguage: (metadataLanguage != null + ? metadataLanguage.value + : this.metadataLanguage), + metadataCountryCode: (metadataCountryCode != null + ? metadataCountryCode.value + : this.metadataCountryCode), + providerIds: + (providerIds != null ? providerIds.value : this.providerIds), + year: (year != null ? year.value : this.year), + indexNumber: + (indexNumber != null ? indexNumber.value : this.indexNumber), + parentIndexNumber: (parentIndexNumber != null + ? parentIndexNumber.value + : this.parentIndexNumber), + premiereDate: + (premiereDate != null ? premiereDate.value : this.premiereDate), + isAutomated: + (isAutomated != null ? isAutomated.value : this.isAutomated)); + } +} + +@JsonSerializable(explicitToJson: true) +class SeriesInfoRemoteSearchQuery { + const SeriesInfoRemoteSearchQuery({ + this.searchInfo, + this.itemId, + this.searchProviderName, + this.includeDisabledProviders, + }); + + factory SeriesInfoRemoteSearchQuery.fromJson(Map json) => + _$SeriesInfoRemoteSearchQueryFromJson(json); + + static const toJsonFactory = _$SeriesInfoRemoteSearchQueryToJson; + Map toJson() => _$SeriesInfoRemoteSearchQueryToJson(this); + + @JsonKey(name: 'SearchInfo', includeIfNull: false) + final SeriesInfo? searchInfo; + @JsonKey(name: 'ItemId', includeIfNull: false) + final String? itemId; + @JsonKey(name: 'SearchProviderName', includeIfNull: false) + final String? searchProviderName; + @JsonKey(name: 'IncludeDisabledProviders', includeIfNull: false) + final bool? includeDisabledProviders; + static const fromJsonFactory = _$SeriesInfoRemoteSearchQueryFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is SeriesInfoRemoteSearchQuery && + (identical(other.searchInfo, searchInfo) || + const DeepCollectionEquality() + .equals(other.searchInfo, searchInfo)) && + (identical(other.itemId, itemId) || + const DeepCollectionEquality().equals(other.itemId, itemId)) && + (identical(other.searchProviderName, searchProviderName) || + const DeepCollectionEquality() + .equals(other.searchProviderName, searchProviderName)) && + (identical( + other.includeDisabledProviders, includeDisabledProviders) || + const DeepCollectionEquality().equals( + other.includeDisabledProviders, includeDisabledProviders))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(searchInfo) ^ + const DeepCollectionEquality().hash(itemId) ^ + const DeepCollectionEquality().hash(searchProviderName) ^ + const DeepCollectionEquality().hash(includeDisabledProviders) ^ + runtimeType.hashCode; +} + +extension $SeriesInfoRemoteSearchQueryExtension on SeriesInfoRemoteSearchQuery { + SeriesInfoRemoteSearchQuery copyWith( + {SeriesInfo? searchInfo, + String? itemId, + String? searchProviderName, + bool? includeDisabledProviders}) { + return SeriesInfoRemoteSearchQuery( + searchInfo: searchInfo ?? this.searchInfo, + itemId: itemId ?? this.itemId, + searchProviderName: searchProviderName ?? this.searchProviderName, + includeDisabledProviders: + includeDisabledProviders ?? this.includeDisabledProviders); + } + + SeriesInfoRemoteSearchQuery copyWithWrapped( + {Wrapped? searchInfo, + Wrapped? itemId, + Wrapped? searchProviderName, + Wrapped? includeDisabledProviders}) { + return SeriesInfoRemoteSearchQuery( + searchInfo: (searchInfo != null ? searchInfo.value : this.searchInfo), + itemId: (itemId != null ? itemId.value : this.itemId), + searchProviderName: (searchProviderName != null + ? searchProviderName.value + : this.searchProviderName), + includeDisabledProviders: (includeDisabledProviders != null + ? includeDisabledProviders.value + : this.includeDisabledProviders)); + } +} + +@JsonSerializable(explicitToJson: true) +class SeriesTimerCancelledMessage { + const SeriesTimerCancelledMessage({ + this.data, + this.messageId, + this.messageType, + }); + + factory SeriesTimerCancelledMessage.fromJson(Map json) => + _$SeriesTimerCancelledMessageFromJson(json); + + static const toJsonFactory = _$SeriesTimerCancelledMessageToJson; + Map toJson() => _$SeriesTimerCancelledMessageToJson(this); + + @JsonKey(name: 'Data', includeIfNull: false) + final TimerEventInfo? data; + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.seriestimercancelled); + + static const fromJsonFactory = _$SeriesTimerCancelledMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is SeriesTimerCancelledMessage && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data)) && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(data) ^ + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $SeriesTimerCancelledMessageExtension on SeriesTimerCancelledMessage { + SeriesTimerCancelledMessage copyWith( + {TimerEventInfo? data, + String? messageId, + enums.SessionMessageType? messageType}) { + return SeriesTimerCancelledMessage( + data: data ?? this.data, + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + SeriesTimerCancelledMessage copyWithWrapped( + {Wrapped? data, + Wrapped? messageId, + Wrapped? messageType}) { + return SeriesTimerCancelledMessage( + data: (data != null ? data.value : this.data), + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class SeriesTimerCreatedMessage { + const SeriesTimerCreatedMessage({ + this.data, + this.messageId, + this.messageType, + }); + + factory SeriesTimerCreatedMessage.fromJson(Map json) => + _$SeriesTimerCreatedMessageFromJson(json); + + static const toJsonFactory = _$SeriesTimerCreatedMessageToJson; + Map toJson() => _$SeriesTimerCreatedMessageToJson(this); + + @JsonKey(name: 'Data', includeIfNull: false) + final TimerEventInfo? data; + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.seriestimercreated); + + static const fromJsonFactory = _$SeriesTimerCreatedMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is SeriesTimerCreatedMessage && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data)) && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(data) ^ + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $SeriesTimerCreatedMessageExtension on SeriesTimerCreatedMessage { + SeriesTimerCreatedMessage copyWith( + {TimerEventInfo? data, + String? messageId, + enums.SessionMessageType? messageType}) { + return SeriesTimerCreatedMessage( + data: data ?? this.data, + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + SeriesTimerCreatedMessage copyWithWrapped( + {Wrapped? data, + Wrapped? messageId, + Wrapped? messageType}) { + return SeriesTimerCreatedMessage( + data: (data != null ? data.value : this.data), + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class SeriesTimerInfoDto { + const SeriesTimerInfoDto({ + this.id, + this.type, + this.serverId, + this.externalId, + this.channelId, + this.externalChannelId, + this.channelName, + this.channelPrimaryImageTag, + this.programId, + this.externalProgramId, + this.name, + this.overview, + this.startDate, + this.endDate, + this.serviceName, + this.priority, + this.prePaddingSeconds, + this.postPaddingSeconds, + this.isPrePaddingRequired, + this.parentBackdropItemId, + this.parentBackdropImageTags, + this.isPostPaddingRequired, + this.keepUntil, + this.recordAnyTime, + this.skipEpisodesInLibrary, + this.recordAnyChannel, + this.keepUpTo, + this.recordNewOnly, + this.days, + this.dayPattern, + this.imageTags, + this.parentThumbItemId, + this.parentThumbImageTag, + this.parentPrimaryImageItemId, + this.parentPrimaryImageTag, + }); + + factory SeriesTimerInfoDto.fromJson(Map json) => + _$SeriesTimerInfoDtoFromJson(json); + + static const toJsonFactory = _$SeriesTimerInfoDtoToJson; + Map toJson() => _$SeriesTimerInfoDtoToJson(this); + + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'Type', includeIfNull: false) + final String? type; + @JsonKey(name: 'ServerId', includeIfNull: false) + final String? serverId; + @JsonKey(name: 'ExternalId', includeIfNull: false) + final String? externalId; + @JsonKey(name: 'ChannelId', includeIfNull: false) + final String? channelId; + @JsonKey(name: 'ExternalChannelId', includeIfNull: false) + final String? externalChannelId; + @JsonKey(name: 'ChannelName', includeIfNull: false) + final String? channelName; + @JsonKey(name: 'ChannelPrimaryImageTag', includeIfNull: false) + final String? channelPrimaryImageTag; + @JsonKey(name: 'ProgramId', includeIfNull: false) + final String? programId; + @JsonKey(name: 'ExternalProgramId', includeIfNull: false) + final String? externalProgramId; + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'Overview', includeIfNull: false) + final String? overview; + @JsonKey(name: 'StartDate', includeIfNull: false) + final DateTime? startDate; + @JsonKey(name: 'EndDate', includeIfNull: false) + final DateTime? endDate; + @JsonKey(name: 'ServiceName', includeIfNull: false) + final String? serviceName; + @JsonKey(name: 'Priority', includeIfNull: false) + final int? priority; + @JsonKey(name: 'PrePaddingSeconds', includeIfNull: false) + final int? prePaddingSeconds; + @JsonKey(name: 'PostPaddingSeconds', includeIfNull: false) + final int? postPaddingSeconds; + @JsonKey(name: 'IsPrePaddingRequired', includeIfNull: false) + final bool? isPrePaddingRequired; + @JsonKey(name: 'ParentBackdropItemId', includeIfNull: false) + final String? parentBackdropItemId; + @JsonKey( + name: 'ParentBackdropImageTags', + includeIfNull: false, + defaultValue: []) + final List? parentBackdropImageTags; + @JsonKey(name: 'IsPostPaddingRequired', includeIfNull: false) + final bool? isPostPaddingRequired; + @JsonKey( + name: 'KeepUntil', + includeIfNull: false, + toJson: keepUntilNullableToJson, + fromJson: keepUntilNullableFromJson, + ) + final enums.KeepUntil? keepUntil; + @JsonKey(name: 'RecordAnyTime', includeIfNull: false) + final bool? recordAnyTime; + @JsonKey(name: 'SkipEpisodesInLibrary', includeIfNull: false) + final bool? skipEpisodesInLibrary; + @JsonKey(name: 'RecordAnyChannel', includeIfNull: false) + final bool? recordAnyChannel; + @JsonKey(name: 'KeepUpTo', includeIfNull: false) + final int? keepUpTo; + @JsonKey(name: 'RecordNewOnly', includeIfNull: false) + final bool? recordNewOnly; + @JsonKey( + name: 'Days', + includeIfNull: false, + toJson: dayOfWeekListToJson, + fromJson: dayOfWeekListFromJson, + ) + final List? days; + @JsonKey( + name: 'DayPattern', + includeIfNull: false, + toJson: dayPatternNullableToJson, + fromJson: dayPatternNullableFromJson, + ) + final enums.DayPattern? dayPattern; + @JsonKey(name: 'ImageTags', includeIfNull: false) + final Map? imageTags; + @JsonKey(name: 'ParentThumbItemId', includeIfNull: false) + final String? parentThumbItemId; + @JsonKey(name: 'ParentThumbImageTag', includeIfNull: false) + final String? parentThumbImageTag; + @JsonKey(name: 'ParentPrimaryImageItemId', includeIfNull: false) + final String? parentPrimaryImageItemId; + @JsonKey(name: 'ParentPrimaryImageTag', includeIfNull: false) + final String? parentPrimaryImageTag; + static const fromJsonFactory = _$SeriesTimerInfoDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is SeriesTimerInfoDto && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.type, type) || + const DeepCollectionEquality().equals(other.type, type)) && + (identical(other.serverId, serverId) || + const DeepCollectionEquality() + .equals(other.serverId, serverId)) && + (identical(other.externalId, externalId) || + const DeepCollectionEquality() + .equals(other.externalId, externalId)) && + (identical(other.channelId, channelId) || + const DeepCollectionEquality() + .equals(other.channelId, channelId)) && + (identical(other.externalChannelId, externalChannelId) || + const DeepCollectionEquality() + .equals(other.externalChannelId, externalChannelId)) && + (identical(other.channelName, channelName) || + const DeepCollectionEquality() + .equals(other.channelName, channelName)) && + (identical(other.channelPrimaryImageTag, channelPrimaryImageTag) || + const DeepCollectionEquality().equals( + other.channelPrimaryImageTag, channelPrimaryImageTag)) && + (identical(other.programId, programId) || + const DeepCollectionEquality() + .equals(other.programId, programId)) && + (identical(other.externalProgramId, externalProgramId) || + const DeepCollectionEquality() + .equals(other.externalProgramId, externalProgramId)) && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.overview, overview) || + const DeepCollectionEquality() + .equals(other.overview, overview)) && + (identical(other.startDate, startDate) || + const DeepCollectionEquality() + .equals(other.startDate, startDate)) && + (identical(other.endDate, endDate) || + const DeepCollectionEquality() + .equals(other.endDate, endDate)) && + (identical(other.serviceName, serviceName) || + const DeepCollectionEquality() + .equals(other.serviceName, serviceName)) && + (identical(other.priority, priority) || + const DeepCollectionEquality() + .equals(other.priority, priority)) && + (identical(other.prePaddingSeconds, prePaddingSeconds) || + const DeepCollectionEquality() + .equals(other.prePaddingSeconds, prePaddingSeconds)) && + (identical(other.postPaddingSeconds, postPaddingSeconds) || + const DeepCollectionEquality() + .equals(other.postPaddingSeconds, postPaddingSeconds)) && + (identical(other.isPrePaddingRequired, isPrePaddingRequired) || + const DeepCollectionEquality().equals( + other.isPrePaddingRequired, isPrePaddingRequired)) && + (identical(other.parentBackdropItemId, parentBackdropItemId) || + const DeepCollectionEquality().equals( + other.parentBackdropItemId, parentBackdropItemId)) && + (identical(other.parentBackdropImageTags, parentBackdropImageTags) || + const DeepCollectionEquality().equals( + other.parentBackdropImageTags, parentBackdropImageTags)) && + (identical(other.isPostPaddingRequired, isPostPaddingRequired) || + const DeepCollectionEquality().equals( + other.isPostPaddingRequired, isPostPaddingRequired)) && + (identical(other.keepUntil, keepUntil) || const DeepCollectionEquality().equals(other.keepUntil, keepUntil)) && + (identical(other.recordAnyTime, recordAnyTime) || const DeepCollectionEquality().equals(other.recordAnyTime, recordAnyTime)) && + (identical(other.skipEpisodesInLibrary, skipEpisodesInLibrary) || const DeepCollectionEquality().equals(other.skipEpisodesInLibrary, skipEpisodesInLibrary)) && + (identical(other.recordAnyChannel, recordAnyChannel) || const DeepCollectionEquality().equals(other.recordAnyChannel, recordAnyChannel)) && + (identical(other.keepUpTo, keepUpTo) || const DeepCollectionEquality().equals(other.keepUpTo, keepUpTo)) && + (identical(other.recordNewOnly, recordNewOnly) || const DeepCollectionEquality().equals(other.recordNewOnly, recordNewOnly)) && + (identical(other.days, days) || const DeepCollectionEquality().equals(other.days, days)) && + (identical(other.dayPattern, dayPattern) || const DeepCollectionEquality().equals(other.dayPattern, dayPattern)) && + (identical(other.imageTags, imageTags) || const DeepCollectionEquality().equals(other.imageTags, imageTags)) && + (identical(other.parentThumbItemId, parentThumbItemId) || const DeepCollectionEquality().equals(other.parentThumbItemId, parentThumbItemId)) && + (identical(other.parentThumbImageTag, parentThumbImageTag) || const DeepCollectionEquality().equals(other.parentThumbImageTag, parentThumbImageTag)) && + (identical(other.parentPrimaryImageItemId, parentPrimaryImageItemId) || const DeepCollectionEquality().equals(other.parentPrimaryImageItemId, parentPrimaryImageItemId)) && + (identical(other.parentPrimaryImageTag, parentPrimaryImageTag) || const DeepCollectionEquality().equals(other.parentPrimaryImageTag, parentPrimaryImageTag))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(type) ^ + const DeepCollectionEquality().hash(serverId) ^ + const DeepCollectionEquality().hash(externalId) ^ + const DeepCollectionEquality().hash(channelId) ^ + const DeepCollectionEquality().hash(externalChannelId) ^ + const DeepCollectionEquality().hash(channelName) ^ + const DeepCollectionEquality().hash(channelPrimaryImageTag) ^ + const DeepCollectionEquality().hash(programId) ^ + const DeepCollectionEquality().hash(externalProgramId) ^ + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(overview) ^ + const DeepCollectionEquality().hash(startDate) ^ + const DeepCollectionEquality().hash(endDate) ^ + const DeepCollectionEquality().hash(serviceName) ^ + const DeepCollectionEquality().hash(priority) ^ + const DeepCollectionEquality().hash(prePaddingSeconds) ^ + const DeepCollectionEquality().hash(postPaddingSeconds) ^ + const DeepCollectionEquality().hash(isPrePaddingRequired) ^ + const DeepCollectionEquality().hash(parentBackdropItemId) ^ + const DeepCollectionEquality().hash(parentBackdropImageTags) ^ + const DeepCollectionEquality().hash(isPostPaddingRequired) ^ + const DeepCollectionEquality().hash(keepUntil) ^ + const DeepCollectionEquality().hash(recordAnyTime) ^ + const DeepCollectionEquality().hash(skipEpisodesInLibrary) ^ + const DeepCollectionEquality().hash(recordAnyChannel) ^ + const DeepCollectionEquality().hash(keepUpTo) ^ + const DeepCollectionEquality().hash(recordNewOnly) ^ + const DeepCollectionEquality().hash(days) ^ + const DeepCollectionEquality().hash(dayPattern) ^ + const DeepCollectionEquality().hash(imageTags) ^ + const DeepCollectionEquality().hash(parentThumbItemId) ^ + const DeepCollectionEquality().hash(parentThumbImageTag) ^ + const DeepCollectionEquality().hash(parentPrimaryImageItemId) ^ + const DeepCollectionEquality().hash(parentPrimaryImageTag) ^ + runtimeType.hashCode; +} + +extension $SeriesTimerInfoDtoExtension on SeriesTimerInfoDto { + SeriesTimerInfoDto copyWith( + {String? id, + String? type, + String? serverId, + String? externalId, + String? channelId, + String? externalChannelId, + String? channelName, + String? channelPrimaryImageTag, + String? programId, + String? externalProgramId, + String? name, + String? overview, + DateTime? startDate, + DateTime? endDate, + String? serviceName, + int? priority, + int? prePaddingSeconds, + int? postPaddingSeconds, + bool? isPrePaddingRequired, + String? parentBackdropItemId, + List? parentBackdropImageTags, + bool? isPostPaddingRequired, + enums.KeepUntil? keepUntil, + bool? recordAnyTime, + bool? skipEpisodesInLibrary, + bool? recordAnyChannel, + int? keepUpTo, + bool? recordNewOnly, + List? days, + enums.DayPattern? dayPattern, + Map? imageTags, + String? parentThumbItemId, + String? parentThumbImageTag, + String? parentPrimaryImageItemId, + String? parentPrimaryImageTag}) { + return SeriesTimerInfoDto( + id: id ?? this.id, + type: type ?? this.type, + serverId: serverId ?? this.serverId, + externalId: externalId ?? this.externalId, + channelId: channelId ?? this.channelId, + externalChannelId: externalChannelId ?? this.externalChannelId, + channelName: channelName ?? this.channelName, + channelPrimaryImageTag: + channelPrimaryImageTag ?? this.channelPrimaryImageTag, + programId: programId ?? this.programId, + externalProgramId: externalProgramId ?? this.externalProgramId, + name: name ?? this.name, + overview: overview ?? this.overview, + startDate: startDate ?? this.startDate, + endDate: endDate ?? this.endDate, + serviceName: serviceName ?? this.serviceName, + priority: priority ?? this.priority, + prePaddingSeconds: prePaddingSeconds ?? this.prePaddingSeconds, + postPaddingSeconds: postPaddingSeconds ?? this.postPaddingSeconds, + isPrePaddingRequired: isPrePaddingRequired ?? this.isPrePaddingRequired, + parentBackdropItemId: parentBackdropItemId ?? this.parentBackdropItemId, + parentBackdropImageTags: + parentBackdropImageTags ?? this.parentBackdropImageTags, + isPostPaddingRequired: + isPostPaddingRequired ?? this.isPostPaddingRequired, + keepUntil: keepUntil ?? this.keepUntil, + recordAnyTime: recordAnyTime ?? this.recordAnyTime, + skipEpisodesInLibrary: + skipEpisodesInLibrary ?? this.skipEpisodesInLibrary, + recordAnyChannel: recordAnyChannel ?? this.recordAnyChannel, + keepUpTo: keepUpTo ?? this.keepUpTo, + recordNewOnly: recordNewOnly ?? this.recordNewOnly, + days: days ?? this.days, + dayPattern: dayPattern ?? this.dayPattern, + imageTags: imageTags ?? this.imageTags, + parentThumbItemId: parentThumbItemId ?? this.parentThumbItemId, + parentThumbImageTag: parentThumbImageTag ?? this.parentThumbImageTag, + parentPrimaryImageItemId: + parentPrimaryImageItemId ?? this.parentPrimaryImageItemId, + parentPrimaryImageTag: + parentPrimaryImageTag ?? this.parentPrimaryImageTag); + } + + SeriesTimerInfoDto copyWithWrapped( + {Wrapped? id, + Wrapped? type, + Wrapped? serverId, + Wrapped? externalId, + Wrapped? channelId, + Wrapped? externalChannelId, + Wrapped? channelName, + Wrapped? channelPrimaryImageTag, + Wrapped? programId, + Wrapped? externalProgramId, + Wrapped? name, + Wrapped? overview, + Wrapped? startDate, + Wrapped? endDate, + Wrapped? serviceName, + Wrapped? priority, + Wrapped? prePaddingSeconds, + Wrapped? postPaddingSeconds, + Wrapped? isPrePaddingRequired, + Wrapped? parentBackdropItemId, + Wrapped?>? parentBackdropImageTags, + Wrapped? isPostPaddingRequired, + Wrapped? keepUntil, + Wrapped? recordAnyTime, + Wrapped? skipEpisodesInLibrary, + Wrapped? recordAnyChannel, + Wrapped? keepUpTo, + Wrapped? recordNewOnly, + Wrapped?>? days, + Wrapped? dayPattern, + Wrapped?>? imageTags, + Wrapped? parentThumbItemId, + Wrapped? parentThumbImageTag, + Wrapped? parentPrimaryImageItemId, + Wrapped? parentPrimaryImageTag}) { + return SeriesTimerInfoDto( + id: (id != null ? id.value : this.id), + type: (type != null ? type.value : this.type), + serverId: (serverId != null ? serverId.value : this.serverId), + externalId: (externalId != null ? externalId.value : this.externalId), + channelId: (channelId != null ? channelId.value : this.channelId), + externalChannelId: (externalChannelId != null + ? externalChannelId.value + : this.externalChannelId), + channelName: + (channelName != null ? channelName.value : this.channelName), + channelPrimaryImageTag: (channelPrimaryImageTag != null + ? channelPrimaryImageTag.value + : this.channelPrimaryImageTag), + programId: (programId != null ? programId.value : this.programId), + externalProgramId: (externalProgramId != null + ? externalProgramId.value + : this.externalProgramId), + name: (name != null ? name.value : this.name), + overview: (overview != null ? overview.value : this.overview), + startDate: (startDate != null ? startDate.value : this.startDate), + endDate: (endDate != null ? endDate.value : this.endDate), + serviceName: + (serviceName != null ? serviceName.value : this.serviceName), + priority: (priority != null ? priority.value : this.priority), + prePaddingSeconds: (prePaddingSeconds != null + ? prePaddingSeconds.value + : this.prePaddingSeconds), + postPaddingSeconds: (postPaddingSeconds != null + ? postPaddingSeconds.value + : this.postPaddingSeconds), + isPrePaddingRequired: (isPrePaddingRequired != null + ? isPrePaddingRequired.value + : this.isPrePaddingRequired), + parentBackdropItemId: (parentBackdropItemId != null + ? parentBackdropItemId.value + : this.parentBackdropItemId), + parentBackdropImageTags: (parentBackdropImageTags != null + ? parentBackdropImageTags.value + : this.parentBackdropImageTags), + isPostPaddingRequired: (isPostPaddingRequired != null + ? isPostPaddingRequired.value + : this.isPostPaddingRequired), + keepUntil: (keepUntil != null ? keepUntil.value : this.keepUntil), + recordAnyTime: + (recordAnyTime != null ? recordAnyTime.value : this.recordAnyTime), + skipEpisodesInLibrary: (skipEpisodesInLibrary != null + ? skipEpisodesInLibrary.value + : this.skipEpisodesInLibrary), + recordAnyChannel: (recordAnyChannel != null + ? recordAnyChannel.value + : this.recordAnyChannel), + keepUpTo: (keepUpTo != null ? keepUpTo.value : this.keepUpTo), + recordNewOnly: + (recordNewOnly != null ? recordNewOnly.value : this.recordNewOnly), + days: (days != null ? days.value : this.days), + dayPattern: (dayPattern != null ? dayPattern.value : this.dayPattern), + imageTags: (imageTags != null ? imageTags.value : this.imageTags), + parentThumbItemId: (parentThumbItemId != null + ? parentThumbItemId.value + : this.parentThumbItemId), + parentThumbImageTag: (parentThumbImageTag != null + ? parentThumbImageTag.value + : this.parentThumbImageTag), + parentPrimaryImageItemId: (parentPrimaryImageItemId != null + ? parentPrimaryImageItemId.value + : this.parentPrimaryImageItemId), + parentPrimaryImageTag: (parentPrimaryImageTag != null + ? parentPrimaryImageTag.value + : this.parentPrimaryImageTag)); + } +} + +@JsonSerializable(explicitToJson: true) +class SeriesTimerInfoDtoQueryResult { + const SeriesTimerInfoDtoQueryResult({ + this.items, + this.totalRecordCount, + this.startIndex, + }); + + factory SeriesTimerInfoDtoQueryResult.fromJson(Map json) => + _$SeriesTimerInfoDtoQueryResultFromJson(json); + + static const toJsonFactory = _$SeriesTimerInfoDtoQueryResultToJson; + Map toJson() => _$SeriesTimerInfoDtoQueryResultToJson(this); + + @JsonKey( + name: 'Items', includeIfNull: false, defaultValue: []) + final List? items; + @JsonKey(name: 'TotalRecordCount', includeIfNull: false) + final int? totalRecordCount; + @JsonKey(name: 'StartIndex', includeIfNull: false) + final int? startIndex; + static const fromJsonFactory = _$SeriesTimerInfoDtoQueryResultFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is SeriesTimerInfoDtoQueryResult && + (identical(other.items, items) || + const DeepCollectionEquality().equals(other.items, items)) && + (identical(other.totalRecordCount, totalRecordCount) || + const DeepCollectionEquality() + .equals(other.totalRecordCount, totalRecordCount)) && + (identical(other.startIndex, startIndex) || + const DeepCollectionEquality() + .equals(other.startIndex, startIndex))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(items) ^ + const DeepCollectionEquality().hash(totalRecordCount) ^ + const DeepCollectionEquality().hash(startIndex) ^ + runtimeType.hashCode; +} + +extension $SeriesTimerInfoDtoQueryResultExtension + on SeriesTimerInfoDtoQueryResult { + SeriesTimerInfoDtoQueryResult copyWith( + {List? items, + int? totalRecordCount, + int? startIndex}) { + return SeriesTimerInfoDtoQueryResult( + items: items ?? this.items, + totalRecordCount: totalRecordCount ?? this.totalRecordCount, + startIndex: startIndex ?? this.startIndex); + } + + SeriesTimerInfoDtoQueryResult copyWithWrapped( + {Wrapped?>? items, + Wrapped? totalRecordCount, + Wrapped? startIndex}) { + return SeriesTimerInfoDtoQueryResult( + items: (items != null ? items.value : this.items), + totalRecordCount: (totalRecordCount != null + ? totalRecordCount.value + : this.totalRecordCount), + startIndex: (startIndex != null ? startIndex.value : this.startIndex)); + } +} + +@JsonSerializable(explicitToJson: true) +class ServerConfiguration { + const ServerConfiguration({ + this.logFileRetentionDays, + this.isStartupWizardCompleted, + this.cachePath, + this.previousVersion, + this.previousVersionStr, + this.enableMetrics, + this.enableNormalizedItemByNameIds, + this.isPortAuthorized, + this.quickConnectAvailable, + this.enableCaseSensitiveItemIds, + this.disableLiveTvChannelUserDataName, + this.metadataPath, + this.metadataNetworkPath, + this.preferredMetadataLanguage, + this.metadataCountryCode, + this.sortReplaceCharacters, + this.sortRemoveCharacters, + this.sortRemoveWords, + this.minResumePct, + this.maxResumePct, + this.minResumeDurationSeconds, + this.minAudiobookResume, + this.maxAudiobookResume, + this.inactiveSessionThreshold, + this.libraryMonitorDelay, + this.libraryUpdateDuration, + this.imageSavingConvention, + this.metadataOptions, + this.skipDeserializationForBasicTypes, + this.serverName, + this.uICulture, + this.saveMetadataHidden, + this.contentTypes, + this.remoteClientBitrateLimit, + this.enableFolderView, + this.enableGroupingIntoCollections, + this.displaySpecialsWithinSeasons, + this.codecsUsed, + this.pluginRepositories, + this.enableExternalContentInSuggestions, + this.imageExtractionTimeoutMs, + this.pathSubstitutions, + this.enableSlowResponseWarning, + this.slowResponseThresholdMs, + this.corsHosts, + this.activityLogRetentionDays, + this.libraryScanFanoutConcurrency, + this.libraryMetadataRefreshConcurrency, + this.removeOldPlugins, + this.allowClientLogUpload, + this.dummyChapterDuration, + this.chapterImageResolution, + this.parallelImageEncodingLimit, + this.castReceiverApplications, + this.trickplayOptions, + }); + + factory ServerConfiguration.fromJson(Map json) => + _$ServerConfigurationFromJson(json); + + static const toJsonFactory = _$ServerConfigurationToJson; + Map toJson() => _$ServerConfigurationToJson(this); + + @JsonKey(name: 'LogFileRetentionDays', includeIfNull: false) + final int? logFileRetentionDays; + @JsonKey(name: 'IsStartupWizardCompleted', includeIfNull: false) + final bool? isStartupWizardCompleted; + @JsonKey(name: 'CachePath', includeIfNull: false) + final String? cachePath; + @JsonKey(name: 'PreviousVersion', includeIfNull: false) + final String? previousVersion; + @JsonKey(name: 'PreviousVersionStr', includeIfNull: false) + final String? previousVersionStr; + @JsonKey(name: 'EnableMetrics', includeIfNull: false) + final bool? enableMetrics; + @JsonKey(name: 'EnableNormalizedItemByNameIds', includeIfNull: false) + final bool? enableNormalizedItemByNameIds; + @JsonKey(name: 'IsPortAuthorized', includeIfNull: false) + final bool? isPortAuthorized; + @JsonKey(name: 'QuickConnectAvailable', includeIfNull: false) + final bool? quickConnectAvailable; + @JsonKey(name: 'EnableCaseSensitiveItemIds', includeIfNull: false) + final bool? enableCaseSensitiveItemIds; + @JsonKey(name: 'DisableLiveTvChannelUserDataName', includeIfNull: false) + final bool? disableLiveTvChannelUserDataName; + @JsonKey(name: 'MetadataPath', includeIfNull: false) + final String? metadataPath; + @JsonKey(name: 'MetadataNetworkPath', includeIfNull: false) + final String? metadataNetworkPath; + @JsonKey(name: 'PreferredMetadataLanguage', includeIfNull: false) + final String? preferredMetadataLanguage; + @JsonKey(name: 'MetadataCountryCode', includeIfNull: false) + final String? metadataCountryCode; + @JsonKey( + name: 'SortReplaceCharacters', + includeIfNull: false, + defaultValue: []) + final List? sortReplaceCharacters; + @JsonKey( + name: 'SortRemoveCharacters', + includeIfNull: false, + defaultValue: []) + final List? sortRemoveCharacters; + @JsonKey( + name: 'SortRemoveWords', includeIfNull: false, defaultValue: []) + final List? sortRemoveWords; + @JsonKey(name: 'MinResumePct', includeIfNull: false) + final int? minResumePct; + @JsonKey(name: 'MaxResumePct', includeIfNull: false) + final int? maxResumePct; + @JsonKey(name: 'MinResumeDurationSeconds', includeIfNull: false) + final int? minResumeDurationSeconds; + @JsonKey(name: 'MinAudiobookResume', includeIfNull: false) + final int? minAudiobookResume; + @JsonKey(name: 'MaxAudiobookResume', includeIfNull: false) + final int? maxAudiobookResume; + @JsonKey(name: 'InactiveSessionThreshold', includeIfNull: false) + final int? inactiveSessionThreshold; + @JsonKey(name: 'LibraryMonitorDelay', includeIfNull: false) + final int? libraryMonitorDelay; + @JsonKey(name: 'LibraryUpdateDuration', includeIfNull: false) + final int? libraryUpdateDuration; + @JsonKey( + name: 'ImageSavingConvention', + includeIfNull: false, + toJson: imageSavingConventionNullableToJson, + fromJson: imageSavingConventionNullableFromJson, + ) + final enums.ImageSavingConvention? imageSavingConvention; + @JsonKey( + name: 'MetadataOptions', + includeIfNull: false, + defaultValue: []) + final List? metadataOptions; + @JsonKey(name: 'SkipDeserializationForBasicTypes', includeIfNull: false) + final bool? skipDeserializationForBasicTypes; + @JsonKey(name: 'ServerName', includeIfNull: false) + final String? serverName; + @JsonKey(name: 'UICulture', includeIfNull: false) + final String? uICulture; + @JsonKey(name: 'SaveMetadataHidden', includeIfNull: false) + final bool? saveMetadataHidden; + @JsonKey( + name: 'ContentTypes', + includeIfNull: false, + defaultValue: []) + final List? contentTypes; + @JsonKey(name: 'RemoteClientBitrateLimit', includeIfNull: false) + final int? remoteClientBitrateLimit; + @JsonKey(name: 'EnableFolderView', includeIfNull: false) + final bool? enableFolderView; + @JsonKey(name: 'EnableGroupingIntoCollections', includeIfNull: false) + final bool? enableGroupingIntoCollections; + @JsonKey(name: 'DisplaySpecialsWithinSeasons', includeIfNull: false) + final bool? displaySpecialsWithinSeasons; + @JsonKey(name: 'CodecsUsed', includeIfNull: false, defaultValue: []) + final List? codecsUsed; + @JsonKey( + name: 'PluginRepositories', + includeIfNull: false, + defaultValue: []) + final List? pluginRepositories; + @JsonKey(name: 'EnableExternalContentInSuggestions', includeIfNull: false) + final bool? enableExternalContentInSuggestions; + @JsonKey(name: 'ImageExtractionTimeoutMs', includeIfNull: false) + final int? imageExtractionTimeoutMs; + @JsonKey( + name: 'PathSubstitutions', + includeIfNull: false, + defaultValue: []) + final List? pathSubstitutions; + @JsonKey(name: 'EnableSlowResponseWarning', includeIfNull: false) + final bool? enableSlowResponseWarning; + @JsonKey(name: 'SlowResponseThresholdMs', includeIfNull: false) + final int? slowResponseThresholdMs; + @JsonKey(name: 'CorsHosts', includeIfNull: false, defaultValue: []) + final List? corsHosts; + @JsonKey(name: 'ActivityLogRetentionDays', includeIfNull: false) + final int? activityLogRetentionDays; + @JsonKey(name: 'LibraryScanFanoutConcurrency', includeIfNull: false) + final int? libraryScanFanoutConcurrency; + @JsonKey(name: 'LibraryMetadataRefreshConcurrency', includeIfNull: false) + final int? libraryMetadataRefreshConcurrency; + @JsonKey(name: 'RemoveOldPlugins', includeIfNull: false) + final bool? removeOldPlugins; + @JsonKey(name: 'AllowClientLogUpload', includeIfNull: false) + final bool? allowClientLogUpload; + @JsonKey(name: 'DummyChapterDuration', includeIfNull: false) + final int? dummyChapterDuration; + @JsonKey( + name: 'ChapterImageResolution', + includeIfNull: false, + toJson: imageResolutionNullableToJson, + fromJson: imageResolutionNullableFromJson, + ) + final enums.ImageResolution? chapterImageResolution; + @JsonKey(name: 'ParallelImageEncodingLimit', includeIfNull: false) + final int? parallelImageEncodingLimit; + @JsonKey( + name: 'CastReceiverApplications', + includeIfNull: false, + defaultValue: []) + final List? castReceiverApplications; + @JsonKey(name: 'TrickplayOptions', includeIfNull: false) + final TrickplayOptions? trickplayOptions; + static const fromJsonFactory = _$ServerConfigurationFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ServerConfiguration && + (identical(other.logFileRetentionDays, logFileRetentionDays) || + const DeepCollectionEquality().equals( + other.logFileRetentionDays, logFileRetentionDays)) && + (identical(other.isStartupWizardCompleted, isStartupWizardCompleted) || + const DeepCollectionEquality().equals( + other.isStartupWizardCompleted, + isStartupWizardCompleted)) && + (identical(other.cachePath, cachePath) || + const DeepCollectionEquality() + .equals(other.cachePath, cachePath)) && + (identical(other.previousVersion, previousVersion) || + const DeepCollectionEquality() + .equals(other.previousVersion, previousVersion)) && + (identical(other.previousVersionStr, previousVersionStr) || + const DeepCollectionEquality() + .equals(other.previousVersionStr, previousVersionStr)) && + (identical(other.enableMetrics, enableMetrics) || + const DeepCollectionEquality() + .equals(other.enableMetrics, enableMetrics)) && + (identical(other.enableNormalizedItemByNameIds, enableNormalizedItemByNameIds) || + const DeepCollectionEquality().equals( + other.enableNormalizedItemByNameIds, + enableNormalizedItemByNameIds)) && + (identical(other.isPortAuthorized, isPortAuthorized) || + const DeepCollectionEquality() + .equals(other.isPortAuthorized, isPortAuthorized)) && + (identical(other.quickConnectAvailable, quickConnectAvailable) || + const DeepCollectionEquality().equals( + other.quickConnectAvailable, quickConnectAvailable)) && + (identical(other.enableCaseSensitiveItemIds, enableCaseSensitiveItemIds) || + const DeepCollectionEquality().equals( + other.enableCaseSensitiveItemIds, + enableCaseSensitiveItemIds)) && + (identical(other.disableLiveTvChannelUserDataName, disableLiveTvChannelUserDataName) || + const DeepCollectionEquality().equals( + other.disableLiveTvChannelUserDataName, + disableLiveTvChannelUserDataName)) && + (identical(other.metadataPath, metadataPath) || + const DeepCollectionEquality() + .equals(other.metadataPath, metadataPath)) && + (identical(other.metadataNetworkPath, metadataNetworkPath) || + const DeepCollectionEquality().equals(other.metadataNetworkPath, metadataNetworkPath)) && + (identical(other.preferredMetadataLanguage, preferredMetadataLanguage) || const DeepCollectionEquality().equals(other.preferredMetadataLanguage, preferredMetadataLanguage)) && + (identical(other.metadataCountryCode, metadataCountryCode) || const DeepCollectionEquality().equals(other.metadataCountryCode, metadataCountryCode)) && + (identical(other.sortReplaceCharacters, sortReplaceCharacters) || const DeepCollectionEquality().equals(other.sortReplaceCharacters, sortReplaceCharacters)) && + (identical(other.sortRemoveCharacters, sortRemoveCharacters) || const DeepCollectionEquality().equals(other.sortRemoveCharacters, sortRemoveCharacters)) && + (identical(other.sortRemoveWords, sortRemoveWords) || const DeepCollectionEquality().equals(other.sortRemoveWords, sortRemoveWords)) && + (identical(other.minResumePct, minResumePct) || const DeepCollectionEquality().equals(other.minResumePct, minResumePct)) && + (identical(other.maxResumePct, maxResumePct) || const DeepCollectionEquality().equals(other.maxResumePct, maxResumePct)) && + (identical(other.minResumeDurationSeconds, minResumeDurationSeconds) || const DeepCollectionEquality().equals(other.minResumeDurationSeconds, minResumeDurationSeconds)) && + (identical(other.minAudiobookResume, minAudiobookResume) || const DeepCollectionEquality().equals(other.minAudiobookResume, minAudiobookResume)) && + (identical(other.maxAudiobookResume, maxAudiobookResume) || const DeepCollectionEquality().equals(other.maxAudiobookResume, maxAudiobookResume)) && + (identical(other.inactiveSessionThreshold, inactiveSessionThreshold) || const DeepCollectionEquality().equals(other.inactiveSessionThreshold, inactiveSessionThreshold)) && + (identical(other.libraryMonitorDelay, libraryMonitorDelay) || const DeepCollectionEquality().equals(other.libraryMonitorDelay, libraryMonitorDelay)) && + (identical(other.libraryUpdateDuration, libraryUpdateDuration) || const DeepCollectionEquality().equals(other.libraryUpdateDuration, libraryUpdateDuration)) && + (identical(other.imageSavingConvention, imageSavingConvention) || const DeepCollectionEquality().equals(other.imageSavingConvention, imageSavingConvention)) && + (identical(other.metadataOptions, metadataOptions) || const DeepCollectionEquality().equals(other.metadataOptions, metadataOptions)) && + (identical(other.skipDeserializationForBasicTypes, skipDeserializationForBasicTypes) || const DeepCollectionEquality().equals(other.skipDeserializationForBasicTypes, skipDeserializationForBasicTypes)) && + (identical(other.serverName, serverName) || const DeepCollectionEquality().equals(other.serverName, serverName)) && + (identical(other.uICulture, uICulture) || const DeepCollectionEquality().equals(other.uICulture, uICulture)) && + (identical(other.saveMetadataHidden, saveMetadataHidden) || const DeepCollectionEquality().equals(other.saveMetadataHidden, saveMetadataHidden)) && + (identical(other.contentTypes, contentTypes) || const DeepCollectionEquality().equals(other.contentTypes, contentTypes)) && + (identical(other.remoteClientBitrateLimit, remoteClientBitrateLimit) || const DeepCollectionEquality().equals(other.remoteClientBitrateLimit, remoteClientBitrateLimit)) && + (identical(other.enableFolderView, enableFolderView) || const DeepCollectionEquality().equals(other.enableFolderView, enableFolderView)) && + (identical(other.enableGroupingIntoCollections, enableGroupingIntoCollections) || const DeepCollectionEquality().equals(other.enableGroupingIntoCollections, enableGroupingIntoCollections)) && + (identical(other.displaySpecialsWithinSeasons, displaySpecialsWithinSeasons) || const DeepCollectionEquality().equals(other.displaySpecialsWithinSeasons, displaySpecialsWithinSeasons)) && + (identical(other.codecsUsed, codecsUsed) || const DeepCollectionEquality().equals(other.codecsUsed, codecsUsed)) && + (identical(other.pluginRepositories, pluginRepositories) || const DeepCollectionEquality().equals(other.pluginRepositories, pluginRepositories)) && + (identical(other.enableExternalContentInSuggestions, enableExternalContentInSuggestions) || const DeepCollectionEquality().equals(other.enableExternalContentInSuggestions, enableExternalContentInSuggestions)) && + (identical(other.imageExtractionTimeoutMs, imageExtractionTimeoutMs) || const DeepCollectionEquality().equals(other.imageExtractionTimeoutMs, imageExtractionTimeoutMs)) && + (identical(other.pathSubstitutions, pathSubstitutions) || const DeepCollectionEquality().equals(other.pathSubstitutions, pathSubstitutions)) && + (identical(other.enableSlowResponseWarning, enableSlowResponseWarning) || const DeepCollectionEquality().equals(other.enableSlowResponseWarning, enableSlowResponseWarning)) && + (identical(other.slowResponseThresholdMs, slowResponseThresholdMs) || const DeepCollectionEquality().equals(other.slowResponseThresholdMs, slowResponseThresholdMs)) && + (identical(other.corsHosts, corsHosts) || const DeepCollectionEquality().equals(other.corsHosts, corsHosts)) && + (identical(other.activityLogRetentionDays, activityLogRetentionDays) || const DeepCollectionEquality().equals(other.activityLogRetentionDays, activityLogRetentionDays)) && + (identical(other.libraryScanFanoutConcurrency, libraryScanFanoutConcurrency) || const DeepCollectionEquality().equals(other.libraryScanFanoutConcurrency, libraryScanFanoutConcurrency)) && + (identical(other.libraryMetadataRefreshConcurrency, libraryMetadataRefreshConcurrency) || const DeepCollectionEquality().equals(other.libraryMetadataRefreshConcurrency, libraryMetadataRefreshConcurrency)) && + (identical(other.removeOldPlugins, removeOldPlugins) || const DeepCollectionEquality().equals(other.removeOldPlugins, removeOldPlugins)) && + (identical(other.allowClientLogUpload, allowClientLogUpload) || const DeepCollectionEquality().equals(other.allowClientLogUpload, allowClientLogUpload)) && + (identical(other.dummyChapterDuration, dummyChapterDuration) || const DeepCollectionEquality().equals(other.dummyChapterDuration, dummyChapterDuration)) && + (identical(other.chapterImageResolution, chapterImageResolution) || const DeepCollectionEquality().equals(other.chapterImageResolution, chapterImageResolution)) && + (identical(other.parallelImageEncodingLimit, parallelImageEncodingLimit) || const DeepCollectionEquality().equals(other.parallelImageEncodingLimit, parallelImageEncodingLimit)) && + (identical(other.castReceiverApplications, castReceiverApplications) || const DeepCollectionEquality().equals(other.castReceiverApplications, castReceiverApplications)) && + (identical(other.trickplayOptions, trickplayOptions) || const DeepCollectionEquality().equals(other.trickplayOptions, trickplayOptions))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(logFileRetentionDays) ^ + const DeepCollectionEquality().hash(isStartupWizardCompleted) ^ + const DeepCollectionEquality().hash(cachePath) ^ + const DeepCollectionEquality().hash(previousVersion) ^ + const DeepCollectionEquality().hash(previousVersionStr) ^ + const DeepCollectionEquality().hash(enableMetrics) ^ + const DeepCollectionEquality().hash(enableNormalizedItemByNameIds) ^ + const DeepCollectionEquality().hash(isPortAuthorized) ^ + const DeepCollectionEquality().hash(quickConnectAvailable) ^ + const DeepCollectionEquality().hash(enableCaseSensitiveItemIds) ^ + const DeepCollectionEquality().hash(disableLiveTvChannelUserDataName) ^ + const DeepCollectionEquality().hash(metadataPath) ^ + const DeepCollectionEquality().hash(metadataNetworkPath) ^ + const DeepCollectionEquality().hash(preferredMetadataLanguage) ^ + const DeepCollectionEquality().hash(metadataCountryCode) ^ + const DeepCollectionEquality().hash(sortReplaceCharacters) ^ + const DeepCollectionEquality().hash(sortRemoveCharacters) ^ + const DeepCollectionEquality().hash(sortRemoveWords) ^ + const DeepCollectionEquality().hash(minResumePct) ^ + const DeepCollectionEquality().hash(maxResumePct) ^ + const DeepCollectionEquality().hash(minResumeDurationSeconds) ^ + const DeepCollectionEquality().hash(minAudiobookResume) ^ + const DeepCollectionEquality().hash(maxAudiobookResume) ^ + const DeepCollectionEquality().hash(inactiveSessionThreshold) ^ + const DeepCollectionEquality().hash(libraryMonitorDelay) ^ + const DeepCollectionEquality().hash(libraryUpdateDuration) ^ + const DeepCollectionEquality().hash(imageSavingConvention) ^ + const DeepCollectionEquality().hash(metadataOptions) ^ + const DeepCollectionEquality().hash(skipDeserializationForBasicTypes) ^ + const DeepCollectionEquality().hash(serverName) ^ + const DeepCollectionEquality().hash(uICulture) ^ + const DeepCollectionEquality().hash(saveMetadataHidden) ^ + const DeepCollectionEquality().hash(contentTypes) ^ + const DeepCollectionEquality().hash(remoteClientBitrateLimit) ^ + const DeepCollectionEquality().hash(enableFolderView) ^ + const DeepCollectionEquality().hash(enableGroupingIntoCollections) ^ + const DeepCollectionEquality().hash(displaySpecialsWithinSeasons) ^ + const DeepCollectionEquality().hash(codecsUsed) ^ + const DeepCollectionEquality().hash(pluginRepositories) ^ + const DeepCollectionEquality().hash(enableExternalContentInSuggestions) ^ + const DeepCollectionEquality().hash(imageExtractionTimeoutMs) ^ + const DeepCollectionEquality().hash(pathSubstitutions) ^ + const DeepCollectionEquality().hash(enableSlowResponseWarning) ^ + const DeepCollectionEquality().hash(slowResponseThresholdMs) ^ + const DeepCollectionEquality().hash(corsHosts) ^ + const DeepCollectionEquality().hash(activityLogRetentionDays) ^ + const DeepCollectionEquality().hash(libraryScanFanoutConcurrency) ^ + const DeepCollectionEquality().hash(libraryMetadataRefreshConcurrency) ^ + const DeepCollectionEquality().hash(removeOldPlugins) ^ + const DeepCollectionEquality().hash(allowClientLogUpload) ^ + const DeepCollectionEquality().hash(dummyChapterDuration) ^ + const DeepCollectionEquality().hash(chapterImageResolution) ^ + const DeepCollectionEquality().hash(parallelImageEncodingLimit) ^ + const DeepCollectionEquality().hash(castReceiverApplications) ^ + const DeepCollectionEquality().hash(trickplayOptions) ^ + runtimeType.hashCode; +} + +extension $ServerConfigurationExtension on ServerConfiguration { + ServerConfiguration copyWith( + {int? logFileRetentionDays, + bool? isStartupWizardCompleted, + String? cachePath, + String? previousVersion, + String? previousVersionStr, + bool? enableMetrics, + bool? enableNormalizedItemByNameIds, + bool? isPortAuthorized, + bool? quickConnectAvailable, + bool? enableCaseSensitiveItemIds, + bool? disableLiveTvChannelUserDataName, + String? metadataPath, + String? metadataNetworkPath, + String? preferredMetadataLanguage, + String? metadataCountryCode, + List? sortReplaceCharacters, + List? sortRemoveCharacters, + List? sortRemoveWords, + int? minResumePct, + int? maxResumePct, + int? minResumeDurationSeconds, + int? minAudiobookResume, + int? maxAudiobookResume, + int? inactiveSessionThreshold, + int? libraryMonitorDelay, + int? libraryUpdateDuration, + enums.ImageSavingConvention? imageSavingConvention, + List? metadataOptions, + bool? skipDeserializationForBasicTypes, + String? serverName, + String? uICulture, + bool? saveMetadataHidden, + List? contentTypes, + int? remoteClientBitrateLimit, + bool? enableFolderView, + bool? enableGroupingIntoCollections, + bool? displaySpecialsWithinSeasons, + List? codecsUsed, + List? pluginRepositories, + bool? enableExternalContentInSuggestions, + int? imageExtractionTimeoutMs, + List? pathSubstitutions, + bool? enableSlowResponseWarning, + int? slowResponseThresholdMs, + List? corsHosts, + int? activityLogRetentionDays, + int? libraryScanFanoutConcurrency, + int? libraryMetadataRefreshConcurrency, + bool? removeOldPlugins, + bool? allowClientLogUpload, + int? dummyChapterDuration, + enums.ImageResolution? chapterImageResolution, + int? parallelImageEncodingLimit, + List? castReceiverApplications, + TrickplayOptions? trickplayOptions}) { + return ServerConfiguration( + logFileRetentionDays: logFileRetentionDays ?? this.logFileRetentionDays, + isStartupWizardCompleted: + isStartupWizardCompleted ?? this.isStartupWizardCompleted, + cachePath: cachePath ?? this.cachePath, + previousVersion: previousVersion ?? this.previousVersion, + previousVersionStr: previousVersionStr ?? this.previousVersionStr, + enableMetrics: enableMetrics ?? this.enableMetrics, + enableNormalizedItemByNameIds: + enableNormalizedItemByNameIds ?? this.enableNormalizedItemByNameIds, + isPortAuthorized: isPortAuthorized ?? this.isPortAuthorized, + quickConnectAvailable: + quickConnectAvailable ?? this.quickConnectAvailable, + enableCaseSensitiveItemIds: + enableCaseSensitiveItemIds ?? this.enableCaseSensitiveItemIds, + disableLiveTvChannelUserDataName: disableLiveTvChannelUserDataName ?? + this.disableLiveTvChannelUserDataName, + metadataPath: metadataPath ?? this.metadataPath, + metadataNetworkPath: metadataNetworkPath ?? this.metadataNetworkPath, + preferredMetadataLanguage: + preferredMetadataLanguage ?? this.preferredMetadataLanguage, + metadataCountryCode: metadataCountryCode ?? this.metadataCountryCode, + sortReplaceCharacters: + sortReplaceCharacters ?? this.sortReplaceCharacters, + sortRemoveCharacters: sortRemoveCharacters ?? this.sortRemoveCharacters, + sortRemoveWords: sortRemoveWords ?? this.sortRemoveWords, + minResumePct: minResumePct ?? this.minResumePct, + maxResumePct: maxResumePct ?? this.maxResumePct, + minResumeDurationSeconds: + minResumeDurationSeconds ?? this.minResumeDurationSeconds, + minAudiobookResume: minAudiobookResume ?? this.minAudiobookResume, + maxAudiobookResume: maxAudiobookResume ?? this.maxAudiobookResume, + inactiveSessionThreshold: + inactiveSessionThreshold ?? this.inactiveSessionThreshold, + libraryMonitorDelay: libraryMonitorDelay ?? this.libraryMonitorDelay, + libraryUpdateDuration: + libraryUpdateDuration ?? this.libraryUpdateDuration, + imageSavingConvention: + imageSavingConvention ?? this.imageSavingConvention, + metadataOptions: metadataOptions ?? this.metadataOptions, + skipDeserializationForBasicTypes: skipDeserializationForBasicTypes ?? + this.skipDeserializationForBasicTypes, + serverName: serverName ?? this.serverName, + uICulture: uICulture ?? this.uICulture, + saveMetadataHidden: saveMetadataHidden ?? this.saveMetadataHidden, + contentTypes: contentTypes ?? this.contentTypes, + remoteClientBitrateLimit: + remoteClientBitrateLimit ?? this.remoteClientBitrateLimit, + enableFolderView: enableFolderView ?? this.enableFolderView, + enableGroupingIntoCollections: + enableGroupingIntoCollections ?? this.enableGroupingIntoCollections, + displaySpecialsWithinSeasons: + displaySpecialsWithinSeasons ?? this.displaySpecialsWithinSeasons, + codecsUsed: codecsUsed ?? this.codecsUsed, + pluginRepositories: pluginRepositories ?? this.pluginRepositories, + enableExternalContentInSuggestions: + enableExternalContentInSuggestions ?? + this.enableExternalContentInSuggestions, + imageExtractionTimeoutMs: + imageExtractionTimeoutMs ?? this.imageExtractionTimeoutMs, + pathSubstitutions: pathSubstitutions ?? this.pathSubstitutions, + enableSlowResponseWarning: + enableSlowResponseWarning ?? this.enableSlowResponseWarning, + slowResponseThresholdMs: + slowResponseThresholdMs ?? this.slowResponseThresholdMs, + corsHosts: corsHosts ?? this.corsHosts, + activityLogRetentionDays: + activityLogRetentionDays ?? this.activityLogRetentionDays, + libraryScanFanoutConcurrency: + libraryScanFanoutConcurrency ?? this.libraryScanFanoutConcurrency, + libraryMetadataRefreshConcurrency: libraryMetadataRefreshConcurrency ?? + this.libraryMetadataRefreshConcurrency, + removeOldPlugins: removeOldPlugins ?? this.removeOldPlugins, + allowClientLogUpload: allowClientLogUpload ?? this.allowClientLogUpload, + dummyChapterDuration: dummyChapterDuration ?? this.dummyChapterDuration, + chapterImageResolution: + chapterImageResolution ?? this.chapterImageResolution, + parallelImageEncodingLimit: + parallelImageEncodingLimit ?? this.parallelImageEncodingLimit, + castReceiverApplications: + castReceiverApplications ?? this.castReceiverApplications, + trickplayOptions: trickplayOptions ?? this.trickplayOptions); + } + + ServerConfiguration copyWithWrapped( + {Wrapped? logFileRetentionDays, + Wrapped? isStartupWizardCompleted, + Wrapped? cachePath, + Wrapped? previousVersion, + Wrapped? previousVersionStr, + Wrapped? enableMetrics, + Wrapped? enableNormalizedItemByNameIds, + Wrapped? isPortAuthorized, + Wrapped? quickConnectAvailable, + Wrapped? enableCaseSensitiveItemIds, + Wrapped? disableLiveTvChannelUserDataName, + Wrapped? metadataPath, + Wrapped? metadataNetworkPath, + Wrapped? preferredMetadataLanguage, + Wrapped? metadataCountryCode, + Wrapped?>? sortReplaceCharacters, + Wrapped?>? sortRemoveCharacters, + Wrapped?>? sortRemoveWords, + Wrapped? minResumePct, + Wrapped? maxResumePct, + Wrapped? minResumeDurationSeconds, + Wrapped? minAudiobookResume, + Wrapped? maxAudiobookResume, + Wrapped? inactiveSessionThreshold, + Wrapped? libraryMonitorDelay, + Wrapped? libraryUpdateDuration, + Wrapped? imageSavingConvention, + Wrapped?>? metadataOptions, + Wrapped? skipDeserializationForBasicTypes, + Wrapped? serverName, + Wrapped? uICulture, + Wrapped? saveMetadataHidden, + Wrapped?>? contentTypes, + Wrapped? remoteClientBitrateLimit, + Wrapped? enableFolderView, + Wrapped? enableGroupingIntoCollections, + Wrapped? displaySpecialsWithinSeasons, + Wrapped?>? codecsUsed, + Wrapped?>? pluginRepositories, + Wrapped? enableExternalContentInSuggestions, + Wrapped? imageExtractionTimeoutMs, + Wrapped?>? pathSubstitutions, + Wrapped? enableSlowResponseWarning, + Wrapped? slowResponseThresholdMs, + Wrapped?>? corsHosts, + Wrapped? activityLogRetentionDays, + Wrapped? libraryScanFanoutConcurrency, + Wrapped? libraryMetadataRefreshConcurrency, + Wrapped? removeOldPlugins, + Wrapped? allowClientLogUpload, + Wrapped? dummyChapterDuration, + Wrapped? chapterImageResolution, + Wrapped? parallelImageEncodingLimit, + Wrapped?>? castReceiverApplications, + Wrapped? trickplayOptions}) { + return ServerConfiguration( + logFileRetentionDays: (logFileRetentionDays != null + ? logFileRetentionDays.value + : this.logFileRetentionDays), + isStartupWizardCompleted: (isStartupWizardCompleted != null + ? isStartupWizardCompleted.value + : this.isStartupWizardCompleted), + cachePath: (cachePath != null ? cachePath.value : this.cachePath), + previousVersion: (previousVersion != null + ? previousVersion.value + : this.previousVersion), + previousVersionStr: (previousVersionStr != null + ? previousVersionStr.value + : this.previousVersionStr), + enableMetrics: + (enableMetrics != null ? enableMetrics.value : this.enableMetrics), + enableNormalizedItemByNameIds: (enableNormalizedItemByNameIds != null + ? enableNormalizedItemByNameIds.value + : this.enableNormalizedItemByNameIds), + isPortAuthorized: (isPortAuthorized != null + ? isPortAuthorized.value + : this.isPortAuthorized), + quickConnectAvailable: (quickConnectAvailable != null + ? quickConnectAvailable.value + : this.quickConnectAvailable), + enableCaseSensitiveItemIds: (enableCaseSensitiveItemIds != null + ? enableCaseSensitiveItemIds.value + : this.enableCaseSensitiveItemIds), + disableLiveTvChannelUserDataName: (disableLiveTvChannelUserDataName != null + ? disableLiveTvChannelUserDataName.value + : this.disableLiveTvChannelUserDataName), + metadataPath: + (metadataPath != null ? metadataPath.value : this.metadataPath), + metadataNetworkPath: (metadataNetworkPath != null + ? metadataNetworkPath.value + : this.metadataNetworkPath), + preferredMetadataLanguage: (preferredMetadataLanguage != null + ? preferredMetadataLanguage.value + : this.preferredMetadataLanguage), + metadataCountryCode: (metadataCountryCode != null + ? metadataCountryCode.value + : this.metadataCountryCode), + sortReplaceCharacters: (sortReplaceCharacters != null + ? sortReplaceCharacters.value + : this.sortReplaceCharacters), + sortRemoveCharacters: (sortRemoveCharacters != null + ? sortRemoveCharacters.value + : this.sortRemoveCharacters), + sortRemoveWords: (sortRemoveWords != null + ? sortRemoveWords.value + : this.sortRemoveWords), + minResumePct: + (minResumePct != null ? minResumePct.value : this.minResumePct), + maxResumePct: + (maxResumePct != null ? maxResumePct.value : this.maxResumePct), + minResumeDurationSeconds: (minResumeDurationSeconds != null + ? minResumeDurationSeconds.value + : this.minResumeDurationSeconds), + minAudiobookResume: (minAudiobookResume != null + ? minAudiobookResume.value + : this.minAudiobookResume), + maxAudiobookResume: (maxAudiobookResume != null + ? maxAudiobookResume.value + : this.maxAudiobookResume), + inactiveSessionThreshold: (inactiveSessionThreshold != null + ? inactiveSessionThreshold.value + : this.inactiveSessionThreshold), + libraryMonitorDelay: (libraryMonitorDelay != null + ? libraryMonitorDelay.value + : this.libraryMonitorDelay), + libraryUpdateDuration: (libraryUpdateDuration != null + ? libraryUpdateDuration.value + : this.libraryUpdateDuration), + imageSavingConvention: (imageSavingConvention != null + ? imageSavingConvention.value + : this.imageSavingConvention), + metadataOptions: (metadataOptions != null + ? metadataOptions.value + : this.metadataOptions), + skipDeserializationForBasicTypes: (skipDeserializationForBasicTypes != null + ? skipDeserializationForBasicTypes.value + : this.skipDeserializationForBasicTypes), + serverName: (serverName != null ? serverName.value : this.serverName), + uICulture: (uICulture != null ? uICulture.value : this.uICulture), + saveMetadataHidden: (saveMetadataHidden != null + ? saveMetadataHidden.value + : this.saveMetadataHidden), + contentTypes: + (contentTypes != null ? contentTypes.value : this.contentTypes), + remoteClientBitrateLimit: (remoteClientBitrateLimit != null + ? remoteClientBitrateLimit.value + : this.remoteClientBitrateLimit), + enableFolderView: (enableFolderView != null + ? enableFolderView.value + : this.enableFolderView), + enableGroupingIntoCollections: (enableGroupingIntoCollections != null + ? enableGroupingIntoCollections.value + : this.enableGroupingIntoCollections), + displaySpecialsWithinSeasons: (displaySpecialsWithinSeasons != null + ? displaySpecialsWithinSeasons.value + : this.displaySpecialsWithinSeasons), + codecsUsed: (codecsUsed != null ? codecsUsed.value : this.codecsUsed), + pluginRepositories: (pluginRepositories != null + ? pluginRepositories.value + : this.pluginRepositories), + enableExternalContentInSuggestions: (enableExternalContentInSuggestions != null + ? enableExternalContentInSuggestions.value + : this.enableExternalContentInSuggestions), + imageExtractionTimeoutMs: (imageExtractionTimeoutMs != null + ? imageExtractionTimeoutMs.value + : this.imageExtractionTimeoutMs), + pathSubstitutions: (pathSubstitutions != null + ? pathSubstitutions.value + : this.pathSubstitutions), + enableSlowResponseWarning: (enableSlowResponseWarning != null + ? enableSlowResponseWarning.value + : this.enableSlowResponseWarning), + slowResponseThresholdMs: (slowResponseThresholdMs != null + ? slowResponseThresholdMs.value + : this.slowResponseThresholdMs), + corsHosts: (corsHosts != null ? corsHosts.value : this.corsHosts), + activityLogRetentionDays: (activityLogRetentionDays != null ? activityLogRetentionDays.value : this.activityLogRetentionDays), + libraryScanFanoutConcurrency: (libraryScanFanoutConcurrency != null ? libraryScanFanoutConcurrency.value : this.libraryScanFanoutConcurrency), + libraryMetadataRefreshConcurrency: (libraryMetadataRefreshConcurrency != null ? libraryMetadataRefreshConcurrency.value : this.libraryMetadataRefreshConcurrency), + removeOldPlugins: (removeOldPlugins != null ? removeOldPlugins.value : this.removeOldPlugins), + allowClientLogUpload: (allowClientLogUpload != null ? allowClientLogUpload.value : this.allowClientLogUpload), + dummyChapterDuration: (dummyChapterDuration != null ? dummyChapterDuration.value : this.dummyChapterDuration), + chapterImageResolution: (chapterImageResolution != null ? chapterImageResolution.value : this.chapterImageResolution), + parallelImageEncodingLimit: (parallelImageEncodingLimit != null ? parallelImageEncodingLimit.value : this.parallelImageEncodingLimit), + castReceiverApplications: (castReceiverApplications != null ? castReceiverApplications.value : this.castReceiverApplications), + trickplayOptions: (trickplayOptions != null ? trickplayOptions.value : this.trickplayOptions)); + } +} + +@JsonSerializable(explicitToJson: true) +class ServerDiscoveryInfo { + const ServerDiscoveryInfo({ + this.address, + this.id, + this.name, + this.endpointAddress, + }); + + factory ServerDiscoveryInfo.fromJson(Map json) => + _$ServerDiscoveryInfoFromJson(json); + + static const toJsonFactory = _$ServerDiscoveryInfoToJson; + Map toJson() => _$ServerDiscoveryInfoToJson(this); + + @JsonKey(name: 'Address', includeIfNull: false) + final String? address; + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'EndpointAddress', includeIfNull: false) + final String? endpointAddress; + static const fromJsonFactory = _$ServerDiscoveryInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ServerDiscoveryInfo && + (identical(other.address, address) || + const DeepCollectionEquality() + .equals(other.address, address)) && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.endpointAddress, endpointAddress) || + const DeepCollectionEquality() + .equals(other.endpointAddress, endpointAddress))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(address) ^ + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(endpointAddress) ^ + runtimeType.hashCode; +} + +extension $ServerDiscoveryInfoExtension on ServerDiscoveryInfo { + ServerDiscoveryInfo copyWith( + {String? address, String? id, String? name, String? endpointAddress}) { + return ServerDiscoveryInfo( + address: address ?? this.address, + id: id ?? this.id, + name: name ?? this.name, + endpointAddress: endpointAddress ?? this.endpointAddress); + } + + ServerDiscoveryInfo copyWithWrapped( + {Wrapped? address, + Wrapped? id, + Wrapped? name, + Wrapped? endpointAddress}) { + return ServerDiscoveryInfo( + address: (address != null ? address.value : this.address), + id: (id != null ? id.value : this.id), + name: (name != null ? name.value : this.name), + endpointAddress: (endpointAddress != null + ? endpointAddress.value + : this.endpointAddress)); + } +} + +@JsonSerializable(explicitToJson: true) +class ServerRestartingMessage { + const ServerRestartingMessage({ + this.messageId, + this.messageType, + }); + + factory ServerRestartingMessage.fromJson(Map json) => + _$ServerRestartingMessageFromJson(json); + + static const toJsonFactory = _$ServerRestartingMessageToJson; + Map toJson() => _$ServerRestartingMessageToJson(this); + + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.serverrestarting); + + static const fromJsonFactory = _$ServerRestartingMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ServerRestartingMessage && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $ServerRestartingMessageExtension on ServerRestartingMessage { + ServerRestartingMessage copyWith( + {String? messageId, enums.SessionMessageType? messageType}) { + return ServerRestartingMessage( + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + ServerRestartingMessage copyWithWrapped( + {Wrapped? messageId, + Wrapped? messageType}) { + return ServerRestartingMessage( + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class ServerShuttingDownMessage { + const ServerShuttingDownMessage({ + this.messageId, + this.messageType, + }); + + factory ServerShuttingDownMessage.fromJson(Map json) => + _$ServerShuttingDownMessageFromJson(json); + + static const toJsonFactory = _$ServerShuttingDownMessageToJson; + Map toJson() => _$ServerShuttingDownMessageToJson(this); + + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.servershuttingdown); + + static const fromJsonFactory = _$ServerShuttingDownMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ServerShuttingDownMessage && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $ServerShuttingDownMessageExtension on ServerShuttingDownMessage { + ServerShuttingDownMessage copyWith( + {String? messageId, enums.SessionMessageType? messageType}) { + return ServerShuttingDownMessage( + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + ServerShuttingDownMessage copyWithWrapped( + {Wrapped? messageId, + Wrapped? messageType}) { + return ServerShuttingDownMessage( + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class SessionInfo { + const SessionInfo({ + this.playState, + this.additionalUsers, + this.capabilities, + this.remoteEndPoint, + this.playableMediaTypes, + this.id, + this.userId, + this.userName, + this.$Client, + this.lastActivityDate, + this.lastPlaybackCheckIn, + this.lastPausedDate, + this.deviceName, + this.deviceType, + this.nowPlayingItem, + this.nowViewingItem, + this.deviceId, + this.applicationVersion, + this.transcodingInfo, + this.isActive, + this.supportsMediaControl, + this.supportsRemoteControl, + this.nowPlayingQueue, + this.nowPlayingQueueFullItems, + this.hasCustomDeviceName, + this.playlistItemId, + this.serverId, + this.userPrimaryImageTag, + this.supportedCommands, + }); + + factory SessionInfo.fromJson(Map json) => + _$SessionInfoFromJson(json); + + static const toJsonFactory = _$SessionInfoToJson; + Map toJson() => _$SessionInfoToJson(this); + + @JsonKey(name: 'PlayState', includeIfNull: false) + final PlayerStateInfo? playState; + @JsonKey( + name: 'AdditionalUsers', + includeIfNull: false, + defaultValue: []) + final List? additionalUsers; + @JsonKey(name: 'Capabilities', includeIfNull: false) + final ClientCapabilities? capabilities; + @JsonKey(name: 'RemoteEndPoint', includeIfNull: false) + final String? remoteEndPoint; + @JsonKey( + name: 'PlayableMediaTypes', + includeIfNull: false, + toJson: mediaTypeListToJson, + fromJson: mediaTypeListFromJson, + ) + final List? playableMediaTypes; + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'UserId', includeIfNull: false) + final String? userId; + @JsonKey(name: 'UserName', includeIfNull: false) + final String? userName; + @JsonKey(name: 'Client', includeIfNull: false) + final String? $Client; + @JsonKey(name: 'LastActivityDate', includeIfNull: false) + final DateTime? lastActivityDate; + @JsonKey(name: 'LastPlaybackCheckIn', includeIfNull: false) + final DateTime? lastPlaybackCheckIn; + @JsonKey(name: 'LastPausedDate', includeIfNull: false) + final DateTime? lastPausedDate; + @JsonKey(name: 'DeviceName', includeIfNull: false) + final String? deviceName; + @JsonKey(name: 'DeviceType', includeIfNull: false) + final String? deviceType; + @JsonKey(name: 'NowPlayingItem', includeIfNull: false) + final BaseItemDto? nowPlayingItem; + @JsonKey(name: 'NowViewingItem', includeIfNull: false) + final BaseItemDto? nowViewingItem; + @JsonKey(name: 'DeviceId', includeIfNull: false) + final String? deviceId; + @JsonKey(name: 'ApplicationVersion', includeIfNull: false) + final String? applicationVersion; + @JsonKey(name: 'TranscodingInfo', includeIfNull: false) + final TranscodingInfo? transcodingInfo; + @JsonKey(name: 'IsActive', includeIfNull: false) + final bool? isActive; + @JsonKey(name: 'SupportsMediaControl', includeIfNull: false) + final bool? supportsMediaControl; + @JsonKey(name: 'SupportsRemoteControl', includeIfNull: false) + final bool? supportsRemoteControl; + @JsonKey( + name: 'NowPlayingQueue', + includeIfNull: false, + defaultValue: []) + final List? nowPlayingQueue; + @JsonKey( + name: 'NowPlayingQueueFullItems', + includeIfNull: false, + defaultValue: []) + final List? nowPlayingQueueFullItems; + @JsonKey(name: 'HasCustomDeviceName', includeIfNull: false) + final bool? hasCustomDeviceName; + @JsonKey(name: 'PlaylistItemId', includeIfNull: false) + final String? playlistItemId; + @JsonKey(name: 'ServerId', includeIfNull: false) + final String? serverId; + @JsonKey(name: 'UserPrimaryImageTag', includeIfNull: false) + final String? userPrimaryImageTag; + @JsonKey( + name: 'SupportedCommands', + includeIfNull: false, + toJson: generalCommandTypeListToJson, + fromJson: generalCommandTypeListFromJson, + ) + final List? supportedCommands; + static const fromJsonFactory = _$SessionInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is SessionInfo && + (identical(other.playState, playState) || + const DeepCollectionEquality() + .equals(other.playState, playState)) && + (identical(other.additionalUsers, additionalUsers) || + const DeepCollectionEquality() + .equals(other.additionalUsers, additionalUsers)) && + (identical(other.capabilities, capabilities) || + const DeepCollectionEquality() + .equals(other.capabilities, capabilities)) && + (identical(other.remoteEndPoint, remoteEndPoint) || + const DeepCollectionEquality() + .equals(other.remoteEndPoint, remoteEndPoint)) && + (identical(other.playableMediaTypes, playableMediaTypes) || + const DeepCollectionEquality() + .equals(other.playableMediaTypes, playableMediaTypes)) && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.userId, userId) || + const DeepCollectionEquality().equals(other.userId, userId)) && + (identical(other.userName, userName) || + const DeepCollectionEquality() + .equals(other.userName, userName)) && + (identical(other.$Client, $Client) || + const DeepCollectionEquality() + .equals(other.$Client, $Client)) && + (identical(other.lastActivityDate, lastActivityDate) || + const DeepCollectionEquality() + .equals(other.lastActivityDate, lastActivityDate)) && + (identical(other.lastPlaybackCheckIn, lastPlaybackCheckIn) || + const DeepCollectionEquality() + .equals(other.lastPlaybackCheckIn, lastPlaybackCheckIn)) && + (identical(other.lastPausedDate, lastPausedDate) || + const DeepCollectionEquality() + .equals(other.lastPausedDate, lastPausedDate)) && + (identical(other.deviceName, deviceName) || + const DeepCollectionEquality() + .equals(other.deviceName, deviceName)) && + (identical(other.deviceType, deviceType) || + const DeepCollectionEquality() + .equals(other.deviceType, deviceType)) && + (identical(other.nowPlayingItem, nowPlayingItem) || + const DeepCollectionEquality() + .equals(other.nowPlayingItem, nowPlayingItem)) && + (identical(other.nowViewingItem, nowViewingItem) || + const DeepCollectionEquality() + .equals(other.nowViewingItem, nowViewingItem)) && + (identical(other.deviceId, deviceId) || + const DeepCollectionEquality() + .equals(other.deviceId, deviceId)) && + (identical(other.applicationVersion, applicationVersion) || + const DeepCollectionEquality() + .equals(other.applicationVersion, applicationVersion)) && + (identical(other.transcodingInfo, transcodingInfo) || + const DeepCollectionEquality() + .equals(other.transcodingInfo, transcodingInfo)) && + (identical(other.isActive, isActive) || + const DeepCollectionEquality() + .equals(other.isActive, isActive)) && + (identical(other.supportsMediaControl, supportsMediaControl) || + const DeepCollectionEquality().equals( + other.supportsMediaControl, supportsMediaControl)) && + (identical(other.supportsRemoteControl, supportsRemoteControl) || + const DeepCollectionEquality().equals( + other.supportsRemoteControl, supportsRemoteControl)) && + (identical(other.nowPlayingQueue, nowPlayingQueue) || const DeepCollectionEquality().equals(other.nowPlayingQueue, nowPlayingQueue)) && + (identical(other.nowPlayingQueueFullItems, nowPlayingQueueFullItems) || const DeepCollectionEquality().equals(other.nowPlayingQueueFullItems, nowPlayingQueueFullItems)) && + (identical(other.hasCustomDeviceName, hasCustomDeviceName) || const DeepCollectionEquality().equals(other.hasCustomDeviceName, hasCustomDeviceName)) && + (identical(other.playlistItemId, playlistItemId) || const DeepCollectionEquality().equals(other.playlistItemId, playlistItemId)) && + (identical(other.serverId, serverId) || const DeepCollectionEquality().equals(other.serverId, serverId)) && + (identical(other.userPrimaryImageTag, userPrimaryImageTag) || const DeepCollectionEquality().equals(other.userPrimaryImageTag, userPrimaryImageTag)) && + (identical(other.supportedCommands, supportedCommands) || const DeepCollectionEquality().equals(other.supportedCommands, supportedCommands))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(playState) ^ + const DeepCollectionEquality().hash(additionalUsers) ^ + const DeepCollectionEquality().hash(capabilities) ^ + const DeepCollectionEquality().hash(remoteEndPoint) ^ + const DeepCollectionEquality().hash(playableMediaTypes) ^ + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(userId) ^ + const DeepCollectionEquality().hash(userName) ^ + const DeepCollectionEquality().hash($Client) ^ + const DeepCollectionEquality().hash(lastActivityDate) ^ + const DeepCollectionEquality().hash(lastPlaybackCheckIn) ^ + const DeepCollectionEquality().hash(lastPausedDate) ^ + const DeepCollectionEquality().hash(deviceName) ^ + const DeepCollectionEquality().hash(deviceType) ^ + const DeepCollectionEquality().hash(nowPlayingItem) ^ + const DeepCollectionEquality().hash(nowViewingItem) ^ + const DeepCollectionEquality().hash(deviceId) ^ + const DeepCollectionEquality().hash(applicationVersion) ^ + const DeepCollectionEquality().hash(transcodingInfo) ^ + const DeepCollectionEquality().hash(isActive) ^ + const DeepCollectionEquality().hash(supportsMediaControl) ^ + const DeepCollectionEquality().hash(supportsRemoteControl) ^ + const DeepCollectionEquality().hash(nowPlayingQueue) ^ + const DeepCollectionEquality().hash(nowPlayingQueueFullItems) ^ + const DeepCollectionEquality().hash(hasCustomDeviceName) ^ + const DeepCollectionEquality().hash(playlistItemId) ^ + const DeepCollectionEquality().hash(serverId) ^ + const DeepCollectionEquality().hash(userPrimaryImageTag) ^ + const DeepCollectionEquality().hash(supportedCommands) ^ + runtimeType.hashCode; +} + +extension $SessionInfoExtension on SessionInfo { + SessionInfo copyWith( + {PlayerStateInfo? playState, + List? additionalUsers, + ClientCapabilities? capabilities, + String? remoteEndPoint, + List? playableMediaTypes, + String? id, + String? userId, + String? userName, + String? $Client, + DateTime? lastActivityDate, + DateTime? lastPlaybackCheckIn, + DateTime? lastPausedDate, + String? deviceName, + String? deviceType, + BaseItemDto? nowPlayingItem, + BaseItemDto? nowViewingItem, + String? deviceId, + String? applicationVersion, + TranscodingInfo? transcodingInfo, + bool? isActive, + bool? supportsMediaControl, + bool? supportsRemoteControl, + List? nowPlayingQueue, + List? nowPlayingQueueFullItems, + bool? hasCustomDeviceName, + String? playlistItemId, + String? serverId, + String? userPrimaryImageTag, + List? supportedCommands}) { + return SessionInfo( + playState: playState ?? this.playState, + additionalUsers: additionalUsers ?? this.additionalUsers, + capabilities: capabilities ?? this.capabilities, + remoteEndPoint: remoteEndPoint ?? this.remoteEndPoint, + playableMediaTypes: playableMediaTypes ?? this.playableMediaTypes, + id: id ?? this.id, + userId: userId ?? this.userId, + userName: userName ?? this.userName, + $Client: $Client ?? this.$Client, + lastActivityDate: lastActivityDate ?? this.lastActivityDate, + lastPlaybackCheckIn: lastPlaybackCheckIn ?? this.lastPlaybackCheckIn, + lastPausedDate: lastPausedDate ?? this.lastPausedDate, + deviceName: deviceName ?? this.deviceName, + deviceType: deviceType ?? this.deviceType, + nowPlayingItem: nowPlayingItem ?? this.nowPlayingItem, + nowViewingItem: nowViewingItem ?? this.nowViewingItem, + deviceId: deviceId ?? this.deviceId, + applicationVersion: applicationVersion ?? this.applicationVersion, + transcodingInfo: transcodingInfo ?? this.transcodingInfo, + isActive: isActive ?? this.isActive, + supportsMediaControl: supportsMediaControl ?? this.supportsMediaControl, + supportsRemoteControl: + supportsRemoteControl ?? this.supportsRemoteControl, + nowPlayingQueue: nowPlayingQueue ?? this.nowPlayingQueue, + nowPlayingQueueFullItems: + nowPlayingQueueFullItems ?? this.nowPlayingQueueFullItems, + hasCustomDeviceName: hasCustomDeviceName ?? this.hasCustomDeviceName, + playlistItemId: playlistItemId ?? this.playlistItemId, + serverId: serverId ?? this.serverId, + userPrimaryImageTag: userPrimaryImageTag ?? this.userPrimaryImageTag, + supportedCommands: supportedCommands ?? this.supportedCommands); + } + + SessionInfo copyWithWrapped( + {Wrapped? playState, + Wrapped?>? additionalUsers, + Wrapped? capabilities, + Wrapped? remoteEndPoint, + Wrapped?>? playableMediaTypes, + Wrapped? id, + Wrapped? userId, + Wrapped? userName, + Wrapped? $Client, + Wrapped? lastActivityDate, + Wrapped? lastPlaybackCheckIn, + Wrapped? lastPausedDate, + Wrapped? deviceName, + Wrapped? deviceType, + Wrapped? nowPlayingItem, + Wrapped? nowViewingItem, + Wrapped? deviceId, + Wrapped? applicationVersion, + Wrapped? transcodingInfo, + Wrapped? isActive, + Wrapped? supportsMediaControl, + Wrapped? supportsRemoteControl, + Wrapped?>? nowPlayingQueue, + Wrapped?>? nowPlayingQueueFullItems, + Wrapped? hasCustomDeviceName, + Wrapped? playlistItemId, + Wrapped? serverId, + Wrapped? userPrimaryImageTag, + Wrapped?>? supportedCommands}) { + return SessionInfo( + playState: (playState != null ? playState.value : this.playState), + additionalUsers: (additionalUsers != null + ? additionalUsers.value + : this.additionalUsers), + capabilities: + (capabilities != null ? capabilities.value : this.capabilities), + remoteEndPoint: (remoteEndPoint != null + ? remoteEndPoint.value + : this.remoteEndPoint), + playableMediaTypes: (playableMediaTypes != null + ? playableMediaTypes.value + : this.playableMediaTypes), + id: (id != null ? id.value : this.id), + userId: (userId != null ? userId.value : this.userId), + userName: (userName != null ? userName.value : this.userName), + $Client: ($Client != null ? $Client.value : this.$Client), + lastActivityDate: (lastActivityDate != null + ? lastActivityDate.value + : this.lastActivityDate), + lastPlaybackCheckIn: (lastPlaybackCheckIn != null + ? lastPlaybackCheckIn.value + : this.lastPlaybackCheckIn), + lastPausedDate: (lastPausedDate != null + ? lastPausedDate.value + : this.lastPausedDate), + deviceName: (deviceName != null ? deviceName.value : this.deviceName), + deviceType: (deviceType != null ? deviceType.value : this.deviceType), + nowPlayingItem: (nowPlayingItem != null + ? nowPlayingItem.value + : this.nowPlayingItem), + nowViewingItem: (nowViewingItem != null + ? nowViewingItem.value + : this.nowViewingItem), + deviceId: (deviceId != null ? deviceId.value : this.deviceId), + applicationVersion: (applicationVersion != null + ? applicationVersion.value + : this.applicationVersion), + transcodingInfo: (transcodingInfo != null + ? transcodingInfo.value + : this.transcodingInfo), + isActive: (isActive != null ? isActive.value : this.isActive), + supportsMediaControl: (supportsMediaControl != null + ? supportsMediaControl.value + : this.supportsMediaControl), + supportsRemoteControl: (supportsRemoteControl != null + ? supportsRemoteControl.value + : this.supportsRemoteControl), + nowPlayingQueue: (nowPlayingQueue != null + ? nowPlayingQueue.value + : this.nowPlayingQueue), + nowPlayingQueueFullItems: (nowPlayingQueueFullItems != null + ? nowPlayingQueueFullItems.value + : this.nowPlayingQueueFullItems), + hasCustomDeviceName: (hasCustomDeviceName != null + ? hasCustomDeviceName.value + : this.hasCustomDeviceName), + playlistItemId: (playlistItemId != null + ? playlistItemId.value + : this.playlistItemId), + serverId: (serverId != null ? serverId.value : this.serverId), + userPrimaryImageTag: (userPrimaryImageTag != null + ? userPrimaryImageTag.value + : this.userPrimaryImageTag), + supportedCommands: (supportedCommands != null + ? supportedCommands.value + : this.supportedCommands)); + } +} + +@JsonSerializable(explicitToJson: true) +class SessionsMessage { + const SessionsMessage({ + this.data, + this.messageId, + this.messageType, + }); + + factory SessionsMessage.fromJson(Map json) => + _$SessionsMessageFromJson(json); + + static const toJsonFactory = _$SessionsMessageToJson; + Map toJson() => _$SessionsMessageToJson(this); + + @JsonKey(name: 'Data', includeIfNull: false, defaultValue: []) + final List? data; + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.sessions); + + static const fromJsonFactory = _$SessionsMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is SessionsMessage && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data)) && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(data) ^ + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $SessionsMessageExtension on SessionsMessage { + SessionsMessage copyWith( + {List? data, + String? messageId, + enums.SessionMessageType? messageType}) { + return SessionsMessage( + data: data ?? this.data, + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + SessionsMessage copyWithWrapped( + {Wrapped?>? data, + Wrapped? messageId, + Wrapped? messageType}) { + return SessionsMessage( + data: (data != null ? data.value : this.data), + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class SessionsStartMessage { + const SessionsStartMessage({ + this.data, + this.messageType, + }); + + factory SessionsStartMessage.fromJson(Map json) => + _$SessionsStartMessageFromJson(json); + + static const toJsonFactory = _$SessionsStartMessageToJson; + Map toJson() => _$SessionsStartMessageToJson(this); + + @JsonKey(name: 'Data', includeIfNull: false) + final String? data; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.sessionsstart); + + static const fromJsonFactory = _$SessionsStartMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is SessionsStartMessage && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(data) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $SessionsStartMessageExtension on SessionsStartMessage { + SessionsStartMessage copyWith( + {String? data, enums.SessionMessageType? messageType}) { + return SessionsStartMessage( + data: data ?? this.data, messageType: messageType ?? this.messageType); + } + + SessionsStartMessage copyWithWrapped( + {Wrapped? data, + Wrapped? messageType}) { + return SessionsStartMessage( + data: (data != null ? data.value : this.data), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class SessionsStopMessage { + const SessionsStopMessage({ + this.messageType, + }); + + factory SessionsStopMessage.fromJson(Map json) => + _$SessionsStopMessageFromJson(json); + + static const toJsonFactory = _$SessionsStopMessageToJson; + Map toJson() => _$SessionsStopMessageToJson(this); + + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.sessionsstop); + + static const fromJsonFactory = _$SessionsStopMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is SessionsStopMessage && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(messageType) ^ runtimeType.hashCode; +} + +extension $SessionsStopMessageExtension on SessionsStopMessage { + SessionsStopMessage copyWith({enums.SessionMessageType? messageType}) { + return SessionsStopMessage(messageType: messageType ?? this.messageType); + } + + SessionsStopMessage copyWithWrapped( + {Wrapped? messageType}) { + return SessionsStopMessage( + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class SessionUserInfo { + const SessionUserInfo({ + this.userId, + this.userName, + }); + + factory SessionUserInfo.fromJson(Map json) => + _$SessionUserInfoFromJson(json); + + static const toJsonFactory = _$SessionUserInfoToJson; + Map toJson() => _$SessionUserInfoToJson(this); + + @JsonKey(name: 'UserId', includeIfNull: false) + final String? userId; + @JsonKey(name: 'UserName', includeIfNull: false) + final String? userName; + static const fromJsonFactory = _$SessionUserInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is SessionUserInfo && + (identical(other.userId, userId) || + const DeepCollectionEquality().equals(other.userId, userId)) && + (identical(other.userName, userName) || + const DeepCollectionEquality() + .equals(other.userName, userName))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(userId) ^ + const DeepCollectionEquality().hash(userName) ^ + runtimeType.hashCode; +} + +extension $SessionUserInfoExtension on SessionUserInfo { + SessionUserInfo copyWith({String? userId, String? userName}) { + return SessionUserInfo( + userId: userId ?? this.userId, userName: userName ?? this.userName); + } + + SessionUserInfo copyWithWrapped( + {Wrapped? userId, Wrapped? userName}) { + return SessionUserInfo( + userId: (userId != null ? userId.value : this.userId), + userName: (userName != null ? userName.value : this.userName)); + } +} + +@JsonSerializable(explicitToJson: true) +class SetChannelMappingDto { + const SetChannelMappingDto({ + required this.providerId, + required this.tunerChannelId, + required this.providerChannelId, + }); + + factory SetChannelMappingDto.fromJson(Map json) => + _$SetChannelMappingDtoFromJson(json); + + static const toJsonFactory = _$SetChannelMappingDtoToJson; + Map toJson() => _$SetChannelMappingDtoToJson(this); + + @JsonKey(name: 'ProviderId', includeIfNull: false) + final String providerId; + @JsonKey(name: 'TunerChannelId', includeIfNull: false) + final String tunerChannelId; + @JsonKey(name: 'ProviderChannelId', includeIfNull: false) + final String providerChannelId; + static const fromJsonFactory = _$SetChannelMappingDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is SetChannelMappingDto && + (identical(other.providerId, providerId) || + const DeepCollectionEquality() + .equals(other.providerId, providerId)) && + (identical(other.tunerChannelId, tunerChannelId) || + const DeepCollectionEquality() + .equals(other.tunerChannelId, tunerChannelId)) && + (identical(other.providerChannelId, providerChannelId) || + const DeepCollectionEquality() + .equals(other.providerChannelId, providerChannelId))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(providerId) ^ + const DeepCollectionEquality().hash(tunerChannelId) ^ + const DeepCollectionEquality().hash(providerChannelId) ^ + runtimeType.hashCode; +} + +extension $SetChannelMappingDtoExtension on SetChannelMappingDto { + SetChannelMappingDto copyWith( + {String? providerId, String? tunerChannelId, String? providerChannelId}) { + return SetChannelMappingDto( + providerId: providerId ?? this.providerId, + tunerChannelId: tunerChannelId ?? this.tunerChannelId, + providerChannelId: providerChannelId ?? this.providerChannelId); + } + + SetChannelMappingDto copyWithWrapped( + {Wrapped? providerId, + Wrapped? tunerChannelId, + Wrapped? providerChannelId}) { + return SetChannelMappingDto( + providerId: (providerId != null ? providerId.value : this.providerId), + tunerChannelId: (tunerChannelId != null + ? tunerChannelId.value + : this.tunerChannelId), + providerChannelId: (providerChannelId != null + ? providerChannelId.value + : this.providerChannelId)); + } +} + +@JsonSerializable(explicitToJson: true) +class SetPlaylistItemRequestDto { + const SetPlaylistItemRequestDto({ + this.playlistItemId, + }); + + factory SetPlaylistItemRequestDto.fromJson(Map json) => + _$SetPlaylistItemRequestDtoFromJson(json); + + static const toJsonFactory = _$SetPlaylistItemRequestDtoToJson; + Map toJson() => _$SetPlaylistItemRequestDtoToJson(this); + + @JsonKey(name: 'PlaylistItemId', includeIfNull: false) + final String? playlistItemId; + static const fromJsonFactory = _$SetPlaylistItemRequestDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is SetPlaylistItemRequestDto && + (identical(other.playlistItemId, playlistItemId) || + const DeepCollectionEquality() + .equals(other.playlistItemId, playlistItemId))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(playlistItemId) ^ + runtimeType.hashCode; +} + +extension $SetPlaylistItemRequestDtoExtension on SetPlaylistItemRequestDto { + SetPlaylistItemRequestDto copyWith({String? playlistItemId}) { + return SetPlaylistItemRequestDto( + playlistItemId: playlistItemId ?? this.playlistItemId); + } + + SetPlaylistItemRequestDto copyWithWrapped( + {Wrapped? playlistItemId}) { + return SetPlaylistItemRequestDto( + playlistItemId: (playlistItemId != null + ? playlistItemId.value + : this.playlistItemId)); + } +} + +@JsonSerializable(explicitToJson: true) +class SetRepeatModeRequestDto { + const SetRepeatModeRequestDto({ + this.mode, + }); + + factory SetRepeatModeRequestDto.fromJson(Map json) => + _$SetRepeatModeRequestDtoFromJson(json); + + static const toJsonFactory = _$SetRepeatModeRequestDtoToJson; + Map toJson() => _$SetRepeatModeRequestDtoToJson(this); + + @JsonKey( + name: 'Mode', + includeIfNull: false, + toJson: groupRepeatModeNullableToJson, + fromJson: groupRepeatModeNullableFromJson, + ) + final enums.GroupRepeatMode? mode; + static const fromJsonFactory = _$SetRepeatModeRequestDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is SetRepeatModeRequestDto && + (identical(other.mode, mode) || + const DeepCollectionEquality().equals(other.mode, mode))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(mode) ^ runtimeType.hashCode; +} + +extension $SetRepeatModeRequestDtoExtension on SetRepeatModeRequestDto { + SetRepeatModeRequestDto copyWith({enums.GroupRepeatMode? mode}) { + return SetRepeatModeRequestDto(mode: mode ?? this.mode); + } + + SetRepeatModeRequestDto copyWithWrapped( + {Wrapped? mode}) { + return SetRepeatModeRequestDto( + mode: (mode != null ? mode.value : this.mode)); + } +} + +@JsonSerializable(explicitToJson: true) +class SetShuffleModeRequestDto { + const SetShuffleModeRequestDto({ + this.mode, + }); + + factory SetShuffleModeRequestDto.fromJson(Map json) => + _$SetShuffleModeRequestDtoFromJson(json); + + static const toJsonFactory = _$SetShuffleModeRequestDtoToJson; + Map toJson() => _$SetShuffleModeRequestDtoToJson(this); + + @JsonKey( + name: 'Mode', + includeIfNull: false, + toJson: groupShuffleModeNullableToJson, + fromJson: groupShuffleModeNullableFromJson, + ) + final enums.GroupShuffleMode? mode; + static const fromJsonFactory = _$SetShuffleModeRequestDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is SetShuffleModeRequestDto && + (identical(other.mode, mode) || + const DeepCollectionEquality().equals(other.mode, mode))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(mode) ^ runtimeType.hashCode; +} + +extension $SetShuffleModeRequestDtoExtension on SetShuffleModeRequestDto { + SetShuffleModeRequestDto copyWith({enums.GroupShuffleMode? mode}) { + return SetShuffleModeRequestDto(mode: mode ?? this.mode); + } + + SetShuffleModeRequestDto copyWithWrapped( + {Wrapped? mode}) { + return SetShuffleModeRequestDto( + mode: (mode != null ? mode.value : this.mode)); + } +} + +@JsonSerializable(explicitToJson: true) +class SongInfo { + const SongInfo({ + this.name, + this.originalTitle, + this.path, + this.metadataLanguage, + this.metadataCountryCode, + this.providerIds, + this.year, + this.indexNumber, + this.parentIndexNumber, + this.premiereDate, + this.isAutomated, + this.albumArtists, + this.album, + this.artists, + }); + + factory SongInfo.fromJson(Map json) => + _$SongInfoFromJson(json); + + static const toJsonFactory = _$SongInfoToJson; + Map toJson() => _$SongInfoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'OriginalTitle', includeIfNull: false) + final String? originalTitle; + @JsonKey(name: 'Path', includeIfNull: false) + final String? path; + @JsonKey(name: 'MetadataLanguage', includeIfNull: false) + final String? metadataLanguage; + @JsonKey(name: 'MetadataCountryCode', includeIfNull: false) + final String? metadataCountryCode; + @JsonKey(name: 'ProviderIds', includeIfNull: false) + final Map? providerIds; + @JsonKey(name: 'Year', includeIfNull: false) + final int? year; + @JsonKey(name: 'IndexNumber', includeIfNull: false) + final int? indexNumber; + @JsonKey(name: 'ParentIndexNumber', includeIfNull: false) + final int? parentIndexNumber; + @JsonKey(name: 'PremiereDate', includeIfNull: false) + final DateTime? premiereDate; + @JsonKey(name: 'IsAutomated', includeIfNull: false) + final bool? isAutomated; + @JsonKey(name: 'AlbumArtists', includeIfNull: false, defaultValue: []) + final List? albumArtists; + @JsonKey(name: 'Album', includeIfNull: false) + final String? album; + @JsonKey(name: 'Artists', includeIfNull: false, defaultValue: []) + final List? artists; + static const fromJsonFactory = _$SongInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is SongInfo && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.originalTitle, originalTitle) || + const DeepCollectionEquality() + .equals(other.originalTitle, originalTitle)) && + (identical(other.path, path) || + const DeepCollectionEquality().equals(other.path, path)) && + (identical(other.metadataLanguage, metadataLanguage) || + const DeepCollectionEquality() + .equals(other.metadataLanguage, metadataLanguage)) && + (identical(other.metadataCountryCode, metadataCountryCode) || + const DeepCollectionEquality() + .equals(other.metadataCountryCode, metadataCountryCode)) && + (identical(other.providerIds, providerIds) || + const DeepCollectionEquality() + .equals(other.providerIds, providerIds)) && + (identical(other.year, year) || + const DeepCollectionEquality().equals(other.year, year)) && + (identical(other.indexNumber, indexNumber) || + const DeepCollectionEquality() + .equals(other.indexNumber, indexNumber)) && + (identical(other.parentIndexNumber, parentIndexNumber) || + const DeepCollectionEquality() + .equals(other.parentIndexNumber, parentIndexNumber)) && + (identical(other.premiereDate, premiereDate) || + const DeepCollectionEquality() + .equals(other.premiereDate, premiereDate)) && + (identical(other.isAutomated, isAutomated) || + const DeepCollectionEquality() + .equals(other.isAutomated, isAutomated)) && + (identical(other.albumArtists, albumArtists) || + const DeepCollectionEquality() + .equals(other.albumArtists, albumArtists)) && + (identical(other.album, album) || + const DeepCollectionEquality().equals(other.album, album)) && + (identical(other.artists, artists) || + const DeepCollectionEquality().equals(other.artists, artists))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(originalTitle) ^ + const DeepCollectionEquality().hash(path) ^ + const DeepCollectionEquality().hash(metadataLanguage) ^ + const DeepCollectionEquality().hash(metadataCountryCode) ^ + const DeepCollectionEquality().hash(providerIds) ^ + const DeepCollectionEquality().hash(year) ^ + const DeepCollectionEquality().hash(indexNumber) ^ + const DeepCollectionEquality().hash(parentIndexNumber) ^ + const DeepCollectionEquality().hash(premiereDate) ^ + const DeepCollectionEquality().hash(isAutomated) ^ + const DeepCollectionEquality().hash(albumArtists) ^ + const DeepCollectionEquality().hash(album) ^ + const DeepCollectionEquality().hash(artists) ^ + runtimeType.hashCode; +} + +extension $SongInfoExtension on SongInfo { + SongInfo copyWith( + {String? name, + String? originalTitle, + String? path, + String? metadataLanguage, + String? metadataCountryCode, + Map? providerIds, + int? year, + int? indexNumber, + int? parentIndexNumber, + DateTime? premiereDate, + bool? isAutomated, + List? albumArtists, + String? album, + List? artists}) { + return SongInfo( + name: name ?? this.name, + originalTitle: originalTitle ?? this.originalTitle, + path: path ?? this.path, + metadataLanguage: metadataLanguage ?? this.metadataLanguage, + metadataCountryCode: metadataCountryCode ?? this.metadataCountryCode, + providerIds: providerIds ?? this.providerIds, + year: year ?? this.year, + indexNumber: indexNumber ?? this.indexNumber, + parentIndexNumber: parentIndexNumber ?? this.parentIndexNumber, + premiereDate: premiereDate ?? this.premiereDate, + isAutomated: isAutomated ?? this.isAutomated, + albumArtists: albumArtists ?? this.albumArtists, + album: album ?? this.album, + artists: artists ?? this.artists); + } + + SongInfo copyWithWrapped( + {Wrapped? name, + Wrapped? originalTitle, + Wrapped? path, + Wrapped? metadataLanguage, + Wrapped? metadataCountryCode, + Wrapped?>? providerIds, + Wrapped? year, + Wrapped? indexNumber, + Wrapped? parentIndexNumber, + Wrapped? premiereDate, + Wrapped? isAutomated, + Wrapped?>? albumArtists, + Wrapped? album, + Wrapped?>? artists}) { + return SongInfo( + name: (name != null ? name.value : this.name), + originalTitle: + (originalTitle != null ? originalTitle.value : this.originalTitle), + path: (path != null ? path.value : this.path), + metadataLanguage: (metadataLanguage != null + ? metadataLanguage.value + : this.metadataLanguage), + metadataCountryCode: (metadataCountryCode != null + ? metadataCountryCode.value + : this.metadataCountryCode), + providerIds: + (providerIds != null ? providerIds.value : this.providerIds), + year: (year != null ? year.value : this.year), + indexNumber: + (indexNumber != null ? indexNumber.value : this.indexNumber), + parentIndexNumber: (parentIndexNumber != null + ? parentIndexNumber.value + : this.parentIndexNumber), + premiereDate: + (premiereDate != null ? premiereDate.value : this.premiereDate), + isAutomated: + (isAutomated != null ? isAutomated.value : this.isAutomated), + albumArtists: + (albumArtists != null ? albumArtists.value : this.albumArtists), + album: (album != null ? album.value : this.album), + artists: (artists != null ? artists.value : this.artists)); + } +} + +@JsonSerializable(explicitToJson: true) +class SpecialViewOptionDto { + const SpecialViewOptionDto({ + this.name, + this.id, + }); + + factory SpecialViewOptionDto.fromJson(Map json) => + _$SpecialViewOptionDtoFromJson(json); + + static const toJsonFactory = _$SpecialViewOptionDtoToJson; + Map toJson() => _$SpecialViewOptionDtoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + static const fromJsonFactory = _$SpecialViewOptionDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is SpecialViewOptionDto && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(id) ^ + runtimeType.hashCode; +} + +extension $SpecialViewOptionDtoExtension on SpecialViewOptionDto { + SpecialViewOptionDto copyWith({String? name, String? id}) { + return SpecialViewOptionDto(name: name ?? this.name, id: id ?? this.id); + } + + SpecialViewOptionDto copyWithWrapped( + {Wrapped? name, Wrapped? id}) { + return SpecialViewOptionDto( + name: (name != null ? name.value : this.name), + id: (id != null ? id.value : this.id)); + } +} + +@JsonSerializable(explicitToJson: true) +class StartupConfigurationDto { + const StartupConfigurationDto({ + this.uICulture, + this.metadataCountryCode, + this.preferredMetadataLanguage, + }); + + factory StartupConfigurationDto.fromJson(Map json) => + _$StartupConfigurationDtoFromJson(json); + + static const toJsonFactory = _$StartupConfigurationDtoToJson; + Map toJson() => _$StartupConfigurationDtoToJson(this); + + @JsonKey(name: 'UICulture', includeIfNull: false) + final String? uICulture; + @JsonKey(name: 'MetadataCountryCode', includeIfNull: false) + final String? metadataCountryCode; + @JsonKey(name: 'PreferredMetadataLanguage', includeIfNull: false) + final String? preferredMetadataLanguage; + static const fromJsonFactory = _$StartupConfigurationDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is StartupConfigurationDto && + (identical(other.uICulture, uICulture) || + const DeepCollectionEquality() + .equals(other.uICulture, uICulture)) && + (identical(other.metadataCountryCode, metadataCountryCode) || + const DeepCollectionEquality() + .equals(other.metadataCountryCode, metadataCountryCode)) && + (identical(other.preferredMetadataLanguage, + preferredMetadataLanguage) || + const DeepCollectionEquality().equals( + other.preferredMetadataLanguage, + preferredMetadataLanguage))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(uICulture) ^ + const DeepCollectionEquality().hash(metadataCountryCode) ^ + const DeepCollectionEquality().hash(preferredMetadataLanguage) ^ + runtimeType.hashCode; +} + +extension $StartupConfigurationDtoExtension on StartupConfigurationDto { + StartupConfigurationDto copyWith( + {String? uICulture, + String? metadataCountryCode, + String? preferredMetadataLanguage}) { + return StartupConfigurationDto( + uICulture: uICulture ?? this.uICulture, + metadataCountryCode: metadataCountryCode ?? this.metadataCountryCode, + preferredMetadataLanguage: + preferredMetadataLanguage ?? this.preferredMetadataLanguage); + } + + StartupConfigurationDto copyWithWrapped( + {Wrapped? uICulture, + Wrapped? metadataCountryCode, + Wrapped? preferredMetadataLanguage}) { + return StartupConfigurationDto( + uICulture: (uICulture != null ? uICulture.value : this.uICulture), + metadataCountryCode: (metadataCountryCode != null + ? metadataCountryCode.value + : this.metadataCountryCode), + preferredMetadataLanguage: (preferredMetadataLanguage != null + ? preferredMetadataLanguage.value + : this.preferredMetadataLanguage)); + } +} + +@JsonSerializable(explicitToJson: true) +class StartupRemoteAccessDto { + const StartupRemoteAccessDto({ + required this.enableRemoteAccess, + required this.enableAutomaticPortMapping, + }); + + factory StartupRemoteAccessDto.fromJson(Map json) => + _$StartupRemoteAccessDtoFromJson(json); + + static const toJsonFactory = _$StartupRemoteAccessDtoToJson; + Map toJson() => _$StartupRemoteAccessDtoToJson(this); + + @JsonKey(name: 'EnableRemoteAccess', includeIfNull: false) + final bool enableRemoteAccess; + @JsonKey(name: 'EnableAutomaticPortMapping', includeIfNull: false) + final bool enableAutomaticPortMapping; + static const fromJsonFactory = _$StartupRemoteAccessDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is StartupRemoteAccessDto && + (identical(other.enableRemoteAccess, enableRemoteAccess) || + const DeepCollectionEquality() + .equals(other.enableRemoteAccess, enableRemoteAccess)) && + (identical(other.enableAutomaticPortMapping, + enableAutomaticPortMapping) || + const DeepCollectionEquality().equals( + other.enableAutomaticPortMapping, + enableAutomaticPortMapping))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(enableRemoteAccess) ^ + const DeepCollectionEquality().hash(enableAutomaticPortMapping) ^ + runtimeType.hashCode; +} + +extension $StartupRemoteAccessDtoExtension on StartupRemoteAccessDto { + StartupRemoteAccessDto copyWith( + {bool? enableRemoteAccess, bool? enableAutomaticPortMapping}) { + return StartupRemoteAccessDto( + enableRemoteAccess: enableRemoteAccess ?? this.enableRemoteAccess, + enableAutomaticPortMapping: + enableAutomaticPortMapping ?? this.enableAutomaticPortMapping); + } + + StartupRemoteAccessDto copyWithWrapped( + {Wrapped? enableRemoteAccess, + Wrapped? enableAutomaticPortMapping}) { + return StartupRemoteAccessDto( + enableRemoteAccess: (enableRemoteAccess != null + ? enableRemoteAccess.value + : this.enableRemoteAccess), + enableAutomaticPortMapping: (enableAutomaticPortMapping != null + ? enableAutomaticPortMapping.value + : this.enableAutomaticPortMapping)); + } +} + +@JsonSerializable(explicitToJson: true) +class StartupUserDto { + const StartupUserDto({ + this.name, + this.password, + }); + + factory StartupUserDto.fromJson(Map json) => + _$StartupUserDtoFromJson(json); + + static const toJsonFactory = _$StartupUserDtoToJson; + Map toJson() => _$StartupUserDtoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'Password', includeIfNull: false) + final String? password; + static const fromJsonFactory = _$StartupUserDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is StartupUserDto && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.password, password) || + const DeepCollectionEquality() + .equals(other.password, password))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(password) ^ + runtimeType.hashCode; +} + +extension $StartupUserDtoExtension on StartupUserDto { + StartupUserDto copyWith({String? name, String? password}) { + return StartupUserDto( + name: name ?? this.name, password: password ?? this.password); + } + + StartupUserDto copyWithWrapped( + {Wrapped? name, Wrapped? password}) { + return StartupUserDto( + name: (name != null ? name.value : this.name), + password: (password != null ? password.value : this.password)); + } +} + +@JsonSerializable(explicitToJson: true) +class StringGroupUpdate { + const StringGroupUpdate({ + this.groupId, + this.type, + this.data, + }); + + factory StringGroupUpdate.fromJson(Map json) => + _$StringGroupUpdateFromJson(json); + + static const toJsonFactory = _$StringGroupUpdateToJson; + Map toJson() => _$StringGroupUpdateToJson(this); + + @JsonKey(name: 'GroupId', includeIfNull: false) + final String? groupId; + @JsonKey( + name: 'Type', + includeIfNull: false, + toJson: groupUpdateTypeNullableToJson, + fromJson: groupUpdateTypeNullableFromJson, + ) + final enums.GroupUpdateType? type; + @JsonKey(name: 'Data', includeIfNull: false) + final String? data; + static const fromJsonFactory = _$StringGroupUpdateFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is StringGroupUpdate && + (identical(other.groupId, groupId) || + const DeepCollectionEquality() + .equals(other.groupId, groupId)) && + (identical(other.type, type) || + const DeepCollectionEquality().equals(other.type, type)) && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(groupId) ^ + const DeepCollectionEquality().hash(type) ^ + const DeepCollectionEquality().hash(data) ^ + runtimeType.hashCode; +} + +extension $StringGroupUpdateExtension on StringGroupUpdate { + StringGroupUpdate copyWith( + {String? groupId, enums.GroupUpdateType? type, String? data}) { + return StringGroupUpdate( + groupId: groupId ?? this.groupId, + type: type ?? this.type, + data: data ?? this.data); + } + + StringGroupUpdate copyWithWrapped( + {Wrapped? groupId, + Wrapped? type, + Wrapped? data}) { + return StringGroupUpdate( + groupId: (groupId != null ? groupId.value : this.groupId), + type: (type != null ? type.value : this.type), + data: (data != null ? data.value : this.data)); + } +} + +@JsonSerializable(explicitToJson: true) +class SubtitleOptions { + const SubtitleOptions({ + this.skipIfEmbeddedSubtitlesPresent, + this.skipIfAudioTrackMatches, + this.downloadLanguages, + this.downloadMovieSubtitles, + this.downloadEpisodeSubtitles, + this.openSubtitlesUsername, + this.openSubtitlesPasswordHash, + this.isOpenSubtitleVipAccount, + this.requirePerfectMatch, + }); + + factory SubtitleOptions.fromJson(Map json) => + _$SubtitleOptionsFromJson(json); + + static const toJsonFactory = _$SubtitleOptionsToJson; + Map toJson() => _$SubtitleOptionsToJson(this); + + @JsonKey(name: 'SkipIfEmbeddedSubtitlesPresent', includeIfNull: false) + final bool? skipIfEmbeddedSubtitlesPresent; + @JsonKey(name: 'SkipIfAudioTrackMatches', includeIfNull: false) + final bool? skipIfAudioTrackMatches; + @JsonKey( + name: 'DownloadLanguages', includeIfNull: false, defaultValue: []) + final List? downloadLanguages; + @JsonKey(name: 'DownloadMovieSubtitles', includeIfNull: false) + final bool? downloadMovieSubtitles; + @JsonKey(name: 'DownloadEpisodeSubtitles', includeIfNull: false) + final bool? downloadEpisodeSubtitles; + @JsonKey(name: 'OpenSubtitlesUsername', includeIfNull: false) + final String? openSubtitlesUsername; + @JsonKey(name: 'OpenSubtitlesPasswordHash', includeIfNull: false) + final String? openSubtitlesPasswordHash; + @JsonKey(name: 'IsOpenSubtitleVipAccount', includeIfNull: false) + final bool? isOpenSubtitleVipAccount; + @JsonKey(name: 'RequirePerfectMatch', includeIfNull: false) + final bool? requirePerfectMatch; + static const fromJsonFactory = _$SubtitleOptionsFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is SubtitleOptions && + (identical(other.skipIfEmbeddedSubtitlesPresent, skipIfEmbeddedSubtitlesPresent) || + const DeepCollectionEquality().equals( + other.skipIfEmbeddedSubtitlesPresent, + skipIfEmbeddedSubtitlesPresent)) && + (identical(other.skipIfAudioTrackMatches, skipIfAudioTrackMatches) || + const DeepCollectionEquality().equals( + other.skipIfAudioTrackMatches, skipIfAudioTrackMatches)) && + (identical(other.downloadLanguages, downloadLanguages) || + const DeepCollectionEquality() + .equals(other.downloadLanguages, downloadLanguages)) && + (identical(other.downloadMovieSubtitles, downloadMovieSubtitles) || + const DeepCollectionEquality().equals( + other.downloadMovieSubtitles, downloadMovieSubtitles)) && + (identical(other.downloadEpisodeSubtitles, downloadEpisodeSubtitles) || + const DeepCollectionEquality().equals( + other.downloadEpisodeSubtitles, + downloadEpisodeSubtitles)) && + (identical(other.openSubtitlesUsername, openSubtitlesUsername) || + const DeepCollectionEquality().equals( + other.openSubtitlesUsername, openSubtitlesUsername)) && + (identical(other.openSubtitlesPasswordHash, openSubtitlesPasswordHash) || + const DeepCollectionEquality().equals( + other.openSubtitlesPasswordHash, + openSubtitlesPasswordHash)) && + (identical(other.isOpenSubtitleVipAccount, isOpenSubtitleVipAccount) || + const DeepCollectionEquality().equals( + other.isOpenSubtitleVipAccount, + isOpenSubtitleVipAccount)) && + (identical(other.requirePerfectMatch, requirePerfectMatch) || + const DeepCollectionEquality() + .equals(other.requirePerfectMatch, requirePerfectMatch))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(skipIfEmbeddedSubtitlesPresent) ^ + const DeepCollectionEquality().hash(skipIfAudioTrackMatches) ^ + const DeepCollectionEquality().hash(downloadLanguages) ^ + const DeepCollectionEquality().hash(downloadMovieSubtitles) ^ + const DeepCollectionEquality().hash(downloadEpisodeSubtitles) ^ + const DeepCollectionEquality().hash(openSubtitlesUsername) ^ + const DeepCollectionEquality().hash(openSubtitlesPasswordHash) ^ + const DeepCollectionEquality().hash(isOpenSubtitleVipAccount) ^ + const DeepCollectionEquality().hash(requirePerfectMatch) ^ + runtimeType.hashCode; +} + +extension $SubtitleOptionsExtension on SubtitleOptions { + SubtitleOptions copyWith( + {bool? skipIfEmbeddedSubtitlesPresent, + bool? skipIfAudioTrackMatches, + List? downloadLanguages, + bool? downloadMovieSubtitles, + bool? downloadEpisodeSubtitles, + String? openSubtitlesUsername, + String? openSubtitlesPasswordHash, + bool? isOpenSubtitleVipAccount, + bool? requirePerfectMatch}) { + return SubtitleOptions( + skipIfEmbeddedSubtitlesPresent: skipIfEmbeddedSubtitlesPresent ?? + this.skipIfEmbeddedSubtitlesPresent, + skipIfAudioTrackMatches: + skipIfAudioTrackMatches ?? this.skipIfAudioTrackMatches, + downloadLanguages: downloadLanguages ?? this.downloadLanguages, + downloadMovieSubtitles: + downloadMovieSubtitles ?? this.downloadMovieSubtitles, + downloadEpisodeSubtitles: + downloadEpisodeSubtitles ?? this.downloadEpisodeSubtitles, + openSubtitlesUsername: + openSubtitlesUsername ?? this.openSubtitlesUsername, + openSubtitlesPasswordHash: + openSubtitlesPasswordHash ?? this.openSubtitlesPasswordHash, + isOpenSubtitleVipAccount: + isOpenSubtitleVipAccount ?? this.isOpenSubtitleVipAccount, + requirePerfectMatch: requirePerfectMatch ?? this.requirePerfectMatch); + } + + SubtitleOptions copyWithWrapped( + {Wrapped? skipIfEmbeddedSubtitlesPresent, + Wrapped? skipIfAudioTrackMatches, + Wrapped?>? downloadLanguages, + Wrapped? downloadMovieSubtitles, + Wrapped? downloadEpisodeSubtitles, + Wrapped? openSubtitlesUsername, + Wrapped? openSubtitlesPasswordHash, + Wrapped? isOpenSubtitleVipAccount, + Wrapped? requirePerfectMatch}) { + return SubtitleOptions( + skipIfEmbeddedSubtitlesPresent: (skipIfEmbeddedSubtitlesPresent != null + ? skipIfEmbeddedSubtitlesPresent.value + : this.skipIfEmbeddedSubtitlesPresent), + skipIfAudioTrackMatches: (skipIfAudioTrackMatches != null + ? skipIfAudioTrackMatches.value + : this.skipIfAudioTrackMatches), + downloadLanguages: (downloadLanguages != null + ? downloadLanguages.value + : this.downloadLanguages), + downloadMovieSubtitles: (downloadMovieSubtitles != null + ? downloadMovieSubtitles.value + : this.downloadMovieSubtitles), + downloadEpisodeSubtitles: (downloadEpisodeSubtitles != null + ? downloadEpisodeSubtitles.value + : this.downloadEpisodeSubtitles), + openSubtitlesUsername: (openSubtitlesUsername != null + ? openSubtitlesUsername.value + : this.openSubtitlesUsername), + openSubtitlesPasswordHash: (openSubtitlesPasswordHash != null + ? openSubtitlesPasswordHash.value + : this.openSubtitlesPasswordHash), + isOpenSubtitleVipAccount: (isOpenSubtitleVipAccount != null + ? isOpenSubtitleVipAccount.value + : this.isOpenSubtitleVipAccount), + requirePerfectMatch: (requirePerfectMatch != null + ? requirePerfectMatch.value + : this.requirePerfectMatch)); + } +} + +@JsonSerializable(explicitToJson: true) +class SubtitleProfile { + const SubtitleProfile({ + this.format, + this.method, + this.didlMode, + this.language, + this.container, + }); + + factory SubtitleProfile.fromJson(Map json) => + _$SubtitleProfileFromJson(json); + + static const toJsonFactory = _$SubtitleProfileToJson; + Map toJson() => _$SubtitleProfileToJson(this); + + @JsonKey(name: 'Format', includeIfNull: false) + final String? format; + @JsonKey( + name: 'Method', + includeIfNull: false, + toJson: subtitleDeliveryMethodNullableToJson, + fromJson: subtitleDeliveryMethodNullableFromJson, + ) + final enums.SubtitleDeliveryMethod? method; + @JsonKey(name: 'DidlMode', includeIfNull: false) + final String? didlMode; + @JsonKey(name: 'Language', includeIfNull: false) + final String? language; + @JsonKey(name: 'Container', includeIfNull: false) + final String? container; + static const fromJsonFactory = _$SubtitleProfileFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is SubtitleProfile && + (identical(other.format, format) || + const DeepCollectionEquality().equals(other.format, format)) && + (identical(other.method, method) || + const DeepCollectionEquality().equals(other.method, method)) && + (identical(other.didlMode, didlMode) || + const DeepCollectionEquality() + .equals(other.didlMode, didlMode)) && + (identical(other.language, language) || + const DeepCollectionEquality() + .equals(other.language, language)) && + (identical(other.container, container) || + const DeepCollectionEquality() + .equals(other.container, container))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(format) ^ + const DeepCollectionEquality().hash(method) ^ + const DeepCollectionEquality().hash(didlMode) ^ + const DeepCollectionEquality().hash(language) ^ + const DeepCollectionEquality().hash(container) ^ + runtimeType.hashCode; +} + +extension $SubtitleProfileExtension on SubtitleProfile { + SubtitleProfile copyWith( + {String? format, + enums.SubtitleDeliveryMethod? method, + String? didlMode, + String? language, + String? container}) { + return SubtitleProfile( + format: format ?? this.format, + method: method ?? this.method, + didlMode: didlMode ?? this.didlMode, + language: language ?? this.language, + container: container ?? this.container); + } + + SubtitleProfile copyWithWrapped( + {Wrapped? format, + Wrapped? method, + Wrapped? didlMode, + Wrapped? language, + Wrapped? container}) { + return SubtitleProfile( + format: (format != null ? format.value : this.format), + method: (method != null ? method.value : this.method), + didlMode: (didlMode != null ? didlMode.value : this.didlMode), + language: (language != null ? language.value : this.language), + container: (container != null ? container.value : this.container)); + } +} + +@JsonSerializable(explicitToJson: true) +class SyncPlayCommandMessage { + const SyncPlayCommandMessage({ + this.data, + this.messageId, + this.messageType, + }); + + factory SyncPlayCommandMessage.fromJson(Map json) => + _$SyncPlayCommandMessageFromJson(json); + + static const toJsonFactory = _$SyncPlayCommandMessageToJson; + Map toJson() => _$SyncPlayCommandMessageToJson(this); + + @JsonKey(name: 'Data', includeIfNull: false) + final SendCommand? data; + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.syncplaycommand); + + static const fromJsonFactory = _$SyncPlayCommandMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is SyncPlayCommandMessage && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data)) && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(data) ^ + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $SyncPlayCommandMessageExtension on SyncPlayCommandMessage { + SyncPlayCommandMessage copyWith( + {SendCommand? data, + String? messageId, + enums.SessionMessageType? messageType}) { + return SyncPlayCommandMessage( + data: data ?? this.data, + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + SyncPlayCommandMessage copyWithWrapped( + {Wrapped? data, + Wrapped? messageId, + Wrapped? messageType}) { + return SyncPlayCommandMessage( + data: (data != null ? data.value : this.data), + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class SyncPlayGroupUpdateCommandMessage { + const SyncPlayGroupUpdateCommandMessage({ + this.data, + this.messageId, + this.messageType, + }); + + factory SyncPlayGroupUpdateCommandMessage.fromJson( + Map json) => + _$SyncPlayGroupUpdateCommandMessageFromJson(json); + + static const toJsonFactory = _$SyncPlayGroupUpdateCommandMessageToJson; + Map toJson() => + _$SyncPlayGroupUpdateCommandMessageToJson(this); + + @JsonKey(name: 'Data', includeIfNull: false) + final GroupUpdate? data; + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.syncplaygroupupdate); + + static const fromJsonFactory = _$SyncPlayGroupUpdateCommandMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is SyncPlayGroupUpdateCommandMessage && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data)) && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(data) ^ + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $SyncPlayGroupUpdateCommandMessageExtension + on SyncPlayGroupUpdateCommandMessage { + SyncPlayGroupUpdateCommandMessage copyWith( + {GroupUpdate? data, + String? messageId, + enums.SessionMessageType? messageType}) { + return SyncPlayGroupUpdateCommandMessage( + data: data ?? this.data, + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + SyncPlayGroupUpdateCommandMessage copyWithWrapped( + {Wrapped? data, + Wrapped? messageId, + Wrapped? messageType}) { + return SyncPlayGroupUpdateCommandMessage( + data: (data != null ? data.value : this.data), + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class SyncPlayQueueItem { + const SyncPlayQueueItem({ + this.itemId, + this.playlistItemId, + }); + + factory SyncPlayQueueItem.fromJson(Map json) => + _$SyncPlayQueueItemFromJson(json); + + static const toJsonFactory = _$SyncPlayQueueItemToJson; + Map toJson() => _$SyncPlayQueueItemToJson(this); + + @JsonKey(name: 'ItemId', includeIfNull: false) + final String? itemId; + @JsonKey(name: 'PlaylistItemId', includeIfNull: false) + final String? playlistItemId; + static const fromJsonFactory = _$SyncPlayQueueItemFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is SyncPlayQueueItem && + (identical(other.itemId, itemId) || + const DeepCollectionEquality().equals(other.itemId, itemId)) && + (identical(other.playlistItemId, playlistItemId) || + const DeepCollectionEquality() + .equals(other.playlistItemId, playlistItemId))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(itemId) ^ + const DeepCollectionEquality().hash(playlistItemId) ^ + runtimeType.hashCode; +} + +extension $SyncPlayQueueItemExtension on SyncPlayQueueItem { + SyncPlayQueueItem copyWith({String? itemId, String? playlistItemId}) { + return SyncPlayQueueItem( + itemId: itemId ?? this.itemId, + playlistItemId: playlistItemId ?? this.playlistItemId); + } + + SyncPlayQueueItem copyWithWrapped( + {Wrapped? itemId, Wrapped? playlistItemId}) { + return SyncPlayQueueItem( + itemId: (itemId != null ? itemId.value : this.itemId), + playlistItemId: (playlistItemId != null + ? playlistItemId.value + : this.playlistItemId)); + } +} + +@JsonSerializable(explicitToJson: true) +class SystemInfo { + const SystemInfo({ + this.localAddress, + this.serverName, + this.version, + this.productName, + this.operatingSystem, + this.id, + this.startupWizardCompleted, + this.operatingSystemDisplayName, + this.packageName, + this.hasPendingRestart, + this.isShuttingDown, + this.supportsLibraryMonitor, + this.webSocketPortNumber, + this.completedInstallations, + this.canSelfRestart, + this.canLaunchWebBrowser, + this.programDataPath, + this.webPath, + this.itemsByNamePath, + this.cachePath, + this.logPath, + this.internalMetadataPath, + this.transcodingTempPath, + this.castReceiverApplications, + this.hasUpdateAvailable, + this.encoderLocation, + this.systemArchitecture, + }); + + factory SystemInfo.fromJson(Map json) => + _$SystemInfoFromJson(json); + + static const toJsonFactory = _$SystemInfoToJson; + Map toJson() => _$SystemInfoToJson(this); + + @JsonKey(name: 'LocalAddress', includeIfNull: false) + final String? localAddress; + @JsonKey(name: 'ServerName', includeIfNull: false) + final String? serverName; + @JsonKey(name: 'Version', includeIfNull: false) + final String? version; + @JsonKey(name: 'ProductName', includeIfNull: false) + final String? productName; + @JsonKey(name: 'OperatingSystem', includeIfNull: false) + @deprecated + final String? operatingSystem; + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'StartupWizardCompleted', includeIfNull: false) + final bool? startupWizardCompleted; + @JsonKey(name: 'OperatingSystemDisplayName', includeIfNull: false) + @deprecated + final String? operatingSystemDisplayName; + @JsonKey(name: 'PackageName', includeIfNull: false) + final String? packageName; + @JsonKey(name: 'HasPendingRestart', includeIfNull: false) + final bool? hasPendingRestart; + @JsonKey(name: 'IsShuttingDown', includeIfNull: false) + final bool? isShuttingDown; + @JsonKey(name: 'SupportsLibraryMonitor', includeIfNull: false) + final bool? supportsLibraryMonitor; + @JsonKey(name: 'WebSocketPortNumber', includeIfNull: false) + final int? webSocketPortNumber; + @JsonKey( + name: 'CompletedInstallations', + includeIfNull: false, + defaultValue: []) + final List? completedInstallations; + @JsonKey(name: 'CanSelfRestart', includeIfNull: false, defaultValue: true) + @deprecated + final bool? canSelfRestart; + @JsonKey( + name: 'CanLaunchWebBrowser', includeIfNull: false, defaultValue: false) + @deprecated + final bool? canLaunchWebBrowser; + @JsonKey(name: 'ProgramDataPath', includeIfNull: false) + final String? programDataPath; + @JsonKey(name: 'WebPath', includeIfNull: false) + final String? webPath; + @JsonKey(name: 'ItemsByNamePath', includeIfNull: false) + final String? itemsByNamePath; + @JsonKey(name: 'CachePath', includeIfNull: false) + final String? cachePath; + @JsonKey(name: 'LogPath', includeIfNull: false) + final String? logPath; + @JsonKey(name: 'InternalMetadataPath', includeIfNull: false) + final String? internalMetadataPath; + @JsonKey(name: 'TranscodingTempPath', includeIfNull: false) + final String? transcodingTempPath; + @JsonKey( + name: 'CastReceiverApplications', + includeIfNull: false, + defaultValue: []) + final List? castReceiverApplications; + @JsonKey( + name: 'HasUpdateAvailable', includeIfNull: false, defaultValue: false) + @deprecated + final bool? hasUpdateAvailable; + @JsonKey(name: 'EncoderLocation', includeIfNull: false) + @deprecated + final String? encoderLocation; + @JsonKey(name: 'SystemArchitecture', includeIfNull: false) + @deprecated + final String? systemArchitecture; + static const fromJsonFactory = _$SystemInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is SystemInfo && + (identical(other.localAddress, localAddress) || + const DeepCollectionEquality() + .equals(other.localAddress, localAddress)) && + (identical(other.serverName, serverName) || + const DeepCollectionEquality() + .equals(other.serverName, serverName)) && + (identical(other.version, version) || + const DeepCollectionEquality() + .equals(other.version, version)) && + (identical(other.productName, productName) || + const DeepCollectionEquality() + .equals(other.productName, productName)) && + (identical(other.operatingSystem, operatingSystem) || + const DeepCollectionEquality() + .equals(other.operatingSystem, operatingSystem)) && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.startupWizardCompleted, startupWizardCompleted) || + const DeepCollectionEquality().equals( + other.startupWizardCompleted, startupWizardCompleted)) && + (identical(other.operatingSystemDisplayName, operatingSystemDisplayName) || + const DeepCollectionEquality().equals( + other.operatingSystemDisplayName, + operatingSystemDisplayName)) && + (identical(other.packageName, packageName) || + const DeepCollectionEquality() + .equals(other.packageName, packageName)) && + (identical(other.hasPendingRestart, hasPendingRestart) || + const DeepCollectionEquality() + .equals(other.hasPendingRestart, hasPendingRestart)) && + (identical(other.isShuttingDown, isShuttingDown) || + const DeepCollectionEquality() + .equals(other.isShuttingDown, isShuttingDown)) && + (identical(other.supportsLibraryMonitor, supportsLibraryMonitor) || + const DeepCollectionEquality().equals( + other.supportsLibraryMonitor, supportsLibraryMonitor)) && + (identical(other.webSocketPortNumber, webSocketPortNumber) || + const DeepCollectionEquality() + .equals(other.webSocketPortNumber, webSocketPortNumber)) && + (identical(other.completedInstallations, completedInstallations) || + const DeepCollectionEquality().equals( + other.completedInstallations, completedInstallations)) && + (identical(other.canSelfRestart, canSelfRestart) || + const DeepCollectionEquality() + .equals(other.canSelfRestart, canSelfRestart)) && + (identical(other.canLaunchWebBrowser, canLaunchWebBrowser) || + const DeepCollectionEquality() + .equals(other.canLaunchWebBrowser, canLaunchWebBrowser)) && + (identical(other.programDataPath, programDataPath) || + const DeepCollectionEquality() + .equals(other.programDataPath, programDataPath)) && + (identical(other.webPath, webPath) || + const DeepCollectionEquality() + .equals(other.webPath, webPath)) && + (identical(other.itemsByNamePath, itemsByNamePath) || const DeepCollectionEquality().equals(other.itemsByNamePath, itemsByNamePath)) && + (identical(other.cachePath, cachePath) || const DeepCollectionEquality().equals(other.cachePath, cachePath)) && + (identical(other.logPath, logPath) || const DeepCollectionEquality().equals(other.logPath, logPath)) && + (identical(other.internalMetadataPath, internalMetadataPath) || const DeepCollectionEquality().equals(other.internalMetadataPath, internalMetadataPath)) && + (identical(other.transcodingTempPath, transcodingTempPath) || const DeepCollectionEquality().equals(other.transcodingTempPath, transcodingTempPath)) && + (identical(other.castReceiverApplications, castReceiverApplications) || const DeepCollectionEquality().equals(other.castReceiverApplications, castReceiverApplications)) && + (identical(other.hasUpdateAvailable, hasUpdateAvailable) || const DeepCollectionEquality().equals(other.hasUpdateAvailable, hasUpdateAvailable)) && + (identical(other.encoderLocation, encoderLocation) || const DeepCollectionEquality().equals(other.encoderLocation, encoderLocation)) && + (identical(other.systemArchitecture, systemArchitecture) || const DeepCollectionEquality().equals(other.systemArchitecture, systemArchitecture))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(localAddress) ^ + const DeepCollectionEquality().hash(serverName) ^ + const DeepCollectionEquality().hash(version) ^ + const DeepCollectionEquality().hash(productName) ^ + const DeepCollectionEquality().hash(operatingSystem) ^ + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(startupWizardCompleted) ^ + const DeepCollectionEquality().hash(operatingSystemDisplayName) ^ + const DeepCollectionEquality().hash(packageName) ^ + const DeepCollectionEquality().hash(hasPendingRestart) ^ + const DeepCollectionEquality().hash(isShuttingDown) ^ + const DeepCollectionEquality().hash(supportsLibraryMonitor) ^ + const DeepCollectionEquality().hash(webSocketPortNumber) ^ + const DeepCollectionEquality().hash(completedInstallations) ^ + const DeepCollectionEquality().hash(canSelfRestart) ^ + const DeepCollectionEquality().hash(canLaunchWebBrowser) ^ + const DeepCollectionEquality().hash(programDataPath) ^ + const DeepCollectionEquality().hash(webPath) ^ + const DeepCollectionEquality().hash(itemsByNamePath) ^ + const DeepCollectionEquality().hash(cachePath) ^ + const DeepCollectionEquality().hash(logPath) ^ + const DeepCollectionEquality().hash(internalMetadataPath) ^ + const DeepCollectionEquality().hash(transcodingTempPath) ^ + const DeepCollectionEquality().hash(castReceiverApplications) ^ + const DeepCollectionEquality().hash(hasUpdateAvailable) ^ + const DeepCollectionEquality().hash(encoderLocation) ^ + const DeepCollectionEquality().hash(systemArchitecture) ^ + runtimeType.hashCode; +} + +extension $SystemInfoExtension on SystemInfo { + SystemInfo copyWith( + {String? localAddress, + String? serverName, + String? version, + String? productName, + String? operatingSystem, + String? id, + bool? startupWizardCompleted, + String? operatingSystemDisplayName, + String? packageName, + bool? hasPendingRestart, + bool? isShuttingDown, + bool? supportsLibraryMonitor, + int? webSocketPortNumber, + List? completedInstallations, + bool? canSelfRestart, + bool? canLaunchWebBrowser, + String? programDataPath, + String? webPath, + String? itemsByNamePath, + String? cachePath, + String? logPath, + String? internalMetadataPath, + String? transcodingTempPath, + List? castReceiverApplications, + bool? hasUpdateAvailable, + String? encoderLocation, + String? systemArchitecture}) { + return SystemInfo( + localAddress: localAddress ?? this.localAddress, + serverName: serverName ?? this.serverName, + version: version ?? this.version, + productName: productName ?? this.productName, + operatingSystem: operatingSystem ?? this.operatingSystem, + id: id ?? this.id, + startupWizardCompleted: + startupWizardCompleted ?? this.startupWizardCompleted, + operatingSystemDisplayName: + operatingSystemDisplayName ?? this.operatingSystemDisplayName, + packageName: packageName ?? this.packageName, + hasPendingRestart: hasPendingRestart ?? this.hasPendingRestart, + isShuttingDown: isShuttingDown ?? this.isShuttingDown, + supportsLibraryMonitor: + supportsLibraryMonitor ?? this.supportsLibraryMonitor, + webSocketPortNumber: webSocketPortNumber ?? this.webSocketPortNumber, + completedInstallations: + completedInstallations ?? this.completedInstallations, + canSelfRestart: canSelfRestart ?? this.canSelfRestart, + canLaunchWebBrowser: canLaunchWebBrowser ?? this.canLaunchWebBrowser, + programDataPath: programDataPath ?? this.programDataPath, + webPath: webPath ?? this.webPath, + itemsByNamePath: itemsByNamePath ?? this.itemsByNamePath, + cachePath: cachePath ?? this.cachePath, + logPath: logPath ?? this.logPath, + internalMetadataPath: internalMetadataPath ?? this.internalMetadataPath, + transcodingTempPath: transcodingTempPath ?? this.transcodingTempPath, + castReceiverApplications: + castReceiverApplications ?? this.castReceiverApplications, + hasUpdateAvailable: hasUpdateAvailable ?? this.hasUpdateAvailable, + encoderLocation: encoderLocation ?? this.encoderLocation, + systemArchitecture: systemArchitecture ?? this.systemArchitecture); + } + + SystemInfo copyWithWrapped( + {Wrapped? localAddress, + Wrapped? serverName, + Wrapped? version, + Wrapped? productName, + Wrapped? operatingSystem, + Wrapped? id, + Wrapped? startupWizardCompleted, + Wrapped? operatingSystemDisplayName, + Wrapped? packageName, + Wrapped? hasPendingRestart, + Wrapped? isShuttingDown, + Wrapped? supportsLibraryMonitor, + Wrapped? webSocketPortNumber, + Wrapped?>? completedInstallations, + Wrapped? canSelfRestart, + Wrapped? canLaunchWebBrowser, + Wrapped? programDataPath, + Wrapped? webPath, + Wrapped? itemsByNamePath, + Wrapped? cachePath, + Wrapped? logPath, + Wrapped? internalMetadataPath, + Wrapped? transcodingTempPath, + Wrapped?>? castReceiverApplications, + Wrapped? hasUpdateAvailable, + Wrapped? encoderLocation, + Wrapped? systemArchitecture}) { + return SystemInfo( + localAddress: + (localAddress != null ? localAddress.value : this.localAddress), + serverName: (serverName != null ? serverName.value : this.serverName), + version: (version != null ? version.value : this.version), + productName: + (productName != null ? productName.value : this.productName), + operatingSystem: (operatingSystem != null + ? operatingSystem.value + : this.operatingSystem), + id: (id != null ? id.value : this.id), + startupWizardCompleted: (startupWizardCompleted != null + ? startupWizardCompleted.value + : this.startupWizardCompleted), + operatingSystemDisplayName: (operatingSystemDisplayName != null + ? operatingSystemDisplayName.value + : this.operatingSystemDisplayName), + packageName: + (packageName != null ? packageName.value : this.packageName), + hasPendingRestart: (hasPendingRestart != null + ? hasPendingRestart.value + : this.hasPendingRestart), + isShuttingDown: (isShuttingDown != null + ? isShuttingDown.value + : this.isShuttingDown), + supportsLibraryMonitor: (supportsLibraryMonitor != null + ? supportsLibraryMonitor.value + : this.supportsLibraryMonitor), + webSocketPortNumber: (webSocketPortNumber != null + ? webSocketPortNumber.value + : this.webSocketPortNumber), + completedInstallations: (completedInstallations != null + ? completedInstallations.value + : this.completedInstallations), + canSelfRestart: (canSelfRestart != null + ? canSelfRestart.value + : this.canSelfRestart), + canLaunchWebBrowser: (canLaunchWebBrowser != null + ? canLaunchWebBrowser.value + : this.canLaunchWebBrowser), + programDataPath: (programDataPath != null + ? programDataPath.value + : this.programDataPath), + webPath: (webPath != null ? webPath.value : this.webPath), + itemsByNamePath: (itemsByNamePath != null + ? itemsByNamePath.value + : this.itemsByNamePath), + cachePath: (cachePath != null ? cachePath.value : this.cachePath), + logPath: (logPath != null ? logPath.value : this.logPath), + internalMetadataPath: (internalMetadataPath != null + ? internalMetadataPath.value + : this.internalMetadataPath), + transcodingTempPath: (transcodingTempPath != null + ? transcodingTempPath.value + : this.transcodingTempPath), + castReceiverApplications: (castReceiverApplications != null + ? castReceiverApplications.value + : this.castReceiverApplications), + hasUpdateAvailable: (hasUpdateAvailable != null + ? hasUpdateAvailable.value + : this.hasUpdateAvailable), + encoderLocation: (encoderLocation != null + ? encoderLocation.value + : this.encoderLocation), + systemArchitecture: (systemArchitecture != null + ? systemArchitecture.value + : this.systemArchitecture)); + } +} + +@JsonSerializable(explicitToJson: true) +class TaskInfo { + const TaskInfo({ + this.name, + this.state, + this.currentProgressPercentage, + this.id, + this.lastExecutionResult, + this.triggers, + this.description, + this.category, + this.isHidden, + this.key, + }); + + factory TaskInfo.fromJson(Map json) => + _$TaskInfoFromJson(json); + + static const toJsonFactory = _$TaskInfoToJson; + Map toJson() => _$TaskInfoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey( + name: 'State', + includeIfNull: false, + toJson: taskStateNullableToJson, + fromJson: taskStateNullableFromJson, + ) + final enums.TaskState? state; + @JsonKey(name: 'CurrentProgressPercentage', includeIfNull: false) + final double? currentProgressPercentage; + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'LastExecutionResult', includeIfNull: false) + final TaskResult? lastExecutionResult; + @JsonKey( + name: 'Triggers', includeIfNull: false, defaultValue: []) + final List? triggers; + @JsonKey(name: 'Description', includeIfNull: false) + final String? description; + @JsonKey(name: 'Category', includeIfNull: false) + final String? category; + @JsonKey(name: 'IsHidden', includeIfNull: false) + final bool? isHidden; + @JsonKey(name: 'Key', includeIfNull: false) + final String? key; + static const fromJsonFactory = _$TaskInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TaskInfo && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.state, state) || + const DeepCollectionEquality().equals(other.state, state)) && + (identical(other.currentProgressPercentage, + currentProgressPercentage) || + const DeepCollectionEquality().equals( + other.currentProgressPercentage, + currentProgressPercentage)) && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.lastExecutionResult, lastExecutionResult) || + const DeepCollectionEquality() + .equals(other.lastExecutionResult, lastExecutionResult)) && + (identical(other.triggers, triggers) || + const DeepCollectionEquality() + .equals(other.triggers, triggers)) && + (identical(other.description, description) || + const DeepCollectionEquality() + .equals(other.description, description)) && + (identical(other.category, category) || + const DeepCollectionEquality() + .equals(other.category, category)) && + (identical(other.isHidden, isHidden) || + const DeepCollectionEquality() + .equals(other.isHidden, isHidden)) && + (identical(other.key, key) || + const DeepCollectionEquality().equals(other.key, key))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(state) ^ + const DeepCollectionEquality().hash(currentProgressPercentage) ^ + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(lastExecutionResult) ^ + const DeepCollectionEquality().hash(triggers) ^ + const DeepCollectionEquality().hash(description) ^ + const DeepCollectionEquality().hash(category) ^ + const DeepCollectionEquality().hash(isHidden) ^ + const DeepCollectionEquality().hash(key) ^ + runtimeType.hashCode; +} + +extension $TaskInfoExtension on TaskInfo { + TaskInfo copyWith( + {String? name, + enums.TaskState? state, + double? currentProgressPercentage, + String? id, + TaskResult? lastExecutionResult, + List? triggers, + String? description, + String? category, + bool? isHidden, + String? key}) { + return TaskInfo( + name: name ?? this.name, + state: state ?? this.state, + currentProgressPercentage: + currentProgressPercentage ?? this.currentProgressPercentage, + id: id ?? this.id, + lastExecutionResult: lastExecutionResult ?? this.lastExecutionResult, + triggers: triggers ?? this.triggers, + description: description ?? this.description, + category: category ?? this.category, + isHidden: isHidden ?? this.isHidden, + key: key ?? this.key); + } + + TaskInfo copyWithWrapped( + {Wrapped? name, + Wrapped? state, + Wrapped? currentProgressPercentage, + Wrapped? id, + Wrapped? lastExecutionResult, + Wrapped?>? triggers, + Wrapped? description, + Wrapped? category, + Wrapped? isHidden, + Wrapped? key}) { + return TaskInfo( + name: (name != null ? name.value : this.name), + state: (state != null ? state.value : this.state), + currentProgressPercentage: (currentProgressPercentage != null + ? currentProgressPercentage.value + : this.currentProgressPercentage), + id: (id != null ? id.value : this.id), + lastExecutionResult: (lastExecutionResult != null + ? lastExecutionResult.value + : this.lastExecutionResult), + triggers: (triggers != null ? triggers.value : this.triggers), + description: + (description != null ? description.value : this.description), + category: (category != null ? category.value : this.category), + isHidden: (isHidden != null ? isHidden.value : this.isHidden), + key: (key != null ? key.value : this.key)); + } +} + +@JsonSerializable(explicitToJson: true) +class TaskResult { + const TaskResult({ + this.startTimeUtc, + this.endTimeUtc, + this.status, + this.name, + this.key, + this.id, + this.errorMessage, + this.longErrorMessage, + }); + + factory TaskResult.fromJson(Map json) => + _$TaskResultFromJson(json); + + static const toJsonFactory = _$TaskResultToJson; + Map toJson() => _$TaskResultToJson(this); + + @JsonKey(name: 'StartTimeUtc', includeIfNull: false) + final DateTime? startTimeUtc; + @JsonKey(name: 'EndTimeUtc', includeIfNull: false) + final DateTime? endTimeUtc; + @JsonKey( + name: 'Status', + includeIfNull: false, + toJson: taskCompletionStatusNullableToJson, + fromJson: taskCompletionStatusNullableFromJson, + ) + final enums.TaskCompletionStatus? status; + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'Key', includeIfNull: false) + final String? key; + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'ErrorMessage', includeIfNull: false) + final String? errorMessage; + @JsonKey(name: 'LongErrorMessage', includeIfNull: false) + final String? longErrorMessage; + static const fromJsonFactory = _$TaskResultFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TaskResult && + (identical(other.startTimeUtc, startTimeUtc) || + const DeepCollectionEquality() + .equals(other.startTimeUtc, startTimeUtc)) && + (identical(other.endTimeUtc, endTimeUtc) || + const DeepCollectionEquality() + .equals(other.endTimeUtc, endTimeUtc)) && + (identical(other.status, status) || + const DeepCollectionEquality().equals(other.status, status)) && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.key, key) || + const DeepCollectionEquality().equals(other.key, key)) && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.errorMessage, errorMessage) || + const DeepCollectionEquality() + .equals(other.errorMessage, errorMessage)) && + (identical(other.longErrorMessage, longErrorMessage) || + const DeepCollectionEquality() + .equals(other.longErrorMessage, longErrorMessage))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(startTimeUtc) ^ + const DeepCollectionEquality().hash(endTimeUtc) ^ + const DeepCollectionEquality().hash(status) ^ + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(key) ^ + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(errorMessage) ^ + const DeepCollectionEquality().hash(longErrorMessage) ^ + runtimeType.hashCode; +} + +extension $TaskResultExtension on TaskResult { + TaskResult copyWith( + {DateTime? startTimeUtc, + DateTime? endTimeUtc, + enums.TaskCompletionStatus? status, + String? name, + String? key, + String? id, + String? errorMessage, + String? longErrorMessage}) { + return TaskResult( + startTimeUtc: startTimeUtc ?? this.startTimeUtc, + endTimeUtc: endTimeUtc ?? this.endTimeUtc, + status: status ?? this.status, + name: name ?? this.name, + key: key ?? this.key, + id: id ?? this.id, + errorMessage: errorMessage ?? this.errorMessage, + longErrorMessage: longErrorMessage ?? this.longErrorMessage); + } + + TaskResult copyWithWrapped( + {Wrapped? startTimeUtc, + Wrapped? endTimeUtc, + Wrapped? status, + Wrapped? name, + Wrapped? key, + Wrapped? id, + Wrapped? errorMessage, + Wrapped? longErrorMessage}) { + return TaskResult( + startTimeUtc: + (startTimeUtc != null ? startTimeUtc.value : this.startTimeUtc), + endTimeUtc: (endTimeUtc != null ? endTimeUtc.value : this.endTimeUtc), + status: (status != null ? status.value : this.status), + name: (name != null ? name.value : this.name), + key: (key != null ? key.value : this.key), + id: (id != null ? id.value : this.id), + errorMessage: + (errorMessage != null ? errorMessage.value : this.errorMessage), + longErrorMessage: (longErrorMessage != null + ? longErrorMessage.value + : this.longErrorMessage)); + } +} + +@JsonSerializable(explicitToJson: true) +class TaskTriggerInfo { + const TaskTriggerInfo({ + this.type, + this.timeOfDayTicks, + this.intervalTicks, + this.dayOfWeek, + this.maxRuntimeTicks, + }); + + factory TaskTriggerInfo.fromJson(Map json) => + _$TaskTriggerInfoFromJson(json); + + static const toJsonFactory = _$TaskTriggerInfoToJson; + Map toJson() => _$TaskTriggerInfoToJson(this); + + @JsonKey(name: 'Type', includeIfNull: false) + final String? type; + @JsonKey(name: 'TimeOfDayTicks', includeIfNull: false) + final int? timeOfDayTicks; + @JsonKey(name: 'IntervalTicks', includeIfNull: false) + final int? intervalTicks; + @JsonKey( + name: 'DayOfWeek', + includeIfNull: false, + toJson: dayOfWeekNullableToJson, + fromJson: dayOfWeekNullableFromJson, + ) + final enums.DayOfWeek? dayOfWeek; + @JsonKey(name: 'MaxRuntimeTicks', includeIfNull: false) + final int? maxRuntimeTicks; + static const fromJsonFactory = _$TaskTriggerInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TaskTriggerInfo && + (identical(other.type, type) || + const DeepCollectionEquality().equals(other.type, type)) && + (identical(other.timeOfDayTicks, timeOfDayTicks) || + const DeepCollectionEquality() + .equals(other.timeOfDayTicks, timeOfDayTicks)) && + (identical(other.intervalTicks, intervalTicks) || + const DeepCollectionEquality() + .equals(other.intervalTicks, intervalTicks)) && + (identical(other.dayOfWeek, dayOfWeek) || + const DeepCollectionEquality() + .equals(other.dayOfWeek, dayOfWeek)) && + (identical(other.maxRuntimeTicks, maxRuntimeTicks) || + const DeepCollectionEquality() + .equals(other.maxRuntimeTicks, maxRuntimeTicks))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(type) ^ + const DeepCollectionEquality().hash(timeOfDayTicks) ^ + const DeepCollectionEquality().hash(intervalTicks) ^ + const DeepCollectionEquality().hash(dayOfWeek) ^ + const DeepCollectionEquality().hash(maxRuntimeTicks) ^ + runtimeType.hashCode; +} + +extension $TaskTriggerInfoExtension on TaskTriggerInfo { + TaskTriggerInfo copyWith( + {String? type, + int? timeOfDayTicks, + int? intervalTicks, + enums.DayOfWeek? dayOfWeek, + int? maxRuntimeTicks}) { + return TaskTriggerInfo( + type: type ?? this.type, + timeOfDayTicks: timeOfDayTicks ?? this.timeOfDayTicks, + intervalTicks: intervalTicks ?? this.intervalTicks, + dayOfWeek: dayOfWeek ?? this.dayOfWeek, + maxRuntimeTicks: maxRuntimeTicks ?? this.maxRuntimeTicks); + } + + TaskTriggerInfo copyWithWrapped( + {Wrapped? type, + Wrapped? timeOfDayTicks, + Wrapped? intervalTicks, + Wrapped? dayOfWeek, + Wrapped? maxRuntimeTicks}) { + return TaskTriggerInfo( + type: (type != null ? type.value : this.type), + timeOfDayTicks: (timeOfDayTicks != null + ? timeOfDayTicks.value + : this.timeOfDayTicks), + intervalTicks: + (intervalTicks != null ? intervalTicks.value : this.intervalTicks), + dayOfWeek: (dayOfWeek != null ? dayOfWeek.value : this.dayOfWeek), + maxRuntimeTicks: (maxRuntimeTicks != null + ? maxRuntimeTicks.value + : this.maxRuntimeTicks)); + } +} + +@JsonSerializable(explicitToJson: true) +class ThemeMediaResult { + const ThemeMediaResult({ + this.items, + this.totalRecordCount, + this.startIndex, + this.ownerId, + }); + + factory ThemeMediaResult.fromJson(Map json) => + _$ThemeMediaResultFromJson(json); + + static const toJsonFactory = _$ThemeMediaResultToJson; + Map toJson() => _$ThemeMediaResultToJson(this); + + @JsonKey(name: 'Items', includeIfNull: false, defaultValue: []) + final List? items; + @JsonKey(name: 'TotalRecordCount', includeIfNull: false) + final int? totalRecordCount; + @JsonKey(name: 'StartIndex', includeIfNull: false) + final int? startIndex; + @JsonKey(name: 'OwnerId', includeIfNull: false) + final String? ownerId; + static const fromJsonFactory = _$ThemeMediaResultFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ThemeMediaResult && + (identical(other.items, items) || + const DeepCollectionEquality().equals(other.items, items)) && + (identical(other.totalRecordCount, totalRecordCount) || + const DeepCollectionEquality() + .equals(other.totalRecordCount, totalRecordCount)) && + (identical(other.startIndex, startIndex) || + const DeepCollectionEquality() + .equals(other.startIndex, startIndex)) && + (identical(other.ownerId, ownerId) || + const DeepCollectionEquality().equals(other.ownerId, ownerId))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(items) ^ + const DeepCollectionEquality().hash(totalRecordCount) ^ + const DeepCollectionEquality().hash(startIndex) ^ + const DeepCollectionEquality().hash(ownerId) ^ + runtimeType.hashCode; +} + +extension $ThemeMediaResultExtension on ThemeMediaResult { + ThemeMediaResult copyWith( + {List? items, + int? totalRecordCount, + int? startIndex, + String? ownerId}) { + return ThemeMediaResult( + items: items ?? this.items, + totalRecordCount: totalRecordCount ?? this.totalRecordCount, + startIndex: startIndex ?? this.startIndex, + ownerId: ownerId ?? this.ownerId); + } + + ThemeMediaResult copyWithWrapped( + {Wrapped?>? items, + Wrapped? totalRecordCount, + Wrapped? startIndex, + Wrapped? ownerId}) { + return ThemeMediaResult( + items: (items != null ? items.value : this.items), + totalRecordCount: (totalRecordCount != null + ? totalRecordCount.value + : this.totalRecordCount), + startIndex: (startIndex != null ? startIndex.value : this.startIndex), + ownerId: (ownerId != null ? ownerId.value : this.ownerId)); + } +} + +@JsonSerializable(explicitToJson: true) +class TimerCancelledMessage { + const TimerCancelledMessage({ + this.data, + this.messageId, + this.messageType, + }); + + factory TimerCancelledMessage.fromJson(Map json) => + _$TimerCancelledMessageFromJson(json); + + static const toJsonFactory = _$TimerCancelledMessageToJson; + Map toJson() => _$TimerCancelledMessageToJson(this); + + @JsonKey(name: 'Data', includeIfNull: false) + final TimerEventInfo? data; + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.timercancelled); + + static const fromJsonFactory = _$TimerCancelledMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TimerCancelledMessage && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data)) && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(data) ^ + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $TimerCancelledMessageExtension on TimerCancelledMessage { + TimerCancelledMessage copyWith( + {TimerEventInfo? data, + String? messageId, + enums.SessionMessageType? messageType}) { + return TimerCancelledMessage( + data: data ?? this.data, + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + TimerCancelledMessage copyWithWrapped( + {Wrapped? data, + Wrapped? messageId, + Wrapped? messageType}) { + return TimerCancelledMessage( + data: (data != null ? data.value : this.data), + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class TimerCreatedMessage { + const TimerCreatedMessage({ + this.data, + this.messageId, + this.messageType, + }); + + factory TimerCreatedMessage.fromJson(Map json) => + _$TimerCreatedMessageFromJson(json); + + static const toJsonFactory = _$TimerCreatedMessageToJson; + Map toJson() => _$TimerCreatedMessageToJson(this); + + @JsonKey(name: 'Data', includeIfNull: false) + final TimerEventInfo? data; + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.timercreated); + + static const fromJsonFactory = _$TimerCreatedMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TimerCreatedMessage && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data)) && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(data) ^ + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $TimerCreatedMessageExtension on TimerCreatedMessage { + TimerCreatedMessage copyWith( + {TimerEventInfo? data, + String? messageId, + enums.SessionMessageType? messageType}) { + return TimerCreatedMessage( + data: data ?? this.data, + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + TimerCreatedMessage copyWithWrapped( + {Wrapped? data, + Wrapped? messageId, + Wrapped? messageType}) { + return TimerCreatedMessage( + data: (data != null ? data.value : this.data), + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class TimerEventInfo { + const TimerEventInfo({ + this.id, + this.programId, + }); + + factory TimerEventInfo.fromJson(Map json) => + _$TimerEventInfoFromJson(json); + + static const toJsonFactory = _$TimerEventInfoToJson; + Map toJson() => _$TimerEventInfoToJson(this); + + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'ProgramId', includeIfNull: false) + final String? programId; + static const fromJsonFactory = _$TimerEventInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TimerEventInfo && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.programId, programId) || + const DeepCollectionEquality() + .equals(other.programId, programId))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(programId) ^ + runtimeType.hashCode; +} + +extension $TimerEventInfoExtension on TimerEventInfo { + TimerEventInfo copyWith({String? id, String? programId}) { + return TimerEventInfo( + id: id ?? this.id, programId: programId ?? this.programId); + } + + TimerEventInfo copyWithWrapped( + {Wrapped? id, Wrapped? programId}) { + return TimerEventInfo( + id: (id != null ? id.value : this.id), + programId: (programId != null ? programId.value : this.programId)); + } +} + +@JsonSerializable(explicitToJson: true) +class TimerInfoDto { + const TimerInfoDto({ + this.id, + this.type, + this.serverId, + this.externalId, + this.channelId, + this.externalChannelId, + this.channelName, + this.channelPrimaryImageTag, + this.programId, + this.externalProgramId, + this.name, + this.overview, + this.startDate, + this.endDate, + this.serviceName, + this.priority, + this.prePaddingSeconds, + this.postPaddingSeconds, + this.isPrePaddingRequired, + this.parentBackdropItemId, + this.parentBackdropImageTags, + this.isPostPaddingRequired, + this.keepUntil, + this.status, + this.seriesTimerId, + this.externalSeriesTimerId, + this.runTimeTicks, + this.programInfo, + }); + + factory TimerInfoDto.fromJson(Map json) => + _$TimerInfoDtoFromJson(json); + + static const toJsonFactory = _$TimerInfoDtoToJson; + Map toJson() => _$TimerInfoDtoToJson(this); + + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'Type', includeIfNull: false) + final String? type; + @JsonKey(name: 'ServerId', includeIfNull: false) + final String? serverId; + @JsonKey(name: 'ExternalId', includeIfNull: false) + final String? externalId; + @JsonKey(name: 'ChannelId', includeIfNull: false) + final String? channelId; + @JsonKey(name: 'ExternalChannelId', includeIfNull: false) + final String? externalChannelId; + @JsonKey(name: 'ChannelName', includeIfNull: false) + final String? channelName; + @JsonKey(name: 'ChannelPrimaryImageTag', includeIfNull: false) + final String? channelPrimaryImageTag; + @JsonKey(name: 'ProgramId', includeIfNull: false) + final String? programId; + @JsonKey(name: 'ExternalProgramId', includeIfNull: false) + final String? externalProgramId; + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'Overview', includeIfNull: false) + final String? overview; + @JsonKey(name: 'StartDate', includeIfNull: false) + final DateTime? startDate; + @JsonKey(name: 'EndDate', includeIfNull: false) + final DateTime? endDate; + @JsonKey(name: 'ServiceName', includeIfNull: false) + final String? serviceName; + @JsonKey(name: 'Priority', includeIfNull: false) + final int? priority; + @JsonKey(name: 'PrePaddingSeconds', includeIfNull: false) + final int? prePaddingSeconds; + @JsonKey(name: 'PostPaddingSeconds', includeIfNull: false) + final int? postPaddingSeconds; + @JsonKey(name: 'IsPrePaddingRequired', includeIfNull: false) + final bool? isPrePaddingRequired; + @JsonKey(name: 'ParentBackdropItemId', includeIfNull: false) + final String? parentBackdropItemId; + @JsonKey( + name: 'ParentBackdropImageTags', + includeIfNull: false, + defaultValue: []) + final List? parentBackdropImageTags; + @JsonKey(name: 'IsPostPaddingRequired', includeIfNull: false) + final bool? isPostPaddingRequired; + @JsonKey( + name: 'KeepUntil', + includeIfNull: false, + toJson: keepUntilNullableToJson, + fromJson: keepUntilNullableFromJson, + ) + final enums.KeepUntil? keepUntil; + @JsonKey( + name: 'Status', + includeIfNull: false, + toJson: recordingStatusNullableToJson, + fromJson: recordingStatusNullableFromJson, + ) + final enums.RecordingStatus? status; + @JsonKey(name: 'SeriesTimerId', includeIfNull: false) + final String? seriesTimerId; + @JsonKey(name: 'ExternalSeriesTimerId', includeIfNull: false) + final String? externalSeriesTimerId; + @JsonKey(name: 'RunTimeTicks', includeIfNull: false) + final int? runTimeTicks; + @JsonKey(name: 'ProgramInfo', includeIfNull: false) + final BaseItemDto? programInfo; + static const fromJsonFactory = _$TimerInfoDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TimerInfoDto && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.type, type) || + const DeepCollectionEquality().equals(other.type, type)) && + (identical(other.serverId, serverId) || + const DeepCollectionEquality() + .equals(other.serverId, serverId)) && + (identical(other.externalId, externalId) || + const DeepCollectionEquality() + .equals(other.externalId, externalId)) && + (identical(other.channelId, channelId) || + const DeepCollectionEquality() + .equals(other.channelId, channelId)) && + (identical(other.externalChannelId, externalChannelId) || + const DeepCollectionEquality() + .equals(other.externalChannelId, externalChannelId)) && + (identical(other.channelName, channelName) || + const DeepCollectionEquality() + .equals(other.channelName, channelName)) && + (identical(other.channelPrimaryImageTag, channelPrimaryImageTag) || + const DeepCollectionEquality().equals( + other.channelPrimaryImageTag, channelPrimaryImageTag)) && + (identical(other.programId, programId) || + const DeepCollectionEquality() + .equals(other.programId, programId)) && + (identical(other.externalProgramId, externalProgramId) || + const DeepCollectionEquality() + .equals(other.externalProgramId, externalProgramId)) && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.overview, overview) || + const DeepCollectionEquality() + .equals(other.overview, overview)) && + (identical(other.startDate, startDate) || + const DeepCollectionEquality() + .equals(other.startDate, startDate)) && + (identical(other.endDate, endDate) || + const DeepCollectionEquality() + .equals(other.endDate, endDate)) && + (identical(other.serviceName, serviceName) || + const DeepCollectionEquality() + .equals(other.serviceName, serviceName)) && + (identical(other.priority, priority) || + const DeepCollectionEquality() + .equals(other.priority, priority)) && + (identical(other.prePaddingSeconds, prePaddingSeconds) || + const DeepCollectionEquality() + .equals(other.prePaddingSeconds, prePaddingSeconds)) && + (identical(other.postPaddingSeconds, postPaddingSeconds) || + const DeepCollectionEquality() + .equals(other.postPaddingSeconds, postPaddingSeconds)) && + (identical(other.isPrePaddingRequired, isPrePaddingRequired) || + const DeepCollectionEquality().equals( + other.isPrePaddingRequired, isPrePaddingRequired)) && + (identical(other.parentBackdropItemId, parentBackdropItemId) || + const DeepCollectionEquality().equals( + other.parentBackdropItemId, parentBackdropItemId)) && + (identical(other.parentBackdropImageTags, parentBackdropImageTags) || + const DeepCollectionEquality().equals( + other.parentBackdropImageTags, parentBackdropImageTags)) && + (identical(other.isPostPaddingRequired, isPostPaddingRequired) || + const DeepCollectionEquality().equals( + other.isPostPaddingRequired, isPostPaddingRequired)) && + (identical(other.keepUntil, keepUntil) || const DeepCollectionEquality().equals(other.keepUntil, keepUntil)) && + (identical(other.status, status) || const DeepCollectionEquality().equals(other.status, status)) && + (identical(other.seriesTimerId, seriesTimerId) || const DeepCollectionEquality().equals(other.seriesTimerId, seriesTimerId)) && + (identical(other.externalSeriesTimerId, externalSeriesTimerId) || const DeepCollectionEquality().equals(other.externalSeriesTimerId, externalSeriesTimerId)) && + (identical(other.runTimeTicks, runTimeTicks) || const DeepCollectionEquality().equals(other.runTimeTicks, runTimeTicks)) && + (identical(other.programInfo, programInfo) || const DeepCollectionEquality().equals(other.programInfo, programInfo))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(type) ^ + const DeepCollectionEquality().hash(serverId) ^ + const DeepCollectionEquality().hash(externalId) ^ + const DeepCollectionEquality().hash(channelId) ^ + const DeepCollectionEquality().hash(externalChannelId) ^ + const DeepCollectionEquality().hash(channelName) ^ + const DeepCollectionEquality().hash(channelPrimaryImageTag) ^ + const DeepCollectionEquality().hash(programId) ^ + const DeepCollectionEquality().hash(externalProgramId) ^ + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(overview) ^ + const DeepCollectionEquality().hash(startDate) ^ + const DeepCollectionEquality().hash(endDate) ^ + const DeepCollectionEquality().hash(serviceName) ^ + const DeepCollectionEquality().hash(priority) ^ + const DeepCollectionEquality().hash(prePaddingSeconds) ^ + const DeepCollectionEquality().hash(postPaddingSeconds) ^ + const DeepCollectionEquality().hash(isPrePaddingRequired) ^ + const DeepCollectionEquality().hash(parentBackdropItemId) ^ + const DeepCollectionEquality().hash(parentBackdropImageTags) ^ + const DeepCollectionEquality().hash(isPostPaddingRequired) ^ + const DeepCollectionEquality().hash(keepUntil) ^ + const DeepCollectionEquality().hash(status) ^ + const DeepCollectionEquality().hash(seriesTimerId) ^ + const DeepCollectionEquality().hash(externalSeriesTimerId) ^ + const DeepCollectionEquality().hash(runTimeTicks) ^ + const DeepCollectionEquality().hash(programInfo) ^ + runtimeType.hashCode; +} + +extension $TimerInfoDtoExtension on TimerInfoDto { + TimerInfoDto copyWith( + {String? id, + String? type, + String? serverId, + String? externalId, + String? channelId, + String? externalChannelId, + String? channelName, + String? channelPrimaryImageTag, + String? programId, + String? externalProgramId, + String? name, + String? overview, + DateTime? startDate, + DateTime? endDate, + String? serviceName, + int? priority, + int? prePaddingSeconds, + int? postPaddingSeconds, + bool? isPrePaddingRequired, + String? parentBackdropItemId, + List? parentBackdropImageTags, + bool? isPostPaddingRequired, + enums.KeepUntil? keepUntil, + enums.RecordingStatus? status, + String? seriesTimerId, + String? externalSeriesTimerId, + int? runTimeTicks, + BaseItemDto? programInfo}) { + return TimerInfoDto( + id: id ?? this.id, + type: type ?? this.type, + serverId: serverId ?? this.serverId, + externalId: externalId ?? this.externalId, + channelId: channelId ?? this.channelId, + externalChannelId: externalChannelId ?? this.externalChannelId, + channelName: channelName ?? this.channelName, + channelPrimaryImageTag: + channelPrimaryImageTag ?? this.channelPrimaryImageTag, + programId: programId ?? this.programId, + externalProgramId: externalProgramId ?? this.externalProgramId, + name: name ?? this.name, + overview: overview ?? this.overview, + startDate: startDate ?? this.startDate, + endDate: endDate ?? this.endDate, + serviceName: serviceName ?? this.serviceName, + priority: priority ?? this.priority, + prePaddingSeconds: prePaddingSeconds ?? this.prePaddingSeconds, + postPaddingSeconds: postPaddingSeconds ?? this.postPaddingSeconds, + isPrePaddingRequired: isPrePaddingRequired ?? this.isPrePaddingRequired, + parentBackdropItemId: parentBackdropItemId ?? this.parentBackdropItemId, + parentBackdropImageTags: + parentBackdropImageTags ?? this.parentBackdropImageTags, + isPostPaddingRequired: + isPostPaddingRequired ?? this.isPostPaddingRequired, + keepUntil: keepUntil ?? this.keepUntil, + status: status ?? this.status, + seriesTimerId: seriesTimerId ?? this.seriesTimerId, + externalSeriesTimerId: + externalSeriesTimerId ?? this.externalSeriesTimerId, + runTimeTicks: runTimeTicks ?? this.runTimeTicks, + programInfo: programInfo ?? this.programInfo); + } + + TimerInfoDto copyWithWrapped( + {Wrapped? id, + Wrapped? type, + Wrapped? serverId, + Wrapped? externalId, + Wrapped? channelId, + Wrapped? externalChannelId, + Wrapped? channelName, + Wrapped? channelPrimaryImageTag, + Wrapped? programId, + Wrapped? externalProgramId, + Wrapped? name, + Wrapped? overview, + Wrapped? startDate, + Wrapped? endDate, + Wrapped? serviceName, + Wrapped? priority, + Wrapped? prePaddingSeconds, + Wrapped? postPaddingSeconds, + Wrapped? isPrePaddingRequired, + Wrapped? parentBackdropItemId, + Wrapped?>? parentBackdropImageTags, + Wrapped? isPostPaddingRequired, + Wrapped? keepUntil, + Wrapped? status, + Wrapped? seriesTimerId, + Wrapped? externalSeriesTimerId, + Wrapped? runTimeTicks, + Wrapped? programInfo}) { + return TimerInfoDto( + id: (id != null ? id.value : this.id), + type: (type != null ? type.value : this.type), + serverId: (serverId != null ? serverId.value : this.serverId), + externalId: (externalId != null ? externalId.value : this.externalId), + channelId: (channelId != null ? channelId.value : this.channelId), + externalChannelId: (externalChannelId != null + ? externalChannelId.value + : this.externalChannelId), + channelName: + (channelName != null ? channelName.value : this.channelName), + channelPrimaryImageTag: (channelPrimaryImageTag != null + ? channelPrimaryImageTag.value + : this.channelPrimaryImageTag), + programId: (programId != null ? programId.value : this.programId), + externalProgramId: (externalProgramId != null + ? externalProgramId.value + : this.externalProgramId), + name: (name != null ? name.value : this.name), + overview: (overview != null ? overview.value : this.overview), + startDate: (startDate != null ? startDate.value : this.startDate), + endDate: (endDate != null ? endDate.value : this.endDate), + serviceName: + (serviceName != null ? serviceName.value : this.serviceName), + priority: (priority != null ? priority.value : this.priority), + prePaddingSeconds: (prePaddingSeconds != null + ? prePaddingSeconds.value + : this.prePaddingSeconds), + postPaddingSeconds: (postPaddingSeconds != null + ? postPaddingSeconds.value + : this.postPaddingSeconds), + isPrePaddingRequired: (isPrePaddingRequired != null + ? isPrePaddingRequired.value + : this.isPrePaddingRequired), + parentBackdropItemId: (parentBackdropItemId != null + ? parentBackdropItemId.value + : this.parentBackdropItemId), + parentBackdropImageTags: (parentBackdropImageTags != null + ? parentBackdropImageTags.value + : this.parentBackdropImageTags), + isPostPaddingRequired: (isPostPaddingRequired != null + ? isPostPaddingRequired.value + : this.isPostPaddingRequired), + keepUntil: (keepUntil != null ? keepUntil.value : this.keepUntil), + status: (status != null ? status.value : this.status), + seriesTimerId: + (seriesTimerId != null ? seriesTimerId.value : this.seriesTimerId), + externalSeriesTimerId: (externalSeriesTimerId != null + ? externalSeriesTimerId.value + : this.externalSeriesTimerId), + runTimeTicks: + (runTimeTicks != null ? runTimeTicks.value : this.runTimeTicks), + programInfo: + (programInfo != null ? programInfo.value : this.programInfo)); + } +} + +@JsonSerializable(explicitToJson: true) +class TimerInfoDtoQueryResult { + const TimerInfoDtoQueryResult({ + this.items, + this.totalRecordCount, + this.startIndex, + }); + + factory TimerInfoDtoQueryResult.fromJson(Map json) => + _$TimerInfoDtoQueryResultFromJson(json); + + static const toJsonFactory = _$TimerInfoDtoQueryResultToJson; + Map toJson() => _$TimerInfoDtoQueryResultToJson(this); + + @JsonKey(name: 'Items', includeIfNull: false, defaultValue: []) + final List? items; + @JsonKey(name: 'TotalRecordCount', includeIfNull: false) + final int? totalRecordCount; + @JsonKey(name: 'StartIndex', includeIfNull: false) + final int? startIndex; + static const fromJsonFactory = _$TimerInfoDtoQueryResultFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TimerInfoDtoQueryResult && + (identical(other.items, items) || + const DeepCollectionEquality().equals(other.items, items)) && + (identical(other.totalRecordCount, totalRecordCount) || + const DeepCollectionEquality() + .equals(other.totalRecordCount, totalRecordCount)) && + (identical(other.startIndex, startIndex) || + const DeepCollectionEquality() + .equals(other.startIndex, startIndex))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(items) ^ + const DeepCollectionEquality().hash(totalRecordCount) ^ + const DeepCollectionEquality().hash(startIndex) ^ + runtimeType.hashCode; +} + +extension $TimerInfoDtoQueryResultExtension on TimerInfoDtoQueryResult { + TimerInfoDtoQueryResult copyWith( + {List? items, int? totalRecordCount, int? startIndex}) { + return TimerInfoDtoQueryResult( + items: items ?? this.items, + totalRecordCount: totalRecordCount ?? this.totalRecordCount, + startIndex: startIndex ?? this.startIndex); + } + + TimerInfoDtoQueryResult copyWithWrapped( + {Wrapped?>? items, + Wrapped? totalRecordCount, + Wrapped? startIndex}) { + return TimerInfoDtoQueryResult( + items: (items != null ? items.value : this.items), + totalRecordCount: (totalRecordCount != null + ? totalRecordCount.value + : this.totalRecordCount), + startIndex: (startIndex != null ? startIndex.value : this.startIndex)); + } +} + +@JsonSerializable(explicitToJson: true) +class TrailerInfo { + const TrailerInfo({ + this.name, + this.originalTitle, + this.path, + this.metadataLanguage, + this.metadataCountryCode, + this.providerIds, + this.year, + this.indexNumber, + this.parentIndexNumber, + this.premiereDate, + this.isAutomated, + }); + + factory TrailerInfo.fromJson(Map json) => + _$TrailerInfoFromJson(json); + + static const toJsonFactory = _$TrailerInfoToJson; + Map toJson() => _$TrailerInfoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'OriginalTitle', includeIfNull: false) + final String? originalTitle; + @JsonKey(name: 'Path', includeIfNull: false) + final String? path; + @JsonKey(name: 'MetadataLanguage', includeIfNull: false) + final String? metadataLanguage; + @JsonKey(name: 'MetadataCountryCode', includeIfNull: false) + final String? metadataCountryCode; + @JsonKey(name: 'ProviderIds', includeIfNull: false) + final Map? providerIds; + @JsonKey(name: 'Year', includeIfNull: false) + final int? year; + @JsonKey(name: 'IndexNumber', includeIfNull: false) + final int? indexNumber; + @JsonKey(name: 'ParentIndexNumber', includeIfNull: false) + final int? parentIndexNumber; + @JsonKey(name: 'PremiereDate', includeIfNull: false) + final DateTime? premiereDate; + @JsonKey(name: 'IsAutomated', includeIfNull: false) + final bool? isAutomated; + static const fromJsonFactory = _$TrailerInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TrailerInfo && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.originalTitle, originalTitle) || + const DeepCollectionEquality() + .equals(other.originalTitle, originalTitle)) && + (identical(other.path, path) || + const DeepCollectionEquality().equals(other.path, path)) && + (identical(other.metadataLanguage, metadataLanguage) || + const DeepCollectionEquality() + .equals(other.metadataLanguage, metadataLanguage)) && + (identical(other.metadataCountryCode, metadataCountryCode) || + const DeepCollectionEquality() + .equals(other.metadataCountryCode, metadataCountryCode)) && + (identical(other.providerIds, providerIds) || + const DeepCollectionEquality() + .equals(other.providerIds, providerIds)) && + (identical(other.year, year) || + const DeepCollectionEquality().equals(other.year, year)) && + (identical(other.indexNumber, indexNumber) || + const DeepCollectionEquality() + .equals(other.indexNumber, indexNumber)) && + (identical(other.parentIndexNumber, parentIndexNumber) || + const DeepCollectionEquality() + .equals(other.parentIndexNumber, parentIndexNumber)) && + (identical(other.premiereDate, premiereDate) || + const DeepCollectionEquality() + .equals(other.premiereDate, premiereDate)) && + (identical(other.isAutomated, isAutomated) || + const DeepCollectionEquality() + .equals(other.isAutomated, isAutomated))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(originalTitle) ^ + const DeepCollectionEquality().hash(path) ^ + const DeepCollectionEquality().hash(metadataLanguage) ^ + const DeepCollectionEquality().hash(metadataCountryCode) ^ + const DeepCollectionEquality().hash(providerIds) ^ + const DeepCollectionEquality().hash(year) ^ + const DeepCollectionEquality().hash(indexNumber) ^ + const DeepCollectionEquality().hash(parentIndexNumber) ^ + const DeepCollectionEquality().hash(premiereDate) ^ + const DeepCollectionEquality().hash(isAutomated) ^ + runtimeType.hashCode; +} + +extension $TrailerInfoExtension on TrailerInfo { + TrailerInfo copyWith( + {String? name, + String? originalTitle, + String? path, + String? metadataLanguage, + String? metadataCountryCode, + Map? providerIds, + int? year, + int? indexNumber, + int? parentIndexNumber, + DateTime? premiereDate, + bool? isAutomated}) { + return TrailerInfo( + name: name ?? this.name, + originalTitle: originalTitle ?? this.originalTitle, + path: path ?? this.path, + metadataLanguage: metadataLanguage ?? this.metadataLanguage, + metadataCountryCode: metadataCountryCode ?? this.metadataCountryCode, + providerIds: providerIds ?? this.providerIds, + year: year ?? this.year, + indexNumber: indexNumber ?? this.indexNumber, + parentIndexNumber: parentIndexNumber ?? this.parentIndexNumber, + premiereDate: premiereDate ?? this.premiereDate, + isAutomated: isAutomated ?? this.isAutomated); + } + + TrailerInfo copyWithWrapped( + {Wrapped? name, + Wrapped? originalTitle, + Wrapped? path, + Wrapped? metadataLanguage, + Wrapped? metadataCountryCode, + Wrapped?>? providerIds, + Wrapped? year, + Wrapped? indexNumber, + Wrapped? parentIndexNumber, + Wrapped? premiereDate, + Wrapped? isAutomated}) { + return TrailerInfo( + name: (name != null ? name.value : this.name), + originalTitle: + (originalTitle != null ? originalTitle.value : this.originalTitle), + path: (path != null ? path.value : this.path), + metadataLanguage: (metadataLanguage != null + ? metadataLanguage.value + : this.metadataLanguage), + metadataCountryCode: (metadataCountryCode != null + ? metadataCountryCode.value + : this.metadataCountryCode), + providerIds: + (providerIds != null ? providerIds.value : this.providerIds), + year: (year != null ? year.value : this.year), + indexNumber: + (indexNumber != null ? indexNumber.value : this.indexNumber), + parentIndexNumber: (parentIndexNumber != null + ? parentIndexNumber.value + : this.parentIndexNumber), + premiereDate: + (premiereDate != null ? premiereDate.value : this.premiereDate), + isAutomated: + (isAutomated != null ? isAutomated.value : this.isAutomated)); + } +} + +@JsonSerializable(explicitToJson: true) +class TrailerInfoRemoteSearchQuery { + const TrailerInfoRemoteSearchQuery({ + this.searchInfo, + this.itemId, + this.searchProviderName, + this.includeDisabledProviders, + }); + + factory TrailerInfoRemoteSearchQuery.fromJson(Map json) => + _$TrailerInfoRemoteSearchQueryFromJson(json); + + static const toJsonFactory = _$TrailerInfoRemoteSearchQueryToJson; + Map toJson() => _$TrailerInfoRemoteSearchQueryToJson(this); + + @JsonKey(name: 'SearchInfo', includeIfNull: false) + final TrailerInfo? searchInfo; + @JsonKey(name: 'ItemId', includeIfNull: false) + final String? itemId; + @JsonKey(name: 'SearchProviderName', includeIfNull: false) + final String? searchProviderName; + @JsonKey(name: 'IncludeDisabledProviders', includeIfNull: false) + final bool? includeDisabledProviders; + static const fromJsonFactory = _$TrailerInfoRemoteSearchQueryFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TrailerInfoRemoteSearchQuery && + (identical(other.searchInfo, searchInfo) || + const DeepCollectionEquality() + .equals(other.searchInfo, searchInfo)) && + (identical(other.itemId, itemId) || + const DeepCollectionEquality().equals(other.itemId, itemId)) && + (identical(other.searchProviderName, searchProviderName) || + const DeepCollectionEquality() + .equals(other.searchProviderName, searchProviderName)) && + (identical( + other.includeDisabledProviders, includeDisabledProviders) || + const DeepCollectionEquality().equals( + other.includeDisabledProviders, includeDisabledProviders))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(searchInfo) ^ + const DeepCollectionEquality().hash(itemId) ^ + const DeepCollectionEquality().hash(searchProviderName) ^ + const DeepCollectionEquality().hash(includeDisabledProviders) ^ + runtimeType.hashCode; +} + +extension $TrailerInfoRemoteSearchQueryExtension + on TrailerInfoRemoteSearchQuery { + TrailerInfoRemoteSearchQuery copyWith( + {TrailerInfo? searchInfo, + String? itemId, + String? searchProviderName, + bool? includeDisabledProviders}) { + return TrailerInfoRemoteSearchQuery( + searchInfo: searchInfo ?? this.searchInfo, + itemId: itemId ?? this.itemId, + searchProviderName: searchProviderName ?? this.searchProviderName, + includeDisabledProviders: + includeDisabledProviders ?? this.includeDisabledProviders); + } + + TrailerInfoRemoteSearchQuery copyWithWrapped( + {Wrapped? searchInfo, + Wrapped? itemId, + Wrapped? searchProviderName, + Wrapped? includeDisabledProviders}) { + return TrailerInfoRemoteSearchQuery( + searchInfo: (searchInfo != null ? searchInfo.value : this.searchInfo), + itemId: (itemId != null ? itemId.value : this.itemId), + searchProviderName: (searchProviderName != null + ? searchProviderName.value + : this.searchProviderName), + includeDisabledProviders: (includeDisabledProviders != null + ? includeDisabledProviders.value + : this.includeDisabledProviders)); + } +} + +@JsonSerializable(explicitToJson: true) +class TraktEpisode { + const TraktEpisode({ + this.season, + this.number, + this.title, + this.ids, + }); + + factory TraktEpisode.fromJson(Map json) => + _$TraktEpisodeFromJson(json); + + static const toJsonFactory = _$TraktEpisodeToJson; + Map toJson() => _$TraktEpisodeToJson(this); + + @JsonKey(name: 'season', includeIfNull: false) + final int? season; + @JsonKey(name: 'number', includeIfNull: false) + final int? number; + @JsonKey(name: 'title', includeIfNull: false) + final String? title; + @JsonKey(name: 'ids', includeIfNull: false) + final TraktEpisodeId? ids; + static const fromJsonFactory = _$TraktEpisodeFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TraktEpisode && + (identical(other.season, season) || + const DeepCollectionEquality().equals(other.season, season)) && + (identical(other.number, number) || + const DeepCollectionEquality().equals(other.number, number)) && + (identical(other.title, title) || + const DeepCollectionEquality().equals(other.title, title)) && + (identical(other.ids, ids) || + const DeepCollectionEquality().equals(other.ids, ids))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(season) ^ + const DeepCollectionEquality().hash(number) ^ + const DeepCollectionEquality().hash(title) ^ + const DeepCollectionEquality().hash(ids) ^ + runtimeType.hashCode; +} + +extension $TraktEpisodeExtension on TraktEpisode { + TraktEpisode copyWith( + {int? season, int? number, String? title, TraktEpisodeId? ids}) { + return TraktEpisode( + season: season ?? this.season, + number: number ?? this.number, + title: title ?? this.title, + ids: ids ?? this.ids); + } + + TraktEpisode copyWithWrapped( + {Wrapped? season, + Wrapped? number, + Wrapped? title, + Wrapped? ids}) { + return TraktEpisode( + season: (season != null ? season.value : this.season), + number: (number != null ? number.value : this.number), + title: (title != null ? title.value : this.title), + ids: (ids != null ? ids.value : this.ids)); + } +} + +@JsonSerializable(explicitToJson: true) +class TraktEpisodeId { + const TraktEpisodeId({ + this.trakt, + this.slug, + this.imdb, + this.tmdb, + this.tvdb, + this.tvrage, + }); + + factory TraktEpisodeId.fromJson(Map json) => + _$TraktEpisodeIdFromJson(json); + + static const toJsonFactory = _$TraktEpisodeIdToJson; + Map toJson() => _$TraktEpisodeIdToJson(this); + + @JsonKey(name: 'trakt', includeIfNull: false) + final int? trakt; + @JsonKey(name: 'slug', includeIfNull: false) + final String? slug; + @JsonKey(name: 'imdb', includeIfNull: false) + final String? imdb; + @JsonKey(name: 'tmdb', includeIfNull: false) + final int? tmdb; + @JsonKey(name: 'tvdb', includeIfNull: false) + final String? tvdb; + @JsonKey(name: 'tvrage', includeIfNull: false) + final String? tvrage; + static const fromJsonFactory = _$TraktEpisodeIdFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TraktEpisodeId && + (identical(other.trakt, trakt) || + const DeepCollectionEquality().equals(other.trakt, trakt)) && + (identical(other.slug, slug) || + const DeepCollectionEquality().equals(other.slug, slug)) && + (identical(other.imdb, imdb) || + const DeepCollectionEquality().equals(other.imdb, imdb)) && + (identical(other.tmdb, tmdb) || + const DeepCollectionEquality().equals(other.tmdb, tmdb)) && + (identical(other.tvdb, tvdb) || + const DeepCollectionEquality().equals(other.tvdb, tvdb)) && + (identical(other.tvrage, tvrage) || + const DeepCollectionEquality().equals(other.tvrage, tvrage))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(trakt) ^ + const DeepCollectionEquality().hash(slug) ^ + const DeepCollectionEquality().hash(imdb) ^ + const DeepCollectionEquality().hash(tmdb) ^ + const DeepCollectionEquality().hash(tvdb) ^ + const DeepCollectionEquality().hash(tvrage) ^ + runtimeType.hashCode; +} + +extension $TraktEpisodeIdExtension on TraktEpisodeId { + TraktEpisodeId copyWith( + {int? trakt, + String? slug, + String? imdb, + int? tmdb, + String? tvdb, + String? tvrage}) { + return TraktEpisodeId( + trakt: trakt ?? this.trakt, + slug: slug ?? this.slug, + imdb: imdb ?? this.imdb, + tmdb: tmdb ?? this.tmdb, + tvdb: tvdb ?? this.tvdb, + tvrage: tvrage ?? this.tvrage); + } + + TraktEpisodeId copyWithWrapped( + {Wrapped? trakt, + Wrapped? slug, + Wrapped? imdb, + Wrapped? tmdb, + Wrapped? tvdb, + Wrapped? tvrage}) { + return TraktEpisodeId( + trakt: (trakt != null ? trakt.value : this.trakt), + slug: (slug != null ? slug.value : this.slug), + imdb: (imdb != null ? imdb.value : this.imdb), + tmdb: (tmdb != null ? tmdb.value : this.tmdb), + tvdb: (tvdb != null ? tvdb.value : this.tvdb), + tvrage: (tvrage != null ? tvrage.value : this.tvrage)); + } +} + +@JsonSerializable(explicitToJson: true) +class TraktMovie { + const TraktMovie({ + this.title, + this.year, + this.ids, + }); + + factory TraktMovie.fromJson(Map json) => + _$TraktMovieFromJson(json); + + static const toJsonFactory = _$TraktMovieToJson; + Map toJson() => _$TraktMovieToJson(this); + + @JsonKey(name: 'title', includeIfNull: false) + final String? title; + @JsonKey(name: 'year', includeIfNull: false) + final int? year; + @JsonKey(name: 'ids', includeIfNull: false) + final TraktMovieId? ids; + static const fromJsonFactory = _$TraktMovieFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TraktMovie && + (identical(other.title, title) || + const DeepCollectionEquality().equals(other.title, title)) && + (identical(other.year, year) || + const DeepCollectionEquality().equals(other.year, year)) && + (identical(other.ids, ids) || + const DeepCollectionEquality().equals(other.ids, ids))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(title) ^ + const DeepCollectionEquality().hash(year) ^ + const DeepCollectionEquality().hash(ids) ^ + runtimeType.hashCode; +} + +extension $TraktMovieExtension on TraktMovie { + TraktMovie copyWith({String? title, int? year, TraktMovieId? ids}) { + return TraktMovie( + title: title ?? this.title, + year: year ?? this.year, + ids: ids ?? this.ids); + } + + TraktMovie copyWithWrapped( + {Wrapped? title, + Wrapped? year, + Wrapped? ids}) { + return TraktMovie( + title: (title != null ? title.value : this.title), + year: (year != null ? year.value : this.year), + ids: (ids != null ? ids.value : this.ids)); + } +} + +@JsonSerializable(explicitToJson: true) +class TraktMovieId { + const TraktMovieId({ + this.trakt, + this.slug, + this.imdb, + this.tmdb, + }); + + factory TraktMovieId.fromJson(Map json) => + _$TraktMovieIdFromJson(json); + + static const toJsonFactory = _$TraktMovieIdToJson; + Map toJson() => _$TraktMovieIdToJson(this); + + @JsonKey(name: 'trakt', includeIfNull: false) + final int? trakt; + @JsonKey(name: 'slug', includeIfNull: false) + final String? slug; + @JsonKey(name: 'imdb', includeIfNull: false) + final String? imdb; + @JsonKey(name: 'tmdb', includeIfNull: false) + final int? tmdb; + static const fromJsonFactory = _$TraktMovieIdFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TraktMovieId && + (identical(other.trakt, trakt) || + const DeepCollectionEquality().equals(other.trakt, trakt)) && + (identical(other.slug, slug) || + const DeepCollectionEquality().equals(other.slug, slug)) && + (identical(other.imdb, imdb) || + const DeepCollectionEquality().equals(other.imdb, imdb)) && + (identical(other.tmdb, tmdb) || + const DeepCollectionEquality().equals(other.tmdb, tmdb))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(trakt) ^ + const DeepCollectionEquality().hash(slug) ^ + const DeepCollectionEquality().hash(imdb) ^ + const DeepCollectionEquality().hash(tmdb) ^ + runtimeType.hashCode; +} + +extension $TraktMovieIdExtension on TraktMovieId { + TraktMovieId copyWith({int? trakt, String? slug, String? imdb, int? tmdb}) { + return TraktMovieId( + trakt: trakt ?? this.trakt, + slug: slug ?? this.slug, + imdb: imdb ?? this.imdb, + tmdb: tmdb ?? this.tmdb); + } + + TraktMovieId copyWithWrapped( + {Wrapped? trakt, + Wrapped? slug, + Wrapped? imdb, + Wrapped? tmdb}) { + return TraktMovieId( + trakt: (trakt != null ? trakt.value : this.trakt), + slug: (slug != null ? slug.value : this.slug), + imdb: (imdb != null ? imdb.value : this.imdb), + tmdb: (tmdb != null ? tmdb.value : this.tmdb)); + } +} + +@JsonSerializable(explicitToJson: true) +class TraktPerson { + const TraktPerson({ + this.name, + this.ids, + }); + + factory TraktPerson.fromJson(Map json) => + _$TraktPersonFromJson(json); + + static const toJsonFactory = _$TraktPersonToJson; + Map toJson() => _$TraktPersonToJson(this); + + @JsonKey(name: 'name', includeIfNull: false) + final String? name; + @JsonKey(name: 'ids', includeIfNull: false) + final TraktPersonId? ids; + static const fromJsonFactory = _$TraktPersonFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TraktPerson && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.ids, ids) || + const DeepCollectionEquality().equals(other.ids, ids))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(ids) ^ + runtimeType.hashCode; +} + +extension $TraktPersonExtension on TraktPerson { + TraktPerson copyWith({String? name, TraktPersonId? ids}) { + return TraktPerson(name: name ?? this.name, ids: ids ?? this.ids); + } + + TraktPerson copyWithWrapped( + {Wrapped? name, Wrapped? ids}) { + return TraktPerson( + name: (name != null ? name.value : this.name), + ids: (ids != null ? ids.value : this.ids)); + } +} + +@JsonSerializable(explicitToJson: true) +class TraktPersonId { + const TraktPersonId({ + this.trakt, + this.slug, + this.imdb, + this.tmdb, + this.tvrage, + }); + + factory TraktPersonId.fromJson(Map json) => + _$TraktPersonIdFromJson(json); + + static const toJsonFactory = _$TraktPersonIdToJson; + Map toJson() => _$TraktPersonIdToJson(this); + + @JsonKey(name: 'trakt', includeIfNull: false) + final int? trakt; + @JsonKey(name: 'slug', includeIfNull: false) + final String? slug; + @JsonKey(name: 'imdb', includeIfNull: false) + final String? imdb; + @JsonKey(name: 'tmdb', includeIfNull: false) + final int? tmdb; + @JsonKey(name: 'tvrage', includeIfNull: false) + final int? tvrage; + static const fromJsonFactory = _$TraktPersonIdFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TraktPersonId && + (identical(other.trakt, trakt) || + const DeepCollectionEquality().equals(other.trakt, trakt)) && + (identical(other.slug, slug) || + const DeepCollectionEquality().equals(other.slug, slug)) && + (identical(other.imdb, imdb) || + const DeepCollectionEquality().equals(other.imdb, imdb)) && + (identical(other.tmdb, tmdb) || + const DeepCollectionEquality().equals(other.tmdb, tmdb)) && + (identical(other.tvrage, tvrage) || + const DeepCollectionEquality().equals(other.tvrage, tvrage))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(trakt) ^ + const DeepCollectionEquality().hash(slug) ^ + const DeepCollectionEquality().hash(imdb) ^ + const DeepCollectionEquality().hash(tmdb) ^ + const DeepCollectionEquality().hash(tvrage) ^ + runtimeType.hashCode; +} + +extension $TraktPersonIdExtension on TraktPersonId { + TraktPersonId copyWith( + {int? trakt, String? slug, String? imdb, int? tmdb, int? tvrage}) { + return TraktPersonId( + trakt: trakt ?? this.trakt, + slug: slug ?? this.slug, + imdb: imdb ?? this.imdb, + tmdb: tmdb ?? this.tmdb, + tvrage: tvrage ?? this.tvrage); + } + + TraktPersonId copyWithWrapped( + {Wrapped? trakt, + Wrapped? slug, + Wrapped? imdb, + Wrapped? tmdb, + Wrapped? tvrage}) { + return TraktPersonId( + trakt: (trakt != null ? trakt.value : this.trakt), + slug: (slug != null ? slug.value : this.slug), + imdb: (imdb != null ? imdb.value : this.imdb), + tmdb: (tmdb != null ? tmdb.value : this.tmdb), + tvrage: (tvrage != null ? tvrage.value : this.tvrage)); + } +} + +@JsonSerializable(explicitToJson: true) +class TraktSeason { + const TraktSeason({ + this.number, + this.ids, + }); + + factory TraktSeason.fromJson(Map json) => + _$TraktSeasonFromJson(json); + + static const toJsonFactory = _$TraktSeasonToJson; + Map toJson() => _$TraktSeasonToJson(this); + + @JsonKey(name: 'number', includeIfNull: false) + final int? number; + @JsonKey(name: 'ids', includeIfNull: false) + final TraktSeasonId? ids; + static const fromJsonFactory = _$TraktSeasonFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TraktSeason && + (identical(other.number, number) || + const DeepCollectionEquality().equals(other.number, number)) && + (identical(other.ids, ids) || + const DeepCollectionEquality().equals(other.ids, ids))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(number) ^ + const DeepCollectionEquality().hash(ids) ^ + runtimeType.hashCode; +} + +extension $TraktSeasonExtension on TraktSeason { + TraktSeason copyWith({int? number, TraktSeasonId? ids}) { + return TraktSeason(number: number ?? this.number, ids: ids ?? this.ids); + } + + TraktSeason copyWithWrapped( + {Wrapped? number, Wrapped? ids}) { + return TraktSeason( + number: (number != null ? number.value : this.number), + ids: (ids != null ? ids.value : this.ids)); + } +} + +@JsonSerializable(explicitToJson: true) +class TraktSeasonId { + const TraktSeasonId({ + this.trakt, + this.slug, + this.tmdb, + this.tvdb, + this.tvrage, + }); + + factory TraktSeasonId.fromJson(Map json) => + _$TraktSeasonIdFromJson(json); + + static const toJsonFactory = _$TraktSeasonIdToJson; + Map toJson() => _$TraktSeasonIdToJson(this); + + @JsonKey(name: 'trakt', includeIfNull: false) + final int? trakt; + @JsonKey(name: 'slug', includeIfNull: false) + final String? slug; + @JsonKey(name: 'tmdb', includeIfNull: false) + final int? tmdb; + @JsonKey(name: 'tvdb', includeIfNull: false) + final int? tvdb; + @JsonKey(name: 'tvrage', includeIfNull: false) + final int? tvrage; + static const fromJsonFactory = _$TraktSeasonIdFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TraktSeasonId && + (identical(other.trakt, trakt) || + const DeepCollectionEquality().equals(other.trakt, trakt)) && + (identical(other.slug, slug) || + const DeepCollectionEquality().equals(other.slug, slug)) && + (identical(other.tmdb, tmdb) || + const DeepCollectionEquality().equals(other.tmdb, tmdb)) && + (identical(other.tvdb, tvdb) || + const DeepCollectionEquality().equals(other.tvdb, tvdb)) && + (identical(other.tvrage, tvrage) || + const DeepCollectionEquality().equals(other.tvrage, tvrage))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(trakt) ^ + const DeepCollectionEquality().hash(slug) ^ + const DeepCollectionEquality().hash(tmdb) ^ + const DeepCollectionEquality().hash(tvdb) ^ + const DeepCollectionEquality().hash(tvrage) ^ + runtimeType.hashCode; +} + +extension $TraktSeasonIdExtension on TraktSeasonId { + TraktSeasonId copyWith( + {int? trakt, String? slug, int? tmdb, int? tvdb, int? tvrage}) { + return TraktSeasonId( + trakt: trakt ?? this.trakt, + slug: slug ?? this.slug, + tmdb: tmdb ?? this.tmdb, + tvdb: tvdb ?? this.tvdb, + tvrage: tvrage ?? this.tvrage); + } + + TraktSeasonId copyWithWrapped( + {Wrapped? trakt, + Wrapped? slug, + Wrapped? tmdb, + Wrapped? tvdb, + Wrapped? tvrage}) { + return TraktSeasonId( + trakt: (trakt != null ? trakt.value : this.trakt), + slug: (slug != null ? slug.value : this.slug), + tmdb: (tmdb != null ? tmdb.value : this.tmdb), + tvdb: (tvdb != null ? tvdb.value : this.tvdb), + tvrage: (tvrage != null ? tvrage.value : this.tvrage)); + } +} + +@JsonSerializable(explicitToJson: true) +class TraktShow { + const TraktShow({ + this.title, + this.year, + this.ids, + }); + + factory TraktShow.fromJson(Map json) => + _$TraktShowFromJson(json); + + static const toJsonFactory = _$TraktShowToJson; + Map toJson() => _$TraktShowToJson(this); + + @JsonKey(name: 'title', includeIfNull: false) + final String? title; + @JsonKey(name: 'year', includeIfNull: false) + final int? year; + @JsonKey(name: 'ids', includeIfNull: false) + final TraktShowId? ids; + static const fromJsonFactory = _$TraktShowFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TraktShow && + (identical(other.title, title) || + const DeepCollectionEquality().equals(other.title, title)) && + (identical(other.year, year) || + const DeepCollectionEquality().equals(other.year, year)) && + (identical(other.ids, ids) || + const DeepCollectionEquality().equals(other.ids, ids))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(title) ^ + const DeepCollectionEquality().hash(year) ^ + const DeepCollectionEquality().hash(ids) ^ + runtimeType.hashCode; +} + +extension $TraktShowExtension on TraktShow { + TraktShow copyWith({String? title, int? year, TraktShowId? ids}) { + return TraktShow( + title: title ?? this.title, + year: year ?? this.year, + ids: ids ?? this.ids); + } + + TraktShow copyWithWrapped( + {Wrapped? title, + Wrapped? year, + Wrapped? ids}) { + return TraktShow( + title: (title != null ? title.value : this.title), + year: (year != null ? year.value : this.year), + ids: (ids != null ? ids.value : this.ids)); + } +} + +@JsonSerializable(explicitToJson: true) +class TraktShowId { + const TraktShowId({ + this.trakt, + this.slug, + this.imdb, + this.tmdb, + this.tvdb, + this.tvrage, + }); + + factory TraktShowId.fromJson(Map json) => + _$TraktShowIdFromJson(json); + + static const toJsonFactory = _$TraktShowIdToJson; + Map toJson() => _$TraktShowIdToJson(this); + + @JsonKey(name: 'trakt', includeIfNull: false) + final int? trakt; + @JsonKey(name: 'slug', includeIfNull: false) + final String? slug; + @JsonKey(name: 'imdb', includeIfNull: false) + final String? imdb; + @JsonKey(name: 'tmdb', includeIfNull: false) + final int? tmdb; + @JsonKey(name: 'tvdb', includeIfNull: false) + final String? tvdb; + @JsonKey(name: 'tvrage', includeIfNull: false) + final String? tvrage; + static const fromJsonFactory = _$TraktShowIdFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TraktShowId && + (identical(other.trakt, trakt) || + const DeepCollectionEquality().equals(other.trakt, trakt)) && + (identical(other.slug, slug) || + const DeepCollectionEquality().equals(other.slug, slug)) && + (identical(other.imdb, imdb) || + const DeepCollectionEquality().equals(other.imdb, imdb)) && + (identical(other.tmdb, tmdb) || + const DeepCollectionEquality().equals(other.tmdb, tmdb)) && + (identical(other.tvdb, tvdb) || + const DeepCollectionEquality().equals(other.tvdb, tvdb)) && + (identical(other.tvrage, tvrage) || + const DeepCollectionEquality().equals(other.tvrage, tvrage))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(trakt) ^ + const DeepCollectionEquality().hash(slug) ^ + const DeepCollectionEquality().hash(imdb) ^ + const DeepCollectionEquality().hash(tmdb) ^ + const DeepCollectionEquality().hash(tvdb) ^ + const DeepCollectionEquality().hash(tvrage) ^ + runtimeType.hashCode; +} + +extension $TraktShowIdExtension on TraktShowId { + TraktShowId copyWith( + {int? trakt, + String? slug, + String? imdb, + int? tmdb, + String? tvdb, + String? tvrage}) { + return TraktShowId( + trakt: trakt ?? this.trakt, + slug: slug ?? this.slug, + imdb: imdb ?? this.imdb, + tmdb: tmdb ?? this.tmdb, + tvdb: tvdb ?? this.tvdb, + tvrage: tvrage ?? this.tvrage); + } + + TraktShowId copyWithWrapped( + {Wrapped? trakt, + Wrapped? slug, + Wrapped? imdb, + Wrapped? tmdb, + Wrapped? tvdb, + Wrapped? tvrage}) { + return TraktShowId( + trakt: (trakt != null ? trakt.value : this.trakt), + slug: (slug != null ? slug.value : this.slug), + imdb: (imdb != null ? imdb.value : this.imdb), + tmdb: (tmdb != null ? tmdb.value : this.tmdb), + tvdb: (tvdb != null ? tvdb.value : this.tvdb), + tvrage: (tvrage != null ? tvrage.value : this.tvrage)); + } +} + +@JsonSerializable(explicitToJson: true) +class TraktSyncResponse { + const TraktSyncResponse({ + this.added, + this.deleted, + this.updated, + this.notFound, + }); + + factory TraktSyncResponse.fromJson(Map json) => + _$TraktSyncResponseFromJson(json); + + static const toJsonFactory = _$TraktSyncResponseToJson; + Map toJson() => _$TraktSyncResponseToJson(this); + + @JsonKey(name: 'added', includeIfNull: false) + final Items? added; + @JsonKey(name: 'deleted', includeIfNull: false) + final Items? deleted; + @JsonKey(name: 'updated', includeIfNull: false) + final Items? updated; + @JsonKey(name: 'not_found', includeIfNull: false) + final NotFoundObjects? notFound; + static const fromJsonFactory = _$TraktSyncResponseFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TraktSyncResponse && + (identical(other.added, added) || + const DeepCollectionEquality().equals(other.added, added)) && + (identical(other.deleted, deleted) || + const DeepCollectionEquality() + .equals(other.deleted, deleted)) && + (identical(other.updated, updated) || + const DeepCollectionEquality() + .equals(other.updated, updated)) && + (identical(other.notFound, notFound) || + const DeepCollectionEquality() + .equals(other.notFound, notFound))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(added) ^ + const DeepCollectionEquality().hash(deleted) ^ + const DeepCollectionEquality().hash(updated) ^ + const DeepCollectionEquality().hash(notFound) ^ + runtimeType.hashCode; +} + +extension $TraktSyncResponseExtension on TraktSyncResponse { + TraktSyncResponse copyWith( + {Items? added, + Items? deleted, + Items? updated, + NotFoundObjects? notFound}) { + return TraktSyncResponse( + added: added ?? this.added, + deleted: deleted ?? this.deleted, + updated: updated ?? this.updated, + notFound: notFound ?? this.notFound); + } + + TraktSyncResponse copyWithWrapped( + {Wrapped? added, + Wrapped? deleted, + Wrapped? updated, + Wrapped? notFound}) { + return TraktSyncResponse( + added: (added != null ? added.value : this.added), + deleted: (deleted != null ? deleted.value : this.deleted), + updated: (updated != null ? updated.value : this.updated), + notFound: (notFound != null ? notFound.value : this.notFound)); + } +} + +@JsonSerializable(explicitToJson: true) +class TranscodingInfo { + const TranscodingInfo({ + this.audioCodec, + this.videoCodec, + this.container, + this.isVideoDirect, + this.isAudioDirect, + this.bitrate, + this.framerate, + this.completionPercentage, + this.width, + this.height, + this.audioChannels, + this.hardwareAccelerationType, + this.transcodeReasons, + }); + + factory TranscodingInfo.fromJson(Map json) => + _$TranscodingInfoFromJson(json); + + static const toJsonFactory = _$TranscodingInfoToJson; + Map toJson() => _$TranscodingInfoToJson(this); + + @JsonKey(name: 'AudioCodec', includeIfNull: false) + final String? audioCodec; + @JsonKey(name: 'VideoCodec', includeIfNull: false) + final String? videoCodec; + @JsonKey(name: 'Container', includeIfNull: false) + final String? container; + @JsonKey(name: 'IsVideoDirect', includeIfNull: false) + final bool? isVideoDirect; + @JsonKey(name: 'IsAudioDirect', includeIfNull: false) + final bool? isAudioDirect; + @JsonKey(name: 'Bitrate', includeIfNull: false) + final int? bitrate; + @JsonKey(name: 'Framerate', includeIfNull: false) + final double? framerate; + @JsonKey(name: 'CompletionPercentage', includeIfNull: false) + final double? completionPercentage; + @JsonKey(name: 'Width', includeIfNull: false) + final int? width; + @JsonKey(name: 'Height', includeIfNull: false) + final int? height; + @JsonKey(name: 'AudioChannels', includeIfNull: false) + final int? audioChannels; + @JsonKey( + name: 'HardwareAccelerationType', + includeIfNull: false, + toJson: hardwareEncodingTypeNullableToJson, + fromJson: hardwareEncodingTypeNullableFromJson, + ) + final enums.HardwareEncodingType? hardwareAccelerationType; + @JsonKey( + name: 'TranscodeReasons', + includeIfNull: false, + toJson: transcodeReasonListToJson, + fromJson: transcodeReasonListFromJson, + ) + final List? transcodeReasons; + static const fromJsonFactory = _$TranscodingInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TranscodingInfo && + (identical(other.audioCodec, audioCodec) || + const DeepCollectionEquality() + .equals(other.audioCodec, audioCodec)) && + (identical(other.videoCodec, videoCodec) || + const DeepCollectionEquality() + .equals(other.videoCodec, videoCodec)) && + (identical(other.container, container) || + const DeepCollectionEquality() + .equals(other.container, container)) && + (identical(other.isVideoDirect, isVideoDirect) || + const DeepCollectionEquality() + .equals(other.isVideoDirect, isVideoDirect)) && + (identical(other.isAudioDirect, isAudioDirect) || + const DeepCollectionEquality() + .equals(other.isAudioDirect, isAudioDirect)) && + (identical(other.bitrate, bitrate) || + const DeepCollectionEquality() + .equals(other.bitrate, bitrate)) && + (identical(other.framerate, framerate) || + const DeepCollectionEquality() + .equals(other.framerate, framerate)) && + (identical(other.completionPercentage, completionPercentage) || + const DeepCollectionEquality().equals( + other.completionPercentage, completionPercentage)) && + (identical(other.width, width) || + const DeepCollectionEquality().equals(other.width, width)) && + (identical(other.height, height) || + const DeepCollectionEquality().equals(other.height, height)) && + (identical(other.audioChannels, audioChannels) || + const DeepCollectionEquality() + .equals(other.audioChannels, audioChannels)) && + (identical( + other.hardwareAccelerationType, hardwareAccelerationType) || + const DeepCollectionEquality().equals( + other.hardwareAccelerationType, + hardwareAccelerationType)) && + (identical(other.transcodeReasons, transcodeReasons) || + const DeepCollectionEquality() + .equals(other.transcodeReasons, transcodeReasons))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(audioCodec) ^ + const DeepCollectionEquality().hash(videoCodec) ^ + const DeepCollectionEquality().hash(container) ^ + const DeepCollectionEquality().hash(isVideoDirect) ^ + const DeepCollectionEquality().hash(isAudioDirect) ^ + const DeepCollectionEquality().hash(bitrate) ^ + const DeepCollectionEquality().hash(framerate) ^ + const DeepCollectionEquality().hash(completionPercentage) ^ + const DeepCollectionEquality().hash(width) ^ + const DeepCollectionEquality().hash(height) ^ + const DeepCollectionEquality().hash(audioChannels) ^ + const DeepCollectionEquality().hash(hardwareAccelerationType) ^ + const DeepCollectionEquality().hash(transcodeReasons) ^ + runtimeType.hashCode; +} + +extension $TranscodingInfoExtension on TranscodingInfo { + TranscodingInfo copyWith( + {String? audioCodec, + String? videoCodec, + String? container, + bool? isVideoDirect, + bool? isAudioDirect, + int? bitrate, + double? framerate, + double? completionPercentage, + int? width, + int? height, + int? audioChannels, + enums.HardwareEncodingType? hardwareAccelerationType, + List? transcodeReasons}) { + return TranscodingInfo( + audioCodec: audioCodec ?? this.audioCodec, + videoCodec: videoCodec ?? this.videoCodec, + container: container ?? this.container, + isVideoDirect: isVideoDirect ?? this.isVideoDirect, + isAudioDirect: isAudioDirect ?? this.isAudioDirect, + bitrate: bitrate ?? this.bitrate, + framerate: framerate ?? this.framerate, + completionPercentage: completionPercentage ?? this.completionPercentage, + width: width ?? this.width, + height: height ?? this.height, + audioChannels: audioChannels ?? this.audioChannels, + hardwareAccelerationType: + hardwareAccelerationType ?? this.hardwareAccelerationType, + transcodeReasons: transcodeReasons ?? this.transcodeReasons); + } + + TranscodingInfo copyWithWrapped( + {Wrapped? audioCodec, + Wrapped? videoCodec, + Wrapped? container, + Wrapped? isVideoDirect, + Wrapped? isAudioDirect, + Wrapped? bitrate, + Wrapped? framerate, + Wrapped? completionPercentage, + Wrapped? width, + Wrapped? height, + Wrapped? audioChannels, + Wrapped? hardwareAccelerationType, + Wrapped?>? transcodeReasons}) { + return TranscodingInfo( + audioCodec: (audioCodec != null ? audioCodec.value : this.audioCodec), + videoCodec: (videoCodec != null ? videoCodec.value : this.videoCodec), + container: (container != null ? container.value : this.container), + isVideoDirect: + (isVideoDirect != null ? isVideoDirect.value : this.isVideoDirect), + isAudioDirect: + (isAudioDirect != null ? isAudioDirect.value : this.isAudioDirect), + bitrate: (bitrate != null ? bitrate.value : this.bitrate), + framerate: (framerate != null ? framerate.value : this.framerate), + completionPercentage: (completionPercentage != null + ? completionPercentage.value + : this.completionPercentage), + width: (width != null ? width.value : this.width), + height: (height != null ? height.value : this.height), + audioChannels: + (audioChannels != null ? audioChannels.value : this.audioChannels), + hardwareAccelerationType: (hardwareAccelerationType != null + ? hardwareAccelerationType.value + : this.hardwareAccelerationType), + transcodeReasons: (transcodeReasons != null + ? transcodeReasons.value + : this.transcodeReasons)); + } +} + +@JsonSerializable(explicitToJson: true) +class TranscodingProfile { + const TranscodingProfile({ + this.container, + this.type, + this.videoCodec, + this.audioCodec, + this.protocol, + this.estimateContentLength, + this.enableMpegtsM2TsMode, + this.transcodeSeekInfo, + this.copyTimestamps, + this.context, + this.enableSubtitlesInManifest, + this.maxAudioChannels, + this.minSegments, + this.segmentLength, + this.breakOnNonKeyFrames, + this.conditions, + }); + + factory TranscodingProfile.fromJson(Map json) => + _$TranscodingProfileFromJson(json); + + static const toJsonFactory = _$TranscodingProfileToJson; + Map toJson() => _$TranscodingProfileToJson(this); + + @JsonKey(name: 'Container', includeIfNull: false) + final String? container; + @JsonKey( + name: 'Type', + includeIfNull: false, + toJson: dlnaProfileTypeNullableToJson, + fromJson: dlnaProfileTypeNullableFromJson, + ) + final enums.DlnaProfileType? type; + @JsonKey(name: 'VideoCodec', includeIfNull: false) + final String? videoCodec; + @JsonKey(name: 'AudioCodec', includeIfNull: false) + final String? audioCodec; + @JsonKey( + name: 'Protocol', + includeIfNull: false, + toJson: mediaStreamProtocolNullableToJson, + fromJson: mediaStreamProtocolNullableFromJson, + ) + final enums.MediaStreamProtocol? protocol; + @JsonKey( + name: 'EstimateContentLength', includeIfNull: false, defaultValue: false) + final bool? estimateContentLength; + @JsonKey( + name: 'EnableMpegtsM2TsMode', includeIfNull: false, defaultValue: false) + final bool? enableMpegtsM2TsMode; + @JsonKey( + name: 'TranscodeSeekInfo', + includeIfNull: false, + toJson: transcodeSeekInfoNullableToJson, + fromJson: transcodeSeekInfoTranscodeSeekInfoNullableFromJson, + ) + final enums.TranscodeSeekInfo? transcodeSeekInfo; + static enums.TranscodeSeekInfo? + transcodeSeekInfoTranscodeSeekInfoNullableFromJson(Object? value) => + transcodeSeekInfoNullableFromJson( + value, enums.TranscodeSeekInfo.auto); + + @JsonKey(name: 'CopyTimestamps', includeIfNull: false, defaultValue: false) + final bool? copyTimestamps; + @JsonKey( + name: 'Context', + includeIfNull: false, + toJson: encodingContextNullableToJson, + fromJson: encodingContextContextNullableFromJson, + ) + final enums.EncodingContext? context; + static enums.EncodingContext? encodingContextContextNullableFromJson( + Object? value) => + encodingContextNullableFromJson(value, enums.EncodingContext.streaming); + + @JsonKey( + name: 'EnableSubtitlesInManifest', + includeIfNull: false, + defaultValue: false) + final bool? enableSubtitlesInManifest; + @JsonKey(name: 'MaxAudioChannels', includeIfNull: false) + final String? maxAudioChannels; + @JsonKey(name: 'MinSegments', includeIfNull: false) + final int? minSegments; + @JsonKey(name: 'SegmentLength', includeIfNull: false) + final int? segmentLength; + @JsonKey( + name: 'BreakOnNonKeyFrames', includeIfNull: false, defaultValue: false) + final bool? breakOnNonKeyFrames; + @JsonKey( + name: 'Conditions', + includeIfNull: false, + defaultValue: []) + final List? conditions; + static const fromJsonFactory = _$TranscodingProfileFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TranscodingProfile && + (identical(other.container, container) || + const DeepCollectionEquality() + .equals(other.container, container)) && + (identical(other.type, type) || + const DeepCollectionEquality().equals(other.type, type)) && + (identical(other.videoCodec, videoCodec) || + const DeepCollectionEquality() + .equals(other.videoCodec, videoCodec)) && + (identical(other.audioCodec, audioCodec) || + const DeepCollectionEquality() + .equals(other.audioCodec, audioCodec)) && + (identical(other.protocol, protocol) || + const DeepCollectionEquality() + .equals(other.protocol, protocol)) && + (identical(other.estimateContentLength, estimateContentLength) || + const DeepCollectionEquality().equals( + other.estimateContentLength, estimateContentLength)) && + (identical(other.enableMpegtsM2TsMode, enableMpegtsM2TsMode) || + const DeepCollectionEquality().equals( + other.enableMpegtsM2TsMode, enableMpegtsM2TsMode)) && + (identical(other.transcodeSeekInfo, transcodeSeekInfo) || + const DeepCollectionEquality() + .equals(other.transcodeSeekInfo, transcodeSeekInfo)) && + (identical(other.copyTimestamps, copyTimestamps) || + const DeepCollectionEquality() + .equals(other.copyTimestamps, copyTimestamps)) && + (identical(other.context, context) || + const DeepCollectionEquality() + .equals(other.context, context)) && + (identical(other.enableSubtitlesInManifest, + enableSubtitlesInManifest) || + const DeepCollectionEquality().equals( + other.enableSubtitlesInManifest, + enableSubtitlesInManifest)) && + (identical(other.maxAudioChannels, maxAudioChannels) || + const DeepCollectionEquality() + .equals(other.maxAudioChannels, maxAudioChannels)) && + (identical(other.minSegments, minSegments) || + const DeepCollectionEquality() + .equals(other.minSegments, minSegments)) && + (identical(other.segmentLength, segmentLength) || + const DeepCollectionEquality() + .equals(other.segmentLength, segmentLength)) && + (identical(other.breakOnNonKeyFrames, breakOnNonKeyFrames) || + const DeepCollectionEquality() + .equals(other.breakOnNonKeyFrames, breakOnNonKeyFrames)) && + (identical(other.conditions, conditions) || + const DeepCollectionEquality() + .equals(other.conditions, conditions))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(container) ^ + const DeepCollectionEquality().hash(type) ^ + const DeepCollectionEquality().hash(videoCodec) ^ + const DeepCollectionEquality().hash(audioCodec) ^ + const DeepCollectionEquality().hash(protocol) ^ + const DeepCollectionEquality().hash(estimateContentLength) ^ + const DeepCollectionEquality().hash(enableMpegtsM2TsMode) ^ + const DeepCollectionEquality().hash(transcodeSeekInfo) ^ + const DeepCollectionEquality().hash(copyTimestamps) ^ + const DeepCollectionEquality().hash(context) ^ + const DeepCollectionEquality().hash(enableSubtitlesInManifest) ^ + const DeepCollectionEquality().hash(maxAudioChannels) ^ + const DeepCollectionEquality().hash(minSegments) ^ + const DeepCollectionEquality().hash(segmentLength) ^ + const DeepCollectionEquality().hash(breakOnNonKeyFrames) ^ + const DeepCollectionEquality().hash(conditions) ^ + runtimeType.hashCode; +} + +extension $TranscodingProfileExtension on TranscodingProfile { + TranscodingProfile copyWith( + {String? container, + enums.DlnaProfileType? type, + String? videoCodec, + String? audioCodec, + enums.MediaStreamProtocol? protocol, + bool? estimateContentLength, + bool? enableMpegtsM2TsMode, + enums.TranscodeSeekInfo? transcodeSeekInfo, + bool? copyTimestamps, + enums.EncodingContext? context, + bool? enableSubtitlesInManifest, + String? maxAudioChannels, + int? minSegments, + int? segmentLength, + bool? breakOnNonKeyFrames, + List? conditions}) { + return TranscodingProfile( + container: container ?? this.container, + type: type ?? this.type, + videoCodec: videoCodec ?? this.videoCodec, + audioCodec: audioCodec ?? this.audioCodec, + protocol: protocol ?? this.protocol, + estimateContentLength: + estimateContentLength ?? this.estimateContentLength, + enableMpegtsM2TsMode: enableMpegtsM2TsMode ?? this.enableMpegtsM2TsMode, + transcodeSeekInfo: transcodeSeekInfo ?? this.transcodeSeekInfo, + copyTimestamps: copyTimestamps ?? this.copyTimestamps, + context: context ?? this.context, + enableSubtitlesInManifest: + enableSubtitlesInManifest ?? this.enableSubtitlesInManifest, + maxAudioChannels: maxAudioChannels ?? this.maxAudioChannels, + minSegments: minSegments ?? this.minSegments, + segmentLength: segmentLength ?? this.segmentLength, + breakOnNonKeyFrames: breakOnNonKeyFrames ?? this.breakOnNonKeyFrames, + conditions: conditions ?? this.conditions); + } + + TranscodingProfile copyWithWrapped( + {Wrapped? container, + Wrapped? type, + Wrapped? videoCodec, + Wrapped? audioCodec, + Wrapped? protocol, + Wrapped? estimateContentLength, + Wrapped? enableMpegtsM2TsMode, + Wrapped? transcodeSeekInfo, + Wrapped? copyTimestamps, + Wrapped? context, + Wrapped? enableSubtitlesInManifest, + Wrapped? maxAudioChannels, + Wrapped? minSegments, + Wrapped? segmentLength, + Wrapped? breakOnNonKeyFrames, + Wrapped?>? conditions}) { + return TranscodingProfile( + container: (container != null ? container.value : this.container), + type: (type != null ? type.value : this.type), + videoCodec: (videoCodec != null ? videoCodec.value : this.videoCodec), + audioCodec: (audioCodec != null ? audioCodec.value : this.audioCodec), + protocol: (protocol != null ? protocol.value : this.protocol), + estimateContentLength: (estimateContentLength != null + ? estimateContentLength.value + : this.estimateContentLength), + enableMpegtsM2TsMode: (enableMpegtsM2TsMode != null + ? enableMpegtsM2TsMode.value + : this.enableMpegtsM2TsMode), + transcodeSeekInfo: (transcodeSeekInfo != null + ? transcodeSeekInfo.value + : this.transcodeSeekInfo), + copyTimestamps: (copyTimestamps != null + ? copyTimestamps.value + : this.copyTimestamps), + context: (context != null ? context.value : this.context), + enableSubtitlesInManifest: (enableSubtitlesInManifest != null + ? enableSubtitlesInManifest.value + : this.enableSubtitlesInManifest), + maxAudioChannels: (maxAudioChannels != null + ? maxAudioChannels.value + : this.maxAudioChannels), + minSegments: + (minSegments != null ? minSegments.value : this.minSegments), + segmentLength: + (segmentLength != null ? segmentLength.value : this.segmentLength), + breakOnNonKeyFrames: (breakOnNonKeyFrames != null + ? breakOnNonKeyFrames.value + : this.breakOnNonKeyFrames), + conditions: (conditions != null ? conditions.value : this.conditions)); + } +} + +@JsonSerializable(explicitToJson: true) +class TrickplayInfo { + const TrickplayInfo({ + this.width, + this.height, + this.tileWidth, + this.tileHeight, + this.thumbnailCount, + this.interval, + this.bandwidth, + }); + + factory TrickplayInfo.fromJson(Map json) => + _$TrickplayInfoFromJson(json); + + static const toJsonFactory = _$TrickplayInfoToJson; + Map toJson() => _$TrickplayInfoToJson(this); + + @JsonKey(name: 'Width', includeIfNull: false) + final int? width; + @JsonKey(name: 'Height', includeIfNull: false) + final int? height; + @JsonKey(name: 'TileWidth', includeIfNull: false) + final int? tileWidth; + @JsonKey(name: 'TileHeight', includeIfNull: false) + final int? tileHeight; + @JsonKey(name: 'ThumbnailCount', includeIfNull: false) + final int? thumbnailCount; + @JsonKey(name: 'Interval', includeIfNull: false) + final int? interval; + @JsonKey(name: 'Bandwidth', includeIfNull: false) + final int? bandwidth; + static const fromJsonFactory = _$TrickplayInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TrickplayInfo && + (identical(other.width, width) || + const DeepCollectionEquality().equals(other.width, width)) && + (identical(other.height, height) || + const DeepCollectionEquality().equals(other.height, height)) && + (identical(other.tileWidth, tileWidth) || + const DeepCollectionEquality() + .equals(other.tileWidth, tileWidth)) && + (identical(other.tileHeight, tileHeight) || + const DeepCollectionEquality() + .equals(other.tileHeight, tileHeight)) && + (identical(other.thumbnailCount, thumbnailCount) || + const DeepCollectionEquality() + .equals(other.thumbnailCount, thumbnailCount)) && + (identical(other.interval, interval) || + const DeepCollectionEquality() + .equals(other.interval, interval)) && + (identical(other.bandwidth, bandwidth) || + const DeepCollectionEquality() + .equals(other.bandwidth, bandwidth))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(width) ^ + const DeepCollectionEquality().hash(height) ^ + const DeepCollectionEquality().hash(tileWidth) ^ + const DeepCollectionEquality().hash(tileHeight) ^ + const DeepCollectionEquality().hash(thumbnailCount) ^ + const DeepCollectionEquality().hash(interval) ^ + const DeepCollectionEquality().hash(bandwidth) ^ + runtimeType.hashCode; +} + +extension $TrickplayInfoExtension on TrickplayInfo { + TrickplayInfo copyWith( + {int? width, + int? height, + int? tileWidth, + int? tileHeight, + int? thumbnailCount, + int? interval, + int? bandwidth}) { + return TrickplayInfo( + width: width ?? this.width, + height: height ?? this.height, + tileWidth: tileWidth ?? this.tileWidth, + tileHeight: tileHeight ?? this.tileHeight, + thumbnailCount: thumbnailCount ?? this.thumbnailCount, + interval: interval ?? this.interval, + bandwidth: bandwidth ?? this.bandwidth); + } + + TrickplayInfo copyWithWrapped( + {Wrapped? width, + Wrapped? height, + Wrapped? tileWidth, + Wrapped? tileHeight, + Wrapped? thumbnailCount, + Wrapped? interval, + Wrapped? bandwidth}) { + return TrickplayInfo( + width: (width != null ? width.value : this.width), + height: (height != null ? height.value : this.height), + tileWidth: (tileWidth != null ? tileWidth.value : this.tileWidth), + tileHeight: (tileHeight != null ? tileHeight.value : this.tileHeight), + thumbnailCount: (thumbnailCount != null + ? thumbnailCount.value + : this.thumbnailCount), + interval: (interval != null ? interval.value : this.interval), + bandwidth: (bandwidth != null ? bandwidth.value : this.bandwidth)); + } +} + +@JsonSerializable(explicitToJson: true) +class TrickplayOptions { + const TrickplayOptions({ + this.enableHwAcceleration, + this.enableHwEncoding, + this.scanBehavior, + this.processPriority, + this.interval, + this.widthResolutions, + this.tileWidth, + this.tileHeight, + this.qscale, + this.jpegQuality, + this.processThreads, + }); + + factory TrickplayOptions.fromJson(Map json) => + _$TrickplayOptionsFromJson(json); + + static const toJsonFactory = _$TrickplayOptionsToJson; + Map toJson() => _$TrickplayOptionsToJson(this); + + @JsonKey(name: 'EnableHwAcceleration', includeIfNull: false) + final bool? enableHwAcceleration; + @JsonKey(name: 'EnableHwEncoding', includeIfNull: false) + final bool? enableHwEncoding; + @JsonKey( + name: 'ScanBehavior', + includeIfNull: false, + toJson: trickplayScanBehaviorNullableToJson, + fromJson: trickplayScanBehaviorNullableFromJson, + ) + final enums.TrickplayScanBehavior? scanBehavior; + @JsonKey( + name: 'ProcessPriority', + includeIfNull: false, + toJson: processPriorityClassNullableToJson, + fromJson: processPriorityClassNullableFromJson, + ) + final enums.ProcessPriorityClass? processPriority; + @JsonKey(name: 'Interval', includeIfNull: false) + final int? interval; + @JsonKey( + name: 'WidthResolutions', includeIfNull: false, defaultValue: []) + final List? widthResolutions; + @JsonKey(name: 'TileWidth', includeIfNull: false) + final int? tileWidth; + @JsonKey(name: 'TileHeight', includeIfNull: false) + final int? tileHeight; + @JsonKey(name: 'Qscale', includeIfNull: false) + final int? qscale; + @JsonKey(name: 'JpegQuality', includeIfNull: false) + final int? jpegQuality; + @JsonKey(name: 'ProcessThreads', includeIfNull: false) + final int? processThreads; + static const fromJsonFactory = _$TrickplayOptionsFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TrickplayOptions && + (identical(other.enableHwAcceleration, enableHwAcceleration) || + const DeepCollectionEquality().equals( + other.enableHwAcceleration, enableHwAcceleration)) && + (identical(other.enableHwEncoding, enableHwEncoding) || + const DeepCollectionEquality() + .equals(other.enableHwEncoding, enableHwEncoding)) && + (identical(other.scanBehavior, scanBehavior) || + const DeepCollectionEquality() + .equals(other.scanBehavior, scanBehavior)) && + (identical(other.processPriority, processPriority) || + const DeepCollectionEquality() + .equals(other.processPriority, processPriority)) && + (identical(other.interval, interval) || + const DeepCollectionEquality() + .equals(other.interval, interval)) && + (identical(other.widthResolutions, widthResolutions) || + const DeepCollectionEquality() + .equals(other.widthResolutions, widthResolutions)) && + (identical(other.tileWidth, tileWidth) || + const DeepCollectionEquality() + .equals(other.tileWidth, tileWidth)) && + (identical(other.tileHeight, tileHeight) || + const DeepCollectionEquality() + .equals(other.tileHeight, tileHeight)) && + (identical(other.qscale, qscale) || + const DeepCollectionEquality().equals(other.qscale, qscale)) && + (identical(other.jpegQuality, jpegQuality) || + const DeepCollectionEquality() + .equals(other.jpegQuality, jpegQuality)) && + (identical(other.processThreads, processThreads) || + const DeepCollectionEquality() + .equals(other.processThreads, processThreads))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(enableHwAcceleration) ^ + const DeepCollectionEquality().hash(enableHwEncoding) ^ + const DeepCollectionEquality().hash(scanBehavior) ^ + const DeepCollectionEquality().hash(processPriority) ^ + const DeepCollectionEquality().hash(interval) ^ + const DeepCollectionEquality().hash(widthResolutions) ^ + const DeepCollectionEquality().hash(tileWidth) ^ + const DeepCollectionEquality().hash(tileHeight) ^ + const DeepCollectionEquality().hash(qscale) ^ + const DeepCollectionEquality().hash(jpegQuality) ^ + const DeepCollectionEquality().hash(processThreads) ^ + runtimeType.hashCode; +} + +extension $TrickplayOptionsExtension on TrickplayOptions { + TrickplayOptions copyWith( + {bool? enableHwAcceleration, + bool? enableHwEncoding, + enums.TrickplayScanBehavior? scanBehavior, + enums.ProcessPriorityClass? processPriority, + int? interval, + List? widthResolutions, + int? tileWidth, + int? tileHeight, + int? qscale, + int? jpegQuality, + int? processThreads}) { + return TrickplayOptions( + enableHwAcceleration: enableHwAcceleration ?? this.enableHwAcceleration, + enableHwEncoding: enableHwEncoding ?? this.enableHwEncoding, + scanBehavior: scanBehavior ?? this.scanBehavior, + processPriority: processPriority ?? this.processPriority, + interval: interval ?? this.interval, + widthResolutions: widthResolutions ?? this.widthResolutions, + tileWidth: tileWidth ?? this.tileWidth, + tileHeight: tileHeight ?? this.tileHeight, + qscale: qscale ?? this.qscale, + jpegQuality: jpegQuality ?? this.jpegQuality, + processThreads: processThreads ?? this.processThreads); + } + + TrickplayOptions copyWithWrapped( + {Wrapped? enableHwAcceleration, + Wrapped? enableHwEncoding, + Wrapped? scanBehavior, + Wrapped? processPriority, + Wrapped? interval, + Wrapped?>? widthResolutions, + Wrapped? tileWidth, + Wrapped? tileHeight, + Wrapped? qscale, + Wrapped? jpegQuality, + Wrapped? processThreads}) { + return TrickplayOptions( + enableHwAcceleration: (enableHwAcceleration != null + ? enableHwAcceleration.value + : this.enableHwAcceleration), + enableHwEncoding: (enableHwEncoding != null + ? enableHwEncoding.value + : this.enableHwEncoding), + scanBehavior: + (scanBehavior != null ? scanBehavior.value : this.scanBehavior), + processPriority: (processPriority != null + ? processPriority.value + : this.processPriority), + interval: (interval != null ? interval.value : this.interval), + widthResolutions: (widthResolutions != null + ? widthResolutions.value + : this.widthResolutions), + tileWidth: (tileWidth != null ? tileWidth.value : this.tileWidth), + tileHeight: (tileHeight != null ? tileHeight.value : this.tileHeight), + qscale: (qscale != null ? qscale.value : this.qscale), + jpegQuality: + (jpegQuality != null ? jpegQuality.value : this.jpegQuality), + processThreads: (processThreads != null + ? processThreads.value + : this.processThreads)); + } +} + +@JsonSerializable(explicitToJson: true) +class TunerChannelMapping { + const TunerChannelMapping({ + this.name, + this.providerChannelName, + this.providerChannelId, + this.id, + }); + + factory TunerChannelMapping.fromJson(Map json) => + _$TunerChannelMappingFromJson(json); + + static const toJsonFactory = _$TunerChannelMappingToJson; + Map toJson() => _$TunerChannelMappingToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'ProviderChannelName', includeIfNull: false) + final String? providerChannelName; + @JsonKey(name: 'ProviderChannelId', includeIfNull: false) + final String? providerChannelId; + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + static const fromJsonFactory = _$TunerChannelMappingFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TunerChannelMapping && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.providerChannelName, providerChannelName) || + const DeepCollectionEquality() + .equals(other.providerChannelName, providerChannelName)) && + (identical(other.providerChannelId, providerChannelId) || + const DeepCollectionEquality() + .equals(other.providerChannelId, providerChannelId)) && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(providerChannelName) ^ + const DeepCollectionEquality().hash(providerChannelId) ^ + const DeepCollectionEquality().hash(id) ^ + runtimeType.hashCode; +} + +extension $TunerChannelMappingExtension on TunerChannelMapping { + TunerChannelMapping copyWith( + {String? name, + String? providerChannelName, + String? providerChannelId, + String? id}) { + return TunerChannelMapping( + name: name ?? this.name, + providerChannelName: providerChannelName ?? this.providerChannelName, + providerChannelId: providerChannelId ?? this.providerChannelId, + id: id ?? this.id); + } + + TunerChannelMapping copyWithWrapped( + {Wrapped? name, + Wrapped? providerChannelName, + Wrapped? providerChannelId, + Wrapped? id}) { + return TunerChannelMapping( + name: (name != null ? name.value : this.name), + providerChannelName: (providerChannelName != null + ? providerChannelName.value + : this.providerChannelName), + providerChannelId: (providerChannelId != null + ? providerChannelId.value + : this.providerChannelId), + id: (id != null ? id.value : this.id)); + } +} + +@JsonSerializable(explicitToJson: true) +class TunerHostInfo { + const TunerHostInfo({ + this.id, + this.url, + this.type, + this.deviceId, + this.friendlyName, + this.importFavoritesOnly, + this.allowHWTranscoding, + this.enableStreamLooping, + this.source, + this.tunerCount, + this.userAgent, + this.ignoreDts, + }); + + factory TunerHostInfo.fromJson(Map json) => + _$TunerHostInfoFromJson(json); + + static const toJsonFactory = _$TunerHostInfoToJson; + Map toJson() => _$TunerHostInfoToJson(this); + + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'Url', includeIfNull: false) + final String? url; + @JsonKey(name: 'Type', includeIfNull: false) + final String? type; + @JsonKey(name: 'DeviceId', includeIfNull: false) + final String? deviceId; + @JsonKey(name: 'FriendlyName', includeIfNull: false) + final String? friendlyName; + @JsonKey(name: 'ImportFavoritesOnly', includeIfNull: false) + final bool? importFavoritesOnly; + @JsonKey(name: 'AllowHWTranscoding', includeIfNull: false) + final bool? allowHWTranscoding; + @JsonKey(name: 'EnableStreamLooping', includeIfNull: false) + final bool? enableStreamLooping; + @JsonKey(name: 'Source', includeIfNull: false) + final String? source; + @JsonKey(name: 'TunerCount', includeIfNull: false) + final int? tunerCount; + @JsonKey(name: 'UserAgent', includeIfNull: false) + final String? userAgent; + @JsonKey(name: 'IgnoreDts', includeIfNull: false) + final bool? ignoreDts; + static const fromJsonFactory = _$TunerHostInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TunerHostInfo && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.url, url) || + const DeepCollectionEquality().equals(other.url, url)) && + (identical(other.type, type) || + const DeepCollectionEquality().equals(other.type, type)) && + (identical(other.deviceId, deviceId) || + const DeepCollectionEquality() + .equals(other.deviceId, deviceId)) && + (identical(other.friendlyName, friendlyName) || + const DeepCollectionEquality() + .equals(other.friendlyName, friendlyName)) && + (identical(other.importFavoritesOnly, importFavoritesOnly) || + const DeepCollectionEquality() + .equals(other.importFavoritesOnly, importFavoritesOnly)) && + (identical(other.allowHWTranscoding, allowHWTranscoding) || + const DeepCollectionEquality() + .equals(other.allowHWTranscoding, allowHWTranscoding)) && + (identical(other.enableStreamLooping, enableStreamLooping) || + const DeepCollectionEquality() + .equals(other.enableStreamLooping, enableStreamLooping)) && + (identical(other.source, source) || + const DeepCollectionEquality().equals(other.source, source)) && + (identical(other.tunerCount, tunerCount) || + const DeepCollectionEquality() + .equals(other.tunerCount, tunerCount)) && + (identical(other.userAgent, userAgent) || + const DeepCollectionEquality() + .equals(other.userAgent, userAgent)) && + (identical(other.ignoreDts, ignoreDts) || + const DeepCollectionEquality() + .equals(other.ignoreDts, ignoreDts))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(url) ^ + const DeepCollectionEquality().hash(type) ^ + const DeepCollectionEquality().hash(deviceId) ^ + const DeepCollectionEquality().hash(friendlyName) ^ + const DeepCollectionEquality().hash(importFavoritesOnly) ^ + const DeepCollectionEquality().hash(allowHWTranscoding) ^ + const DeepCollectionEquality().hash(enableStreamLooping) ^ + const DeepCollectionEquality().hash(source) ^ + const DeepCollectionEquality().hash(tunerCount) ^ + const DeepCollectionEquality().hash(userAgent) ^ + const DeepCollectionEquality().hash(ignoreDts) ^ + runtimeType.hashCode; +} + +extension $TunerHostInfoExtension on TunerHostInfo { + TunerHostInfo copyWith( + {String? id, + String? url, + String? type, + String? deviceId, + String? friendlyName, + bool? importFavoritesOnly, + bool? allowHWTranscoding, + bool? enableStreamLooping, + String? source, + int? tunerCount, + String? userAgent, + bool? ignoreDts}) { + return TunerHostInfo( + id: id ?? this.id, + url: url ?? this.url, + type: type ?? this.type, + deviceId: deviceId ?? this.deviceId, + friendlyName: friendlyName ?? this.friendlyName, + importFavoritesOnly: importFavoritesOnly ?? this.importFavoritesOnly, + allowHWTranscoding: allowHWTranscoding ?? this.allowHWTranscoding, + enableStreamLooping: enableStreamLooping ?? this.enableStreamLooping, + source: source ?? this.source, + tunerCount: tunerCount ?? this.tunerCount, + userAgent: userAgent ?? this.userAgent, + ignoreDts: ignoreDts ?? this.ignoreDts); + } + + TunerHostInfo copyWithWrapped( + {Wrapped? id, + Wrapped? url, + Wrapped? type, + Wrapped? deviceId, + Wrapped? friendlyName, + Wrapped? importFavoritesOnly, + Wrapped? allowHWTranscoding, + Wrapped? enableStreamLooping, + Wrapped? source, + Wrapped? tunerCount, + Wrapped? userAgent, + Wrapped? ignoreDts}) { + return TunerHostInfo( + id: (id != null ? id.value : this.id), + url: (url != null ? url.value : this.url), + type: (type != null ? type.value : this.type), + deviceId: (deviceId != null ? deviceId.value : this.deviceId), + friendlyName: + (friendlyName != null ? friendlyName.value : this.friendlyName), + importFavoritesOnly: (importFavoritesOnly != null + ? importFavoritesOnly.value + : this.importFavoritesOnly), + allowHWTranscoding: (allowHWTranscoding != null + ? allowHWTranscoding.value + : this.allowHWTranscoding), + enableStreamLooping: (enableStreamLooping != null + ? enableStreamLooping.value + : this.enableStreamLooping), + source: (source != null ? source.value : this.source), + tunerCount: (tunerCount != null ? tunerCount.value : this.tunerCount), + userAgent: (userAgent != null ? userAgent.value : this.userAgent), + ignoreDts: (ignoreDts != null ? ignoreDts.value : this.ignoreDts)); + } +} + +@JsonSerializable(explicitToJson: true) +class TypeOptions { + const TypeOptions({ + this.type, + this.metadataFetchers, + this.metadataFetcherOrder, + this.imageFetchers, + this.imageFetcherOrder, + this.imageOptions, + }); + + factory TypeOptions.fromJson(Map json) => + _$TypeOptionsFromJson(json); + + static const toJsonFactory = _$TypeOptionsToJson; + Map toJson() => _$TypeOptionsToJson(this); + + @JsonKey(name: 'Type', includeIfNull: false) + final String? type; + @JsonKey( + name: 'MetadataFetchers', includeIfNull: false, defaultValue: []) + final List? metadataFetchers; + @JsonKey( + name: 'MetadataFetcherOrder', + includeIfNull: false, + defaultValue: []) + final List? metadataFetcherOrder; + @JsonKey( + name: 'ImageFetchers', includeIfNull: false, defaultValue: []) + final List? imageFetchers; + @JsonKey( + name: 'ImageFetcherOrder', includeIfNull: false, defaultValue: []) + final List? imageFetcherOrder; + @JsonKey( + name: 'ImageOptions', includeIfNull: false, defaultValue: []) + final List? imageOptions; + static const fromJsonFactory = _$TypeOptionsFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is TypeOptions && + (identical(other.type, type) || + const DeepCollectionEquality().equals(other.type, type)) && + (identical(other.metadataFetchers, metadataFetchers) || + const DeepCollectionEquality() + .equals(other.metadataFetchers, metadataFetchers)) && + (identical(other.metadataFetcherOrder, metadataFetcherOrder) || + const DeepCollectionEquality().equals( + other.metadataFetcherOrder, metadataFetcherOrder)) && + (identical(other.imageFetchers, imageFetchers) || + const DeepCollectionEquality() + .equals(other.imageFetchers, imageFetchers)) && + (identical(other.imageFetcherOrder, imageFetcherOrder) || + const DeepCollectionEquality() + .equals(other.imageFetcherOrder, imageFetcherOrder)) && + (identical(other.imageOptions, imageOptions) || + const DeepCollectionEquality() + .equals(other.imageOptions, imageOptions))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(type) ^ + const DeepCollectionEquality().hash(metadataFetchers) ^ + const DeepCollectionEquality().hash(metadataFetcherOrder) ^ + const DeepCollectionEquality().hash(imageFetchers) ^ + const DeepCollectionEquality().hash(imageFetcherOrder) ^ + const DeepCollectionEquality().hash(imageOptions) ^ + runtimeType.hashCode; +} + +extension $TypeOptionsExtension on TypeOptions { + TypeOptions copyWith( + {String? type, + List? metadataFetchers, + List? metadataFetcherOrder, + List? imageFetchers, + List? imageFetcherOrder, + List? imageOptions}) { + return TypeOptions( + type: type ?? this.type, + metadataFetchers: metadataFetchers ?? this.metadataFetchers, + metadataFetcherOrder: metadataFetcherOrder ?? this.metadataFetcherOrder, + imageFetchers: imageFetchers ?? this.imageFetchers, + imageFetcherOrder: imageFetcherOrder ?? this.imageFetcherOrder, + imageOptions: imageOptions ?? this.imageOptions); + } + + TypeOptions copyWithWrapped( + {Wrapped? type, + Wrapped?>? metadataFetchers, + Wrapped?>? metadataFetcherOrder, + Wrapped?>? imageFetchers, + Wrapped?>? imageFetcherOrder, + Wrapped?>? imageOptions}) { + return TypeOptions( + type: (type != null ? type.value : this.type), + metadataFetchers: (metadataFetchers != null + ? metadataFetchers.value + : this.metadataFetchers), + metadataFetcherOrder: (metadataFetcherOrder != null + ? metadataFetcherOrder.value + : this.metadataFetcherOrder), + imageFetchers: + (imageFetchers != null ? imageFetchers.value : this.imageFetchers), + imageFetcherOrder: (imageFetcherOrder != null + ? imageFetcherOrder.value + : this.imageFetcherOrder), + imageOptions: + (imageOptions != null ? imageOptions.value : this.imageOptions)); + } +} + +@JsonSerializable(explicitToJson: true) +class UpdateLibraryOptionsDto { + const UpdateLibraryOptionsDto({ + this.id, + this.libraryOptions, + }); + + factory UpdateLibraryOptionsDto.fromJson(Map json) => + _$UpdateLibraryOptionsDtoFromJson(json); + + static const toJsonFactory = _$UpdateLibraryOptionsDtoToJson; + Map toJson() => _$UpdateLibraryOptionsDtoToJson(this); + + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'LibraryOptions', includeIfNull: false) + final LibraryOptions? libraryOptions; + static const fromJsonFactory = _$UpdateLibraryOptionsDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is UpdateLibraryOptionsDto && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.libraryOptions, libraryOptions) || + const DeepCollectionEquality() + .equals(other.libraryOptions, libraryOptions))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(libraryOptions) ^ + runtimeType.hashCode; +} + +extension $UpdateLibraryOptionsDtoExtension on UpdateLibraryOptionsDto { + UpdateLibraryOptionsDto copyWith( + {String? id, LibraryOptions? libraryOptions}) { + return UpdateLibraryOptionsDto( + id: id ?? this.id, + libraryOptions: libraryOptions ?? this.libraryOptions); + } + + UpdateLibraryOptionsDto copyWithWrapped( + {Wrapped? id, Wrapped? libraryOptions}) { + return UpdateLibraryOptionsDto( + id: (id != null ? id.value : this.id), + libraryOptions: (libraryOptions != null + ? libraryOptions.value + : this.libraryOptions)); + } +} + +@JsonSerializable(explicitToJson: true) +class UpdateMediaPathRequestDto { + const UpdateMediaPathRequestDto({ + required this.name, + required this.pathInfo, + }); + + factory UpdateMediaPathRequestDto.fromJson(Map json) => + _$UpdateMediaPathRequestDtoFromJson(json); + + static const toJsonFactory = _$UpdateMediaPathRequestDtoToJson; + Map toJson() => _$UpdateMediaPathRequestDtoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String name; + @JsonKey(name: 'PathInfo', includeIfNull: false) + final MediaPathInfo pathInfo; + static const fromJsonFactory = _$UpdateMediaPathRequestDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is UpdateMediaPathRequestDto && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.pathInfo, pathInfo) || + const DeepCollectionEquality() + .equals(other.pathInfo, pathInfo))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(pathInfo) ^ + runtimeType.hashCode; +} + +extension $UpdateMediaPathRequestDtoExtension on UpdateMediaPathRequestDto { + UpdateMediaPathRequestDto copyWith({String? name, MediaPathInfo? pathInfo}) { + return UpdateMediaPathRequestDto( + name: name ?? this.name, pathInfo: pathInfo ?? this.pathInfo); + } + + UpdateMediaPathRequestDto copyWithWrapped( + {Wrapped? name, Wrapped? pathInfo}) { + return UpdateMediaPathRequestDto( + name: (name != null ? name.value : this.name), + pathInfo: (pathInfo != null ? pathInfo.value : this.pathInfo)); + } +} + +@JsonSerializable(explicitToJson: true) +class UpdatePlaylistDto { + const UpdatePlaylistDto({ + this.name, + this.ids, + this.users, + this.isPublic, + }); + + factory UpdatePlaylistDto.fromJson(Map json) => + _$UpdatePlaylistDtoFromJson(json); + + static const toJsonFactory = _$UpdatePlaylistDtoToJson; + Map toJson() => _$UpdatePlaylistDtoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'Ids', includeIfNull: false, defaultValue: []) + final List? ids; + @JsonKey( + name: 'Users', + includeIfNull: false, + defaultValue: []) + final List? users; + @JsonKey(name: 'IsPublic', includeIfNull: false) + final bool? isPublic; + static const fromJsonFactory = _$UpdatePlaylistDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is UpdatePlaylistDto && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.ids, ids) || + const DeepCollectionEquality().equals(other.ids, ids)) && + (identical(other.users, users) || + const DeepCollectionEquality().equals(other.users, users)) && + (identical(other.isPublic, isPublic) || + const DeepCollectionEquality() + .equals(other.isPublic, isPublic))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(ids) ^ + const DeepCollectionEquality().hash(users) ^ + const DeepCollectionEquality().hash(isPublic) ^ + runtimeType.hashCode; +} + +extension $UpdatePlaylistDtoExtension on UpdatePlaylistDto { + UpdatePlaylistDto copyWith( + {String? name, + List? ids, + List? users, + bool? isPublic}) { + return UpdatePlaylistDto( + name: name ?? this.name, + ids: ids ?? this.ids, + users: users ?? this.users, + isPublic: isPublic ?? this.isPublic); + } + + UpdatePlaylistDto copyWithWrapped( + {Wrapped? name, + Wrapped?>? ids, + Wrapped?>? users, + Wrapped? isPublic}) { + return UpdatePlaylistDto( + name: (name != null ? name.value : this.name), + ids: (ids != null ? ids.value : this.ids), + users: (users != null ? users.value : this.users), + isPublic: (isPublic != null ? isPublic.value : this.isPublic)); + } +} + +@JsonSerializable(explicitToJson: true) +class UpdatePlaylistUserDto { + const UpdatePlaylistUserDto({ + this.canEdit, + }); + + factory UpdatePlaylistUserDto.fromJson(Map json) => + _$UpdatePlaylistUserDtoFromJson(json); + + static const toJsonFactory = _$UpdatePlaylistUserDtoToJson; + Map toJson() => _$UpdatePlaylistUserDtoToJson(this); + + @JsonKey(name: 'CanEdit', includeIfNull: false) + final bool? canEdit; + static const fromJsonFactory = _$UpdatePlaylistUserDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is UpdatePlaylistUserDto && + (identical(other.canEdit, canEdit) || + const DeepCollectionEquality().equals(other.canEdit, canEdit))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(canEdit) ^ runtimeType.hashCode; +} + +extension $UpdatePlaylistUserDtoExtension on UpdatePlaylistUserDto { + UpdatePlaylistUserDto copyWith({bool? canEdit}) { + return UpdatePlaylistUserDto(canEdit: canEdit ?? this.canEdit); + } + + UpdatePlaylistUserDto copyWithWrapped({Wrapped? canEdit}) { + return UpdatePlaylistUserDto( + canEdit: (canEdit != null ? canEdit.value : this.canEdit)); + } +} + +@JsonSerializable(explicitToJson: true) +class UpdateUserItemDataDto { + const UpdateUserItemDataDto({ + this.rating, + this.playedPercentage, + this.unplayedItemCount, + this.playbackPositionTicks, + this.playCount, + this.isFavorite, + this.likes, + this.lastPlayedDate, + this.played, + this.key, + this.itemId, + }); + + factory UpdateUserItemDataDto.fromJson(Map json) => + _$UpdateUserItemDataDtoFromJson(json); + + static const toJsonFactory = _$UpdateUserItemDataDtoToJson; + Map toJson() => _$UpdateUserItemDataDtoToJson(this); + + @JsonKey(name: 'Rating', includeIfNull: false) + final double? rating; + @JsonKey(name: 'PlayedPercentage', includeIfNull: false) + final double? playedPercentage; + @JsonKey(name: 'UnplayedItemCount', includeIfNull: false) + final int? unplayedItemCount; + @JsonKey(name: 'PlaybackPositionTicks', includeIfNull: false) + final int? playbackPositionTicks; + @JsonKey(name: 'PlayCount', includeIfNull: false) + final int? playCount; + @JsonKey(name: 'IsFavorite', includeIfNull: false) + final bool? isFavorite; + @JsonKey(name: 'Likes', includeIfNull: false) + final bool? likes; + @JsonKey(name: 'LastPlayedDate', includeIfNull: false) + final DateTime? lastPlayedDate; + @JsonKey(name: 'Played', includeIfNull: false) + final bool? played; + @JsonKey(name: 'Key', includeIfNull: false) + final String? key; + @JsonKey(name: 'ItemId', includeIfNull: false) + final String? itemId; + static const fromJsonFactory = _$UpdateUserItemDataDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is UpdateUserItemDataDto && + (identical(other.rating, rating) || + const DeepCollectionEquality().equals(other.rating, rating)) && + (identical(other.playedPercentage, playedPercentage) || + const DeepCollectionEquality() + .equals(other.playedPercentage, playedPercentage)) && + (identical(other.unplayedItemCount, unplayedItemCount) || + const DeepCollectionEquality() + .equals(other.unplayedItemCount, unplayedItemCount)) && + (identical(other.playbackPositionTicks, playbackPositionTicks) || + const DeepCollectionEquality().equals( + other.playbackPositionTicks, playbackPositionTicks)) && + (identical(other.playCount, playCount) || + const DeepCollectionEquality() + .equals(other.playCount, playCount)) && + (identical(other.isFavorite, isFavorite) || + const DeepCollectionEquality() + .equals(other.isFavorite, isFavorite)) && + (identical(other.likes, likes) || + const DeepCollectionEquality().equals(other.likes, likes)) && + (identical(other.lastPlayedDate, lastPlayedDate) || + const DeepCollectionEquality() + .equals(other.lastPlayedDate, lastPlayedDate)) && + (identical(other.played, played) || + const DeepCollectionEquality().equals(other.played, played)) && + (identical(other.key, key) || + const DeepCollectionEquality().equals(other.key, key)) && + (identical(other.itemId, itemId) || + const DeepCollectionEquality().equals(other.itemId, itemId))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(rating) ^ + const DeepCollectionEquality().hash(playedPercentage) ^ + const DeepCollectionEquality().hash(unplayedItemCount) ^ + const DeepCollectionEquality().hash(playbackPositionTicks) ^ + const DeepCollectionEquality().hash(playCount) ^ + const DeepCollectionEquality().hash(isFavorite) ^ + const DeepCollectionEquality().hash(likes) ^ + const DeepCollectionEquality().hash(lastPlayedDate) ^ + const DeepCollectionEquality().hash(played) ^ + const DeepCollectionEquality().hash(key) ^ + const DeepCollectionEquality().hash(itemId) ^ + runtimeType.hashCode; +} + +extension $UpdateUserItemDataDtoExtension on UpdateUserItemDataDto { + UpdateUserItemDataDto copyWith( + {double? rating, + double? playedPercentage, + int? unplayedItemCount, + int? playbackPositionTicks, + int? playCount, + bool? isFavorite, + bool? likes, + DateTime? lastPlayedDate, + bool? played, + String? key, + String? itemId}) { + return UpdateUserItemDataDto( + rating: rating ?? this.rating, + playedPercentage: playedPercentage ?? this.playedPercentage, + unplayedItemCount: unplayedItemCount ?? this.unplayedItemCount, + playbackPositionTicks: + playbackPositionTicks ?? this.playbackPositionTicks, + playCount: playCount ?? this.playCount, + isFavorite: isFavorite ?? this.isFavorite, + likes: likes ?? this.likes, + lastPlayedDate: lastPlayedDate ?? this.lastPlayedDate, + played: played ?? this.played, + key: key ?? this.key, + itemId: itemId ?? this.itemId); + } + + UpdateUserItemDataDto copyWithWrapped( + {Wrapped? rating, + Wrapped? playedPercentage, + Wrapped? unplayedItemCount, + Wrapped? playbackPositionTicks, + Wrapped? playCount, + Wrapped? isFavorite, + Wrapped? likes, + Wrapped? lastPlayedDate, + Wrapped? played, + Wrapped? key, + Wrapped? itemId}) { + return UpdateUserItemDataDto( + rating: (rating != null ? rating.value : this.rating), + playedPercentage: (playedPercentage != null + ? playedPercentage.value + : this.playedPercentage), + unplayedItemCount: (unplayedItemCount != null + ? unplayedItemCount.value + : this.unplayedItemCount), + playbackPositionTicks: (playbackPositionTicks != null + ? playbackPositionTicks.value + : this.playbackPositionTicks), + playCount: (playCount != null ? playCount.value : this.playCount), + isFavorite: (isFavorite != null ? isFavorite.value : this.isFavorite), + likes: (likes != null ? likes.value : this.likes), + lastPlayedDate: (lastPlayedDate != null + ? lastPlayedDate.value + : this.lastPlayedDate), + played: (played != null ? played.value : this.played), + key: (key != null ? key.value : this.key), + itemId: (itemId != null ? itemId.value : this.itemId)); + } +} + +@JsonSerializable(explicitToJson: true) +class UpdateUserPassword { + const UpdateUserPassword({ + this.currentPassword, + this.currentPw, + this.newPw, + this.resetPassword, + }); + + factory UpdateUserPassword.fromJson(Map json) => + _$UpdateUserPasswordFromJson(json); + + static const toJsonFactory = _$UpdateUserPasswordToJson; + Map toJson() => _$UpdateUserPasswordToJson(this); + + @JsonKey(name: 'CurrentPassword', includeIfNull: false) + final String? currentPassword; + @JsonKey(name: 'CurrentPw', includeIfNull: false) + final String? currentPw; + @JsonKey(name: 'NewPw', includeIfNull: false) + final String? newPw; + @JsonKey(name: 'ResetPassword', includeIfNull: false) + final bool? resetPassword; + static const fromJsonFactory = _$UpdateUserPasswordFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is UpdateUserPassword && + (identical(other.currentPassword, currentPassword) || + const DeepCollectionEquality() + .equals(other.currentPassword, currentPassword)) && + (identical(other.currentPw, currentPw) || + const DeepCollectionEquality() + .equals(other.currentPw, currentPw)) && + (identical(other.newPw, newPw) || + const DeepCollectionEquality().equals(other.newPw, newPw)) && + (identical(other.resetPassword, resetPassword) || + const DeepCollectionEquality() + .equals(other.resetPassword, resetPassword))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(currentPassword) ^ + const DeepCollectionEquality().hash(currentPw) ^ + const DeepCollectionEquality().hash(newPw) ^ + const DeepCollectionEquality().hash(resetPassword) ^ + runtimeType.hashCode; +} + +extension $UpdateUserPasswordExtension on UpdateUserPassword { + UpdateUserPassword copyWith( + {String? currentPassword, + String? currentPw, + String? newPw, + bool? resetPassword}) { + return UpdateUserPassword( + currentPassword: currentPassword ?? this.currentPassword, + currentPw: currentPw ?? this.currentPw, + newPw: newPw ?? this.newPw, + resetPassword: resetPassword ?? this.resetPassword); + } + + UpdateUserPassword copyWithWrapped( + {Wrapped? currentPassword, + Wrapped? currentPw, + Wrapped? newPw, + Wrapped? resetPassword}) { + return UpdateUserPassword( + currentPassword: (currentPassword != null + ? currentPassword.value + : this.currentPassword), + currentPw: (currentPw != null ? currentPw.value : this.currentPw), + newPw: (newPw != null ? newPw.value : this.newPw), + resetPassword: + (resetPassword != null ? resetPassword.value : this.resetPassword)); + } +} + +@JsonSerializable(explicitToJson: true) +class UploadSubtitleDto { + const UploadSubtitleDto({ + required this.language, + required this.format, + required this.isForced, + required this.isHearingImpaired, + required this.data, + }); + + factory UploadSubtitleDto.fromJson(Map json) => + _$UploadSubtitleDtoFromJson(json); + + static const toJsonFactory = _$UploadSubtitleDtoToJson; + Map toJson() => _$UploadSubtitleDtoToJson(this); + + @JsonKey(name: 'Language', includeIfNull: false) + final String language; + @JsonKey(name: 'Format', includeIfNull: false) + final String format; + @JsonKey(name: 'IsForced', includeIfNull: false) + final bool isForced; + @JsonKey(name: 'IsHearingImpaired', includeIfNull: false) + final bool isHearingImpaired; + @JsonKey(name: 'Data', includeIfNull: false) + final String data; + static const fromJsonFactory = _$UploadSubtitleDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is UploadSubtitleDto && + (identical(other.language, language) || + const DeepCollectionEquality() + .equals(other.language, language)) && + (identical(other.format, format) || + const DeepCollectionEquality().equals(other.format, format)) && + (identical(other.isForced, isForced) || + const DeepCollectionEquality() + .equals(other.isForced, isForced)) && + (identical(other.isHearingImpaired, isHearingImpaired) || + const DeepCollectionEquality() + .equals(other.isHearingImpaired, isHearingImpaired)) && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(language) ^ + const DeepCollectionEquality().hash(format) ^ + const DeepCollectionEquality().hash(isForced) ^ + const DeepCollectionEquality().hash(isHearingImpaired) ^ + const DeepCollectionEquality().hash(data) ^ + runtimeType.hashCode; +} + +extension $UploadSubtitleDtoExtension on UploadSubtitleDto { + UploadSubtitleDto copyWith( + {String? language, + String? format, + bool? isForced, + bool? isHearingImpaired, + String? data}) { + return UploadSubtitleDto( + language: language ?? this.language, + format: format ?? this.format, + isForced: isForced ?? this.isForced, + isHearingImpaired: isHearingImpaired ?? this.isHearingImpaired, + data: data ?? this.data); + } + + UploadSubtitleDto copyWithWrapped( + {Wrapped? language, + Wrapped? format, + Wrapped? isForced, + Wrapped? isHearingImpaired, + Wrapped? data}) { + return UploadSubtitleDto( + language: (language != null ? language.value : this.language), + format: (format != null ? format.value : this.format), + isForced: (isForced != null ? isForced.value : this.isForced), + isHearingImpaired: (isHearingImpaired != null + ? isHearingImpaired.value + : this.isHearingImpaired), + data: (data != null ? data.value : this.data)); + } +} + +@JsonSerializable(explicitToJson: true) +class UserConfiguration { + const UserConfiguration({ + this.audioLanguagePreference, + this.playDefaultAudioTrack, + this.subtitleLanguagePreference, + this.displayMissingEpisodes, + this.groupedFolders, + this.subtitleMode, + this.displayCollectionsView, + this.enableLocalPassword, + this.orderedViews, + this.latestItemsExcludes, + this.myMediaExcludes, + this.hidePlayedInLatest, + this.rememberAudioSelections, + this.rememberSubtitleSelections, + this.enableNextEpisodeAutoPlay, + this.castReceiverId, + }); + + factory UserConfiguration.fromJson(Map json) => + _$UserConfigurationFromJson(json); + + static const toJsonFactory = _$UserConfigurationToJson; + Map toJson() => _$UserConfigurationToJson(this); + + @JsonKey(name: 'AudioLanguagePreference', includeIfNull: false) + final String? audioLanguagePreference; + @JsonKey(name: 'PlayDefaultAudioTrack', includeIfNull: false) + final bool? playDefaultAudioTrack; + @JsonKey(name: 'SubtitleLanguagePreference', includeIfNull: false) + final String? subtitleLanguagePreference; + @JsonKey(name: 'DisplayMissingEpisodes', includeIfNull: false) + final bool? displayMissingEpisodes; + @JsonKey( + name: 'GroupedFolders', includeIfNull: false, defaultValue: []) + final List? groupedFolders; + @JsonKey( + name: 'SubtitleMode', + includeIfNull: false, + toJson: subtitlePlaybackModeNullableToJson, + fromJson: subtitlePlaybackModeNullableFromJson, + ) + final enums.SubtitlePlaybackMode? subtitleMode; + @JsonKey(name: 'DisplayCollectionsView', includeIfNull: false) + final bool? displayCollectionsView; + @JsonKey(name: 'EnableLocalPassword', includeIfNull: false) + final bool? enableLocalPassword; + @JsonKey(name: 'OrderedViews', includeIfNull: false, defaultValue: []) + final List? orderedViews; + @JsonKey( + name: 'LatestItemsExcludes', + includeIfNull: false, + defaultValue: []) + final List? latestItemsExcludes; + @JsonKey( + name: 'MyMediaExcludes', includeIfNull: false, defaultValue: []) + final List? myMediaExcludes; + @JsonKey(name: 'HidePlayedInLatest', includeIfNull: false) + final bool? hidePlayedInLatest; + @JsonKey(name: 'RememberAudioSelections', includeIfNull: false) + final bool? rememberAudioSelections; + @JsonKey(name: 'RememberSubtitleSelections', includeIfNull: false) + final bool? rememberSubtitleSelections; + @JsonKey(name: 'EnableNextEpisodeAutoPlay', includeIfNull: false) + final bool? enableNextEpisodeAutoPlay; + @JsonKey(name: 'CastReceiverId', includeIfNull: false) + final String? castReceiverId; + static const fromJsonFactory = _$UserConfigurationFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is UserConfiguration && + (identical(other.audioLanguagePreference, audioLanguagePreference) || + const DeepCollectionEquality().equals( + other.audioLanguagePreference, audioLanguagePreference)) && + (identical(other.playDefaultAudioTrack, playDefaultAudioTrack) || + const DeepCollectionEquality().equals( + other.playDefaultAudioTrack, playDefaultAudioTrack)) && + (identical(other.subtitleLanguagePreference, subtitleLanguagePreference) || + const DeepCollectionEquality().equals( + other.subtitleLanguagePreference, + subtitleLanguagePreference)) && + (identical(other.displayMissingEpisodes, displayMissingEpisodes) || + const DeepCollectionEquality().equals( + other.displayMissingEpisodes, displayMissingEpisodes)) && + (identical(other.groupedFolders, groupedFolders) || + const DeepCollectionEquality() + .equals(other.groupedFolders, groupedFolders)) && + (identical(other.subtitleMode, subtitleMode) || + const DeepCollectionEquality() + .equals(other.subtitleMode, subtitleMode)) && + (identical(other.displayCollectionsView, displayCollectionsView) || + const DeepCollectionEquality().equals( + other.displayCollectionsView, displayCollectionsView)) && + (identical(other.enableLocalPassword, enableLocalPassword) || + const DeepCollectionEquality() + .equals(other.enableLocalPassword, enableLocalPassword)) && + (identical(other.orderedViews, orderedViews) || + const DeepCollectionEquality() + .equals(other.orderedViews, orderedViews)) && + (identical(other.latestItemsExcludes, latestItemsExcludes) || + const DeepCollectionEquality() + .equals(other.latestItemsExcludes, latestItemsExcludes)) && + (identical(other.myMediaExcludes, myMediaExcludes) || + const DeepCollectionEquality() + .equals(other.myMediaExcludes, myMediaExcludes)) && + (identical(other.hidePlayedInLatest, hidePlayedInLatest) || + const DeepCollectionEquality() + .equals(other.hidePlayedInLatest, hidePlayedInLatest)) && + (identical(other.rememberAudioSelections, rememberAudioSelections) || + const DeepCollectionEquality().equals(other.rememberAudioSelections, rememberAudioSelections)) && + (identical(other.rememberSubtitleSelections, rememberSubtitleSelections) || const DeepCollectionEquality().equals(other.rememberSubtitleSelections, rememberSubtitleSelections)) && + (identical(other.enableNextEpisodeAutoPlay, enableNextEpisodeAutoPlay) || const DeepCollectionEquality().equals(other.enableNextEpisodeAutoPlay, enableNextEpisodeAutoPlay)) && + (identical(other.castReceiverId, castReceiverId) || const DeepCollectionEquality().equals(other.castReceiverId, castReceiverId))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(audioLanguagePreference) ^ + const DeepCollectionEquality().hash(playDefaultAudioTrack) ^ + const DeepCollectionEquality().hash(subtitleLanguagePreference) ^ + const DeepCollectionEquality().hash(displayMissingEpisodes) ^ + const DeepCollectionEquality().hash(groupedFolders) ^ + const DeepCollectionEquality().hash(subtitleMode) ^ + const DeepCollectionEquality().hash(displayCollectionsView) ^ + const DeepCollectionEquality().hash(enableLocalPassword) ^ + const DeepCollectionEquality().hash(orderedViews) ^ + const DeepCollectionEquality().hash(latestItemsExcludes) ^ + const DeepCollectionEquality().hash(myMediaExcludes) ^ + const DeepCollectionEquality().hash(hidePlayedInLatest) ^ + const DeepCollectionEquality().hash(rememberAudioSelections) ^ + const DeepCollectionEquality().hash(rememberSubtitleSelections) ^ + const DeepCollectionEquality().hash(enableNextEpisodeAutoPlay) ^ + const DeepCollectionEquality().hash(castReceiverId) ^ + runtimeType.hashCode; +} + +extension $UserConfigurationExtension on UserConfiguration { + UserConfiguration copyWith( + {String? audioLanguagePreference, + bool? playDefaultAudioTrack, + String? subtitleLanguagePreference, + bool? displayMissingEpisodes, + List? groupedFolders, + enums.SubtitlePlaybackMode? subtitleMode, + bool? displayCollectionsView, + bool? enableLocalPassword, + List? orderedViews, + List? latestItemsExcludes, + List? myMediaExcludes, + bool? hidePlayedInLatest, + bool? rememberAudioSelections, + bool? rememberSubtitleSelections, + bool? enableNextEpisodeAutoPlay, + String? castReceiverId}) { + return UserConfiguration( + audioLanguagePreference: + audioLanguagePreference ?? this.audioLanguagePreference, + playDefaultAudioTrack: + playDefaultAudioTrack ?? this.playDefaultAudioTrack, + subtitleLanguagePreference: + subtitleLanguagePreference ?? this.subtitleLanguagePreference, + displayMissingEpisodes: + displayMissingEpisodes ?? this.displayMissingEpisodes, + groupedFolders: groupedFolders ?? this.groupedFolders, + subtitleMode: subtitleMode ?? this.subtitleMode, + displayCollectionsView: + displayCollectionsView ?? this.displayCollectionsView, + enableLocalPassword: enableLocalPassword ?? this.enableLocalPassword, + orderedViews: orderedViews ?? this.orderedViews, + latestItemsExcludes: latestItemsExcludes ?? this.latestItemsExcludes, + myMediaExcludes: myMediaExcludes ?? this.myMediaExcludes, + hidePlayedInLatest: hidePlayedInLatest ?? this.hidePlayedInLatest, + rememberAudioSelections: + rememberAudioSelections ?? this.rememberAudioSelections, + rememberSubtitleSelections: + rememberSubtitleSelections ?? this.rememberSubtitleSelections, + enableNextEpisodeAutoPlay: + enableNextEpisodeAutoPlay ?? this.enableNextEpisodeAutoPlay, + castReceiverId: castReceiverId ?? this.castReceiverId); + } + + UserConfiguration copyWithWrapped( + {Wrapped? audioLanguagePreference, + Wrapped? playDefaultAudioTrack, + Wrapped? subtitleLanguagePreference, + Wrapped? displayMissingEpisodes, + Wrapped?>? groupedFolders, + Wrapped? subtitleMode, + Wrapped? displayCollectionsView, + Wrapped? enableLocalPassword, + Wrapped?>? orderedViews, + Wrapped?>? latestItemsExcludes, + Wrapped?>? myMediaExcludes, + Wrapped? hidePlayedInLatest, + Wrapped? rememberAudioSelections, + Wrapped? rememberSubtitleSelections, + Wrapped? enableNextEpisodeAutoPlay, + Wrapped? castReceiverId}) { + return UserConfiguration( + audioLanguagePreference: (audioLanguagePreference != null + ? audioLanguagePreference.value + : this.audioLanguagePreference), + playDefaultAudioTrack: (playDefaultAudioTrack != null + ? playDefaultAudioTrack.value + : this.playDefaultAudioTrack), + subtitleLanguagePreference: (subtitleLanguagePreference != null + ? subtitleLanguagePreference.value + : this.subtitleLanguagePreference), + displayMissingEpisodes: (displayMissingEpisodes != null + ? displayMissingEpisodes.value + : this.displayMissingEpisodes), + groupedFolders: (groupedFolders != null + ? groupedFolders.value + : this.groupedFolders), + subtitleMode: + (subtitleMode != null ? subtitleMode.value : this.subtitleMode), + displayCollectionsView: (displayCollectionsView != null + ? displayCollectionsView.value + : this.displayCollectionsView), + enableLocalPassword: (enableLocalPassword != null + ? enableLocalPassword.value + : this.enableLocalPassword), + orderedViews: + (orderedViews != null ? orderedViews.value : this.orderedViews), + latestItemsExcludes: (latestItemsExcludes != null + ? latestItemsExcludes.value + : this.latestItemsExcludes), + myMediaExcludes: (myMediaExcludes != null + ? myMediaExcludes.value + : this.myMediaExcludes), + hidePlayedInLatest: (hidePlayedInLatest != null + ? hidePlayedInLatest.value + : this.hidePlayedInLatest), + rememberAudioSelections: (rememberAudioSelections != null + ? rememberAudioSelections.value + : this.rememberAudioSelections), + rememberSubtitleSelections: (rememberSubtitleSelections != null + ? rememberSubtitleSelections.value + : this.rememberSubtitleSelections), + enableNextEpisodeAutoPlay: (enableNextEpisodeAutoPlay != null + ? enableNextEpisodeAutoPlay.value + : this.enableNextEpisodeAutoPlay), + castReceiverId: (castReceiverId != null + ? castReceiverId.value + : this.castReceiverId)); + } +} + +@JsonSerializable(explicitToJson: true) +class UserDataChangedMessage { + const UserDataChangedMessage({ + this.data, + this.messageId, + this.messageType, + }); + + factory UserDataChangedMessage.fromJson(Map json) => + _$UserDataChangedMessageFromJson(json); + + static const toJsonFactory = _$UserDataChangedMessageToJson; + Map toJson() => _$UserDataChangedMessageToJson(this); + + @JsonKey(name: 'Data', includeIfNull: false) + final UserDataChangeInfo? data; + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.userdatachanged); + + static const fromJsonFactory = _$UserDataChangedMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is UserDataChangedMessage && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data)) && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(data) ^ + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $UserDataChangedMessageExtension on UserDataChangedMessage { + UserDataChangedMessage copyWith( + {UserDataChangeInfo? data, + String? messageId, + enums.SessionMessageType? messageType}) { + return UserDataChangedMessage( + data: data ?? this.data, + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + UserDataChangedMessage copyWithWrapped( + {Wrapped? data, + Wrapped? messageId, + Wrapped? messageType}) { + return UserDataChangedMessage( + data: (data != null ? data.value : this.data), + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class UserDataChangeInfo { + const UserDataChangeInfo({ + this.userId, + this.userDataList, + }); + + factory UserDataChangeInfo.fromJson(Map json) => + _$UserDataChangeInfoFromJson(json); + + static const toJsonFactory = _$UserDataChangeInfoToJson; + Map toJson() => _$UserDataChangeInfoToJson(this); + + @JsonKey(name: 'UserId', includeIfNull: false) + final String? userId; + @JsonKey( + name: 'UserDataList', + includeIfNull: false, + defaultValue: []) + final List? userDataList; + static const fromJsonFactory = _$UserDataChangeInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is UserDataChangeInfo && + (identical(other.userId, userId) || + const DeepCollectionEquality().equals(other.userId, userId)) && + (identical(other.userDataList, userDataList) || + const DeepCollectionEquality() + .equals(other.userDataList, userDataList))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(userId) ^ + const DeepCollectionEquality().hash(userDataList) ^ + runtimeType.hashCode; +} + +extension $UserDataChangeInfoExtension on UserDataChangeInfo { + UserDataChangeInfo copyWith( + {String? userId, List? userDataList}) { + return UserDataChangeInfo( + userId: userId ?? this.userId, + userDataList: userDataList ?? this.userDataList); + } + + UserDataChangeInfo copyWithWrapped( + {Wrapped? userId, + Wrapped?>? userDataList}) { + return UserDataChangeInfo( + userId: (userId != null ? userId.value : this.userId), + userDataList: + (userDataList != null ? userDataList.value : this.userDataList)); + } +} + +@JsonSerializable(explicitToJson: true) +class UserDeletedMessage { + const UserDeletedMessage({ + this.data, + this.messageId, + this.messageType, + }); + + factory UserDeletedMessage.fromJson(Map json) => + _$UserDeletedMessageFromJson(json); + + static const toJsonFactory = _$UserDeletedMessageToJson; + Map toJson() => _$UserDeletedMessageToJson(this); + + @JsonKey(name: 'Data', includeIfNull: false) + final String? data; + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.userdeleted); + + static const fromJsonFactory = _$UserDeletedMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is UserDeletedMessage && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data)) && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(data) ^ + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $UserDeletedMessageExtension on UserDeletedMessage { + UserDeletedMessage copyWith( + {String? data, + String? messageId, + enums.SessionMessageType? messageType}) { + return UserDeletedMessage( + data: data ?? this.data, + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + UserDeletedMessage copyWithWrapped( + {Wrapped? data, + Wrapped? messageId, + Wrapped? messageType}) { + return UserDeletedMessage( + data: (data != null ? data.value : this.data), + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class UserDto { + const UserDto({ + this.name, + this.serverId, + this.serverName, + this.id, + this.primaryImageTag, + this.hasPassword, + this.hasConfiguredPassword, + this.hasConfiguredEasyPassword, + this.enableAutoLogin, + this.lastLoginDate, + this.lastActivityDate, + this.configuration, + this.policy, + this.primaryImageAspectRatio, + }); + + factory UserDto.fromJson(Map json) => + _$UserDtoFromJson(json); + + static const toJsonFactory = _$UserDtoToJson; + Map toJson() => _$UserDtoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'ServerId', includeIfNull: false) + final String? serverId; + @JsonKey(name: 'ServerName', includeIfNull: false) + final String? serverName; + @JsonKey(name: 'Id', includeIfNull: false) + final String? id; + @JsonKey(name: 'PrimaryImageTag', includeIfNull: false) + final String? primaryImageTag; + @JsonKey(name: 'HasPassword', includeIfNull: false) + final bool? hasPassword; + @JsonKey(name: 'HasConfiguredPassword', includeIfNull: false) + final bool? hasConfiguredPassword; + @JsonKey(name: 'HasConfiguredEasyPassword', includeIfNull: false) + @deprecated + final bool? hasConfiguredEasyPassword; + @JsonKey(name: 'EnableAutoLogin', includeIfNull: false) + final bool? enableAutoLogin; + @JsonKey(name: 'LastLoginDate', includeIfNull: false) + final DateTime? lastLoginDate; + @JsonKey(name: 'LastActivityDate', includeIfNull: false) + final DateTime? lastActivityDate; + @JsonKey(name: 'Configuration', includeIfNull: false) + final UserConfiguration? configuration; + @JsonKey(name: 'Policy', includeIfNull: false) + final UserPolicy? policy; + @JsonKey(name: 'PrimaryImageAspectRatio', includeIfNull: false) + final double? primaryImageAspectRatio; + static const fromJsonFactory = _$UserDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is UserDto && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.serverId, serverId) || + const DeepCollectionEquality() + .equals(other.serverId, serverId)) && + (identical(other.serverName, serverName) || + const DeepCollectionEquality() + .equals(other.serverName, serverName)) && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.primaryImageTag, primaryImageTag) || + const DeepCollectionEquality() + .equals(other.primaryImageTag, primaryImageTag)) && + (identical(other.hasPassword, hasPassword) || + const DeepCollectionEquality() + .equals(other.hasPassword, hasPassword)) && + (identical(other.hasConfiguredPassword, hasConfiguredPassword) || + const DeepCollectionEquality().equals( + other.hasConfiguredPassword, hasConfiguredPassword)) && + (identical(other.hasConfiguredEasyPassword, + hasConfiguredEasyPassword) || + const DeepCollectionEquality().equals( + other.hasConfiguredEasyPassword, + hasConfiguredEasyPassword)) && + (identical(other.enableAutoLogin, enableAutoLogin) || + const DeepCollectionEquality() + .equals(other.enableAutoLogin, enableAutoLogin)) && + (identical(other.lastLoginDate, lastLoginDate) || + const DeepCollectionEquality() + .equals(other.lastLoginDate, lastLoginDate)) && + (identical(other.lastActivityDate, lastActivityDate) || + const DeepCollectionEquality() + .equals(other.lastActivityDate, lastActivityDate)) && + (identical(other.configuration, configuration) || + const DeepCollectionEquality() + .equals(other.configuration, configuration)) && + (identical(other.policy, policy) || + const DeepCollectionEquality().equals(other.policy, policy)) && + (identical( + other.primaryImageAspectRatio, primaryImageAspectRatio) || + const DeepCollectionEquality().equals( + other.primaryImageAspectRatio, primaryImageAspectRatio))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(serverId) ^ + const DeepCollectionEquality().hash(serverName) ^ + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(primaryImageTag) ^ + const DeepCollectionEquality().hash(hasPassword) ^ + const DeepCollectionEquality().hash(hasConfiguredPassword) ^ + const DeepCollectionEquality().hash(hasConfiguredEasyPassword) ^ + const DeepCollectionEquality().hash(enableAutoLogin) ^ + const DeepCollectionEquality().hash(lastLoginDate) ^ + const DeepCollectionEquality().hash(lastActivityDate) ^ + const DeepCollectionEquality().hash(configuration) ^ + const DeepCollectionEquality().hash(policy) ^ + const DeepCollectionEquality().hash(primaryImageAspectRatio) ^ + runtimeType.hashCode; +} + +extension $UserDtoExtension on UserDto { + UserDto copyWith( + {String? name, + String? serverId, + String? serverName, + String? id, + String? primaryImageTag, + bool? hasPassword, + bool? hasConfiguredPassword, + bool? hasConfiguredEasyPassword, + bool? enableAutoLogin, + DateTime? lastLoginDate, + DateTime? lastActivityDate, + UserConfiguration? configuration, + UserPolicy? policy, + double? primaryImageAspectRatio}) { + return UserDto( + name: name ?? this.name, + serverId: serverId ?? this.serverId, + serverName: serverName ?? this.serverName, + id: id ?? this.id, + primaryImageTag: primaryImageTag ?? this.primaryImageTag, + hasPassword: hasPassword ?? this.hasPassword, + hasConfiguredPassword: + hasConfiguredPassword ?? this.hasConfiguredPassword, + hasConfiguredEasyPassword: + hasConfiguredEasyPassword ?? this.hasConfiguredEasyPassword, + enableAutoLogin: enableAutoLogin ?? this.enableAutoLogin, + lastLoginDate: lastLoginDate ?? this.lastLoginDate, + lastActivityDate: lastActivityDate ?? this.lastActivityDate, + configuration: configuration ?? this.configuration, + policy: policy ?? this.policy, + primaryImageAspectRatio: + primaryImageAspectRatio ?? this.primaryImageAspectRatio); + } + + UserDto copyWithWrapped( + {Wrapped? name, + Wrapped? serverId, + Wrapped? serverName, + Wrapped? id, + Wrapped? primaryImageTag, + Wrapped? hasPassword, + Wrapped? hasConfiguredPassword, + Wrapped? hasConfiguredEasyPassword, + Wrapped? enableAutoLogin, + Wrapped? lastLoginDate, + Wrapped? lastActivityDate, + Wrapped? configuration, + Wrapped? policy, + Wrapped? primaryImageAspectRatio}) { + return UserDto( + name: (name != null ? name.value : this.name), + serverId: (serverId != null ? serverId.value : this.serverId), + serverName: (serverName != null ? serverName.value : this.serverName), + id: (id != null ? id.value : this.id), + primaryImageTag: (primaryImageTag != null + ? primaryImageTag.value + : this.primaryImageTag), + hasPassword: + (hasPassword != null ? hasPassword.value : this.hasPassword), + hasConfiguredPassword: (hasConfiguredPassword != null + ? hasConfiguredPassword.value + : this.hasConfiguredPassword), + hasConfiguredEasyPassword: (hasConfiguredEasyPassword != null + ? hasConfiguredEasyPassword.value + : this.hasConfiguredEasyPassword), + enableAutoLogin: (enableAutoLogin != null + ? enableAutoLogin.value + : this.enableAutoLogin), + lastLoginDate: + (lastLoginDate != null ? lastLoginDate.value : this.lastLoginDate), + lastActivityDate: (lastActivityDate != null + ? lastActivityDate.value + : this.lastActivityDate), + configuration: + (configuration != null ? configuration.value : this.configuration), + policy: (policy != null ? policy.value : this.policy), + primaryImageAspectRatio: (primaryImageAspectRatio != null + ? primaryImageAspectRatio.value + : this.primaryImageAspectRatio)); + } +} + +@JsonSerializable(explicitToJson: true) +class UserInterfaceConfiguration { + const UserInterfaceConfiguration({ + this.skipButtonVisible, + this.skipButtonIntroText, + this.skipButtonEndCreditsText, + }); + + factory UserInterfaceConfiguration.fromJson(Map json) => + _$UserInterfaceConfigurationFromJson(json); + + static const toJsonFactory = _$UserInterfaceConfigurationToJson; + Map toJson() => _$UserInterfaceConfigurationToJson(this); + + @JsonKey(name: 'SkipButtonVisible', includeIfNull: false) + final bool? skipButtonVisible; + @JsonKey(name: 'SkipButtonIntroText', includeIfNull: false) + final String? skipButtonIntroText; + @JsonKey(name: 'SkipButtonEndCreditsText', includeIfNull: false) + final String? skipButtonEndCreditsText; + static const fromJsonFactory = _$UserInterfaceConfigurationFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is UserInterfaceConfiguration && + (identical(other.skipButtonVisible, skipButtonVisible) || + const DeepCollectionEquality() + .equals(other.skipButtonVisible, skipButtonVisible)) && + (identical(other.skipButtonIntroText, skipButtonIntroText) || + const DeepCollectionEquality() + .equals(other.skipButtonIntroText, skipButtonIntroText)) && + (identical( + other.skipButtonEndCreditsText, skipButtonEndCreditsText) || + const DeepCollectionEquality().equals( + other.skipButtonEndCreditsText, skipButtonEndCreditsText))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(skipButtonVisible) ^ + const DeepCollectionEquality().hash(skipButtonIntroText) ^ + const DeepCollectionEquality().hash(skipButtonEndCreditsText) ^ + runtimeType.hashCode; +} + +extension $UserInterfaceConfigurationExtension on UserInterfaceConfiguration { + UserInterfaceConfiguration copyWith( + {bool? skipButtonVisible, + String? skipButtonIntroText, + String? skipButtonEndCreditsText}) { + return UserInterfaceConfiguration( + skipButtonVisible: skipButtonVisible ?? this.skipButtonVisible, + skipButtonIntroText: skipButtonIntroText ?? this.skipButtonIntroText, + skipButtonEndCreditsText: + skipButtonEndCreditsText ?? this.skipButtonEndCreditsText); + } + + UserInterfaceConfiguration copyWithWrapped( + {Wrapped? skipButtonVisible, + Wrapped? skipButtonIntroText, + Wrapped? skipButtonEndCreditsText}) { + return UserInterfaceConfiguration( + skipButtonVisible: (skipButtonVisible != null + ? skipButtonVisible.value + : this.skipButtonVisible), + skipButtonIntroText: (skipButtonIntroText != null + ? skipButtonIntroText.value + : this.skipButtonIntroText), + skipButtonEndCreditsText: (skipButtonEndCreditsText != null + ? skipButtonEndCreditsText.value + : this.skipButtonEndCreditsText)); + } +} + +@JsonSerializable(explicitToJson: true) +class UserItemDataDto { + const UserItemDataDto({ + this.rating, + this.playedPercentage, + this.unplayedItemCount, + this.playbackPositionTicks, + this.playCount, + this.isFavorite, + this.likes, + this.lastPlayedDate, + this.played, + this.key, + this.itemId, + }); + + factory UserItemDataDto.fromJson(Map json) => + _$UserItemDataDtoFromJson(json); + + static const toJsonFactory = _$UserItemDataDtoToJson; + Map toJson() => _$UserItemDataDtoToJson(this); + + @JsonKey(name: 'Rating', includeIfNull: false) + final double? rating; + @JsonKey(name: 'PlayedPercentage', includeIfNull: false) + final double? playedPercentage; + @JsonKey(name: 'UnplayedItemCount', includeIfNull: false) + final int? unplayedItemCount; + @JsonKey(name: 'PlaybackPositionTicks', includeIfNull: false) + final int? playbackPositionTicks; + @JsonKey(name: 'PlayCount', includeIfNull: false) + final int? playCount; + @JsonKey(name: 'IsFavorite', includeIfNull: false) + final bool? isFavorite; + @JsonKey(name: 'Likes', includeIfNull: false) + final bool? likes; + @JsonKey(name: 'LastPlayedDate', includeIfNull: false) + final DateTime? lastPlayedDate; + @JsonKey(name: 'Played', includeIfNull: false) + final bool? played; + @JsonKey(name: 'Key', includeIfNull: false) + final String? key; + @JsonKey(name: 'ItemId', includeIfNull: false) + final String? itemId; + static const fromJsonFactory = _$UserItemDataDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is UserItemDataDto && + (identical(other.rating, rating) || + const DeepCollectionEquality().equals(other.rating, rating)) && + (identical(other.playedPercentage, playedPercentage) || + const DeepCollectionEquality() + .equals(other.playedPercentage, playedPercentage)) && + (identical(other.unplayedItemCount, unplayedItemCount) || + const DeepCollectionEquality() + .equals(other.unplayedItemCount, unplayedItemCount)) && + (identical(other.playbackPositionTicks, playbackPositionTicks) || + const DeepCollectionEquality().equals( + other.playbackPositionTicks, playbackPositionTicks)) && + (identical(other.playCount, playCount) || + const DeepCollectionEquality() + .equals(other.playCount, playCount)) && + (identical(other.isFavorite, isFavorite) || + const DeepCollectionEquality() + .equals(other.isFavorite, isFavorite)) && + (identical(other.likes, likes) || + const DeepCollectionEquality().equals(other.likes, likes)) && + (identical(other.lastPlayedDate, lastPlayedDate) || + const DeepCollectionEquality() + .equals(other.lastPlayedDate, lastPlayedDate)) && + (identical(other.played, played) || + const DeepCollectionEquality().equals(other.played, played)) && + (identical(other.key, key) || + const DeepCollectionEquality().equals(other.key, key)) && + (identical(other.itemId, itemId) || + const DeepCollectionEquality().equals(other.itemId, itemId))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(rating) ^ + const DeepCollectionEquality().hash(playedPercentage) ^ + const DeepCollectionEquality().hash(unplayedItemCount) ^ + const DeepCollectionEquality().hash(playbackPositionTicks) ^ + const DeepCollectionEquality().hash(playCount) ^ + const DeepCollectionEquality().hash(isFavorite) ^ + const DeepCollectionEquality().hash(likes) ^ + const DeepCollectionEquality().hash(lastPlayedDate) ^ + const DeepCollectionEquality().hash(played) ^ + const DeepCollectionEquality().hash(key) ^ + const DeepCollectionEquality().hash(itemId) ^ + runtimeType.hashCode; +} + +extension $UserItemDataDtoExtension on UserItemDataDto { + UserItemDataDto copyWith( + {double? rating, + double? playedPercentage, + int? unplayedItemCount, + int? playbackPositionTicks, + int? playCount, + bool? isFavorite, + bool? likes, + DateTime? lastPlayedDate, + bool? played, + String? key, + String? itemId}) { + return UserItemDataDto( + rating: rating ?? this.rating, + playedPercentage: playedPercentage ?? this.playedPercentage, + unplayedItemCount: unplayedItemCount ?? this.unplayedItemCount, + playbackPositionTicks: + playbackPositionTicks ?? this.playbackPositionTicks, + playCount: playCount ?? this.playCount, + isFavorite: isFavorite ?? this.isFavorite, + likes: likes ?? this.likes, + lastPlayedDate: lastPlayedDate ?? this.lastPlayedDate, + played: played ?? this.played, + key: key ?? this.key, + itemId: itemId ?? this.itemId); + } + + UserItemDataDto copyWithWrapped( + {Wrapped? rating, + Wrapped? playedPercentage, + Wrapped? unplayedItemCount, + Wrapped? playbackPositionTicks, + Wrapped? playCount, + Wrapped? isFavorite, + Wrapped? likes, + Wrapped? lastPlayedDate, + Wrapped? played, + Wrapped? key, + Wrapped? itemId}) { + return UserItemDataDto( + rating: (rating != null ? rating.value : this.rating), + playedPercentage: (playedPercentage != null + ? playedPercentage.value + : this.playedPercentage), + unplayedItemCount: (unplayedItemCount != null + ? unplayedItemCount.value + : this.unplayedItemCount), + playbackPositionTicks: (playbackPositionTicks != null + ? playbackPositionTicks.value + : this.playbackPositionTicks), + playCount: (playCount != null ? playCount.value : this.playCount), + isFavorite: (isFavorite != null ? isFavorite.value : this.isFavorite), + likes: (likes != null ? likes.value : this.likes), + lastPlayedDate: (lastPlayedDate != null + ? lastPlayedDate.value + : this.lastPlayedDate), + played: (played != null ? played.value : this.played), + key: (key != null ? key.value : this.key), + itemId: (itemId != null ? itemId.value : this.itemId)); + } +} + +@JsonSerializable(explicitToJson: true) +class UserPolicy { + const UserPolicy({ + this.isAdministrator, + this.isHidden, + this.enableCollectionManagement, + this.enableSubtitleManagement, + this.enableLyricManagement, + this.isDisabled, + this.maxParentalRating, + this.blockedTags, + this.allowedTags, + this.enableUserPreferenceAccess, + this.accessSchedules, + this.blockUnratedItems, + this.enableRemoteControlOfOtherUsers, + this.enableSharedDeviceControl, + this.enableRemoteAccess, + this.enableLiveTvManagement, + this.enableLiveTvAccess, + this.enableMediaPlayback, + this.enableAudioPlaybackTranscoding, + this.enableVideoPlaybackTranscoding, + this.enablePlaybackRemuxing, + this.forceRemoteSourceTranscoding, + this.enableContentDeletion, + this.enableContentDeletionFromFolders, + this.enableContentDownloading, + this.enableSyncTranscoding, + this.enableMediaConversion, + this.enabledDevices, + this.enableAllDevices, + this.enabledChannels, + this.enableAllChannels, + this.enabledFolders, + this.enableAllFolders, + this.invalidLoginAttemptCount, + this.loginAttemptsBeforeLockout, + this.maxActiveSessions, + this.enablePublicSharing, + this.blockedMediaFolders, + this.blockedChannels, + this.remoteClientBitrateLimit, + required this.authenticationProviderId, + required this.passwordResetProviderId, + this.syncPlayAccess, + }); + + factory UserPolicy.fromJson(Map json) => + _$UserPolicyFromJson(json); + + static const toJsonFactory = _$UserPolicyToJson; + Map toJson() => _$UserPolicyToJson(this); + + @JsonKey(name: 'IsAdministrator', includeIfNull: false) + final bool? isAdministrator; + @JsonKey(name: 'IsHidden', includeIfNull: false) + final bool? isHidden; + @JsonKey( + name: 'EnableCollectionManagement', + includeIfNull: false, + defaultValue: false) + final bool? enableCollectionManagement; + @JsonKey( + name: 'EnableSubtitleManagement', + includeIfNull: false, + defaultValue: false) + final bool? enableSubtitleManagement; + @JsonKey( + name: 'EnableLyricManagement', includeIfNull: false, defaultValue: false) + final bool? enableLyricManagement; + @JsonKey(name: 'IsDisabled', includeIfNull: false) + final bool? isDisabled; + @JsonKey(name: 'MaxParentalRating', includeIfNull: false) + final int? maxParentalRating; + @JsonKey(name: 'BlockedTags', includeIfNull: false, defaultValue: []) + final List? blockedTags; + @JsonKey(name: 'AllowedTags', includeIfNull: false, defaultValue: []) + final List? allowedTags; + @JsonKey(name: 'EnableUserPreferenceAccess', includeIfNull: false) + final bool? enableUserPreferenceAccess; + @JsonKey( + name: 'AccessSchedules', + includeIfNull: false, + defaultValue: []) + final List? accessSchedules; + @JsonKey( + name: 'BlockUnratedItems', + includeIfNull: false, + toJson: unratedItemListToJson, + fromJson: unratedItemListFromJson, + ) + final List? blockUnratedItems; + @JsonKey(name: 'EnableRemoteControlOfOtherUsers', includeIfNull: false) + final bool? enableRemoteControlOfOtherUsers; + @JsonKey(name: 'EnableSharedDeviceControl', includeIfNull: false) + final bool? enableSharedDeviceControl; + @JsonKey(name: 'EnableRemoteAccess', includeIfNull: false) + final bool? enableRemoteAccess; + @JsonKey(name: 'EnableLiveTvManagement', includeIfNull: false) + final bool? enableLiveTvManagement; + @JsonKey(name: 'EnableLiveTvAccess', includeIfNull: false) + final bool? enableLiveTvAccess; + @JsonKey(name: 'EnableMediaPlayback', includeIfNull: false) + final bool? enableMediaPlayback; + @JsonKey(name: 'EnableAudioPlaybackTranscoding', includeIfNull: false) + final bool? enableAudioPlaybackTranscoding; + @JsonKey(name: 'EnableVideoPlaybackTranscoding', includeIfNull: false) + final bool? enableVideoPlaybackTranscoding; + @JsonKey(name: 'EnablePlaybackRemuxing', includeIfNull: false) + final bool? enablePlaybackRemuxing; + @JsonKey(name: 'ForceRemoteSourceTranscoding', includeIfNull: false) + final bool? forceRemoteSourceTranscoding; + @JsonKey(name: 'EnableContentDeletion', includeIfNull: false) + final bool? enableContentDeletion; + @JsonKey( + name: 'EnableContentDeletionFromFolders', + includeIfNull: false, + defaultValue: []) + final List? enableContentDeletionFromFolders; + @JsonKey(name: 'EnableContentDownloading', includeIfNull: false) + final bool? enableContentDownloading; + @JsonKey(name: 'EnableSyncTranscoding', includeIfNull: false) + final bool? enableSyncTranscoding; + @JsonKey(name: 'EnableMediaConversion', includeIfNull: false) + final bool? enableMediaConversion; + @JsonKey( + name: 'EnabledDevices', includeIfNull: false, defaultValue: []) + final List? enabledDevices; + @JsonKey(name: 'EnableAllDevices', includeIfNull: false) + final bool? enableAllDevices; + @JsonKey( + name: 'EnabledChannels', includeIfNull: false, defaultValue: []) + final List? enabledChannels; + @JsonKey(name: 'EnableAllChannels', includeIfNull: false) + final bool? enableAllChannels; + @JsonKey( + name: 'EnabledFolders', includeIfNull: false, defaultValue: []) + final List? enabledFolders; + @JsonKey(name: 'EnableAllFolders', includeIfNull: false) + final bool? enableAllFolders; + @JsonKey(name: 'InvalidLoginAttemptCount', includeIfNull: false) + final int? invalidLoginAttemptCount; + @JsonKey(name: 'LoginAttemptsBeforeLockout', includeIfNull: false) + final int? loginAttemptsBeforeLockout; + @JsonKey(name: 'MaxActiveSessions', includeIfNull: false) + final int? maxActiveSessions; + @JsonKey(name: 'EnablePublicSharing', includeIfNull: false) + final bool? enablePublicSharing; + @JsonKey( + name: 'BlockedMediaFolders', + includeIfNull: false, + defaultValue: []) + final List? blockedMediaFolders; + @JsonKey( + name: 'BlockedChannels', includeIfNull: false, defaultValue: []) + final List? blockedChannels; + @JsonKey(name: 'RemoteClientBitrateLimit', includeIfNull: false) + final int? remoteClientBitrateLimit; + @JsonKey(name: 'AuthenticationProviderId', includeIfNull: false) + final String authenticationProviderId; + @JsonKey(name: 'PasswordResetProviderId', includeIfNull: false) + final String passwordResetProviderId; + @JsonKey( + name: 'SyncPlayAccess', + includeIfNull: false, + toJson: syncPlayUserAccessTypeNullableToJson, + fromJson: syncPlayUserAccessTypeNullableFromJson, + ) + final enums.SyncPlayUserAccessType? syncPlayAccess; + static const fromJsonFactory = _$UserPolicyFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is UserPolicy && + (identical(other.isAdministrator, isAdministrator) || + const DeepCollectionEquality() + .equals(other.isAdministrator, isAdministrator)) && + (identical(other.isHidden, isHidden) || + const DeepCollectionEquality() + .equals(other.isHidden, isHidden)) && + (identical(other.enableCollectionManagement, enableCollectionManagement) || + const DeepCollectionEquality().equals( + other.enableCollectionManagement, + enableCollectionManagement)) && + (identical(other.enableSubtitleManagement, enableSubtitleManagement) || + const DeepCollectionEquality().equals( + other.enableSubtitleManagement, + enableSubtitleManagement)) && + (identical(other.enableLyricManagement, enableLyricManagement) || + const DeepCollectionEquality().equals( + other.enableLyricManagement, enableLyricManagement)) && + (identical(other.isDisabled, isDisabled) || + const DeepCollectionEquality() + .equals(other.isDisabled, isDisabled)) && + (identical(other.maxParentalRating, maxParentalRating) || + const DeepCollectionEquality() + .equals(other.maxParentalRating, maxParentalRating)) && + (identical(other.blockedTags, blockedTags) || + const DeepCollectionEquality() + .equals(other.blockedTags, blockedTags)) && + (identical(other.allowedTags, allowedTags) || + const DeepCollectionEquality() + .equals(other.allowedTags, allowedTags)) && + (identical(other.enableUserPreferenceAccess, enableUserPreferenceAccess) || + const DeepCollectionEquality().equals( + other.enableUserPreferenceAccess, + enableUserPreferenceAccess)) && + (identical(other.accessSchedules, accessSchedules) || + const DeepCollectionEquality() + .equals(other.accessSchedules, accessSchedules)) && + (identical(other.blockUnratedItems, blockUnratedItems) || + const DeepCollectionEquality() + .equals(other.blockUnratedItems, blockUnratedItems)) && + (identical(other.enableRemoteControlOfOtherUsers, enableRemoteControlOfOtherUsers) || + const DeepCollectionEquality().equals(other.enableRemoteControlOfOtherUsers, enableRemoteControlOfOtherUsers)) && + (identical(other.enableSharedDeviceControl, enableSharedDeviceControl) || const DeepCollectionEquality().equals(other.enableSharedDeviceControl, enableSharedDeviceControl)) && + (identical(other.enableRemoteAccess, enableRemoteAccess) || const DeepCollectionEquality().equals(other.enableRemoteAccess, enableRemoteAccess)) && + (identical(other.enableLiveTvManagement, enableLiveTvManagement) || const DeepCollectionEquality().equals(other.enableLiveTvManagement, enableLiveTvManagement)) && + (identical(other.enableLiveTvAccess, enableLiveTvAccess) || const DeepCollectionEquality().equals(other.enableLiveTvAccess, enableLiveTvAccess)) && + (identical(other.enableMediaPlayback, enableMediaPlayback) || const DeepCollectionEquality().equals(other.enableMediaPlayback, enableMediaPlayback)) && + (identical(other.enableAudioPlaybackTranscoding, enableAudioPlaybackTranscoding) || const DeepCollectionEquality().equals(other.enableAudioPlaybackTranscoding, enableAudioPlaybackTranscoding)) && + (identical(other.enableVideoPlaybackTranscoding, enableVideoPlaybackTranscoding) || const DeepCollectionEquality().equals(other.enableVideoPlaybackTranscoding, enableVideoPlaybackTranscoding)) && + (identical(other.enablePlaybackRemuxing, enablePlaybackRemuxing) || const DeepCollectionEquality().equals(other.enablePlaybackRemuxing, enablePlaybackRemuxing)) && + (identical(other.forceRemoteSourceTranscoding, forceRemoteSourceTranscoding) || const DeepCollectionEquality().equals(other.forceRemoteSourceTranscoding, forceRemoteSourceTranscoding)) && + (identical(other.enableContentDeletion, enableContentDeletion) || const DeepCollectionEquality().equals(other.enableContentDeletion, enableContentDeletion)) && + (identical(other.enableContentDeletionFromFolders, enableContentDeletionFromFolders) || const DeepCollectionEquality().equals(other.enableContentDeletionFromFolders, enableContentDeletionFromFolders)) && + (identical(other.enableContentDownloading, enableContentDownloading) || const DeepCollectionEquality().equals(other.enableContentDownloading, enableContentDownloading)) && + (identical(other.enableSyncTranscoding, enableSyncTranscoding) || const DeepCollectionEquality().equals(other.enableSyncTranscoding, enableSyncTranscoding)) && + (identical(other.enableMediaConversion, enableMediaConversion) || const DeepCollectionEquality().equals(other.enableMediaConversion, enableMediaConversion)) && + (identical(other.enabledDevices, enabledDevices) || const DeepCollectionEquality().equals(other.enabledDevices, enabledDevices)) && + (identical(other.enableAllDevices, enableAllDevices) || const DeepCollectionEquality().equals(other.enableAllDevices, enableAllDevices)) && + (identical(other.enabledChannels, enabledChannels) || const DeepCollectionEquality().equals(other.enabledChannels, enabledChannels)) && + (identical(other.enableAllChannels, enableAllChannels) || const DeepCollectionEquality().equals(other.enableAllChannels, enableAllChannels)) && + (identical(other.enabledFolders, enabledFolders) || const DeepCollectionEquality().equals(other.enabledFolders, enabledFolders)) && + (identical(other.enableAllFolders, enableAllFolders) || const DeepCollectionEquality().equals(other.enableAllFolders, enableAllFolders)) && + (identical(other.invalidLoginAttemptCount, invalidLoginAttemptCount) || const DeepCollectionEquality().equals(other.invalidLoginAttemptCount, invalidLoginAttemptCount)) && + (identical(other.loginAttemptsBeforeLockout, loginAttemptsBeforeLockout) || const DeepCollectionEquality().equals(other.loginAttemptsBeforeLockout, loginAttemptsBeforeLockout)) && + (identical(other.maxActiveSessions, maxActiveSessions) || const DeepCollectionEquality().equals(other.maxActiveSessions, maxActiveSessions)) && + (identical(other.enablePublicSharing, enablePublicSharing) || const DeepCollectionEquality().equals(other.enablePublicSharing, enablePublicSharing)) && + (identical(other.blockedMediaFolders, blockedMediaFolders) || const DeepCollectionEquality().equals(other.blockedMediaFolders, blockedMediaFolders)) && + (identical(other.blockedChannels, blockedChannels) || const DeepCollectionEquality().equals(other.blockedChannels, blockedChannels)) && + (identical(other.remoteClientBitrateLimit, remoteClientBitrateLimit) || const DeepCollectionEquality().equals(other.remoteClientBitrateLimit, remoteClientBitrateLimit)) && + (identical(other.authenticationProviderId, authenticationProviderId) || const DeepCollectionEquality().equals(other.authenticationProviderId, authenticationProviderId)) && + (identical(other.passwordResetProviderId, passwordResetProviderId) || const DeepCollectionEquality().equals(other.passwordResetProviderId, passwordResetProviderId)) && + (identical(other.syncPlayAccess, syncPlayAccess) || const DeepCollectionEquality().equals(other.syncPlayAccess, syncPlayAccess))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(isAdministrator) ^ + const DeepCollectionEquality().hash(isHidden) ^ + const DeepCollectionEquality().hash(enableCollectionManagement) ^ + const DeepCollectionEquality().hash(enableSubtitleManagement) ^ + const DeepCollectionEquality().hash(enableLyricManagement) ^ + const DeepCollectionEquality().hash(isDisabled) ^ + const DeepCollectionEquality().hash(maxParentalRating) ^ + const DeepCollectionEquality().hash(blockedTags) ^ + const DeepCollectionEquality().hash(allowedTags) ^ + const DeepCollectionEquality().hash(enableUserPreferenceAccess) ^ + const DeepCollectionEquality().hash(accessSchedules) ^ + const DeepCollectionEquality().hash(blockUnratedItems) ^ + const DeepCollectionEquality().hash(enableRemoteControlOfOtherUsers) ^ + const DeepCollectionEquality().hash(enableSharedDeviceControl) ^ + const DeepCollectionEquality().hash(enableRemoteAccess) ^ + const DeepCollectionEquality().hash(enableLiveTvManagement) ^ + const DeepCollectionEquality().hash(enableLiveTvAccess) ^ + const DeepCollectionEquality().hash(enableMediaPlayback) ^ + const DeepCollectionEquality().hash(enableAudioPlaybackTranscoding) ^ + const DeepCollectionEquality().hash(enableVideoPlaybackTranscoding) ^ + const DeepCollectionEquality().hash(enablePlaybackRemuxing) ^ + const DeepCollectionEquality().hash(forceRemoteSourceTranscoding) ^ + const DeepCollectionEquality().hash(enableContentDeletion) ^ + const DeepCollectionEquality().hash(enableContentDeletionFromFolders) ^ + const DeepCollectionEquality().hash(enableContentDownloading) ^ + const DeepCollectionEquality().hash(enableSyncTranscoding) ^ + const DeepCollectionEquality().hash(enableMediaConversion) ^ + const DeepCollectionEquality().hash(enabledDevices) ^ + const DeepCollectionEquality().hash(enableAllDevices) ^ + const DeepCollectionEquality().hash(enabledChannels) ^ + const DeepCollectionEquality().hash(enableAllChannels) ^ + const DeepCollectionEquality().hash(enabledFolders) ^ + const DeepCollectionEquality().hash(enableAllFolders) ^ + const DeepCollectionEquality().hash(invalidLoginAttemptCount) ^ + const DeepCollectionEquality().hash(loginAttemptsBeforeLockout) ^ + const DeepCollectionEquality().hash(maxActiveSessions) ^ + const DeepCollectionEquality().hash(enablePublicSharing) ^ + const DeepCollectionEquality().hash(blockedMediaFolders) ^ + const DeepCollectionEquality().hash(blockedChannels) ^ + const DeepCollectionEquality().hash(remoteClientBitrateLimit) ^ + const DeepCollectionEquality().hash(authenticationProviderId) ^ + const DeepCollectionEquality().hash(passwordResetProviderId) ^ + const DeepCollectionEquality().hash(syncPlayAccess) ^ + runtimeType.hashCode; +} + +extension $UserPolicyExtension on UserPolicy { + UserPolicy copyWith( + {bool? isAdministrator, + bool? isHidden, + bool? enableCollectionManagement, + bool? enableSubtitleManagement, + bool? enableLyricManagement, + bool? isDisabled, + int? maxParentalRating, + List? blockedTags, + List? allowedTags, + bool? enableUserPreferenceAccess, + List? accessSchedules, + List? blockUnratedItems, + bool? enableRemoteControlOfOtherUsers, + bool? enableSharedDeviceControl, + bool? enableRemoteAccess, + bool? enableLiveTvManagement, + bool? enableLiveTvAccess, + bool? enableMediaPlayback, + bool? enableAudioPlaybackTranscoding, + bool? enableVideoPlaybackTranscoding, + bool? enablePlaybackRemuxing, + bool? forceRemoteSourceTranscoding, + bool? enableContentDeletion, + List? enableContentDeletionFromFolders, + bool? enableContentDownloading, + bool? enableSyncTranscoding, + bool? enableMediaConversion, + List? enabledDevices, + bool? enableAllDevices, + List? enabledChannels, + bool? enableAllChannels, + List? enabledFolders, + bool? enableAllFolders, + int? invalidLoginAttemptCount, + int? loginAttemptsBeforeLockout, + int? maxActiveSessions, + bool? enablePublicSharing, + List? blockedMediaFolders, + List? blockedChannels, + int? remoteClientBitrateLimit, + String? authenticationProviderId, + String? passwordResetProviderId, + enums.SyncPlayUserAccessType? syncPlayAccess}) { + return UserPolicy( + isAdministrator: isAdministrator ?? this.isAdministrator, + isHidden: isHidden ?? this.isHidden, + enableCollectionManagement: + enableCollectionManagement ?? this.enableCollectionManagement, + enableSubtitleManagement: + enableSubtitleManagement ?? this.enableSubtitleManagement, + enableLyricManagement: + enableLyricManagement ?? this.enableLyricManagement, + isDisabled: isDisabled ?? this.isDisabled, + maxParentalRating: maxParentalRating ?? this.maxParentalRating, + blockedTags: blockedTags ?? this.blockedTags, + allowedTags: allowedTags ?? this.allowedTags, + enableUserPreferenceAccess: + enableUserPreferenceAccess ?? this.enableUserPreferenceAccess, + accessSchedules: accessSchedules ?? this.accessSchedules, + blockUnratedItems: blockUnratedItems ?? this.blockUnratedItems, + enableRemoteControlOfOtherUsers: enableRemoteControlOfOtherUsers ?? + this.enableRemoteControlOfOtherUsers, + enableSharedDeviceControl: + enableSharedDeviceControl ?? this.enableSharedDeviceControl, + enableRemoteAccess: enableRemoteAccess ?? this.enableRemoteAccess, + enableLiveTvManagement: + enableLiveTvManagement ?? this.enableLiveTvManagement, + enableLiveTvAccess: enableLiveTvAccess ?? this.enableLiveTvAccess, + enableMediaPlayback: enableMediaPlayback ?? this.enableMediaPlayback, + enableAudioPlaybackTranscoding: enableAudioPlaybackTranscoding ?? + this.enableAudioPlaybackTranscoding, + enableVideoPlaybackTranscoding: enableVideoPlaybackTranscoding ?? + this.enableVideoPlaybackTranscoding, + enablePlaybackRemuxing: + enablePlaybackRemuxing ?? this.enablePlaybackRemuxing, + forceRemoteSourceTranscoding: + forceRemoteSourceTranscoding ?? this.forceRemoteSourceTranscoding, + enableContentDeletion: + enableContentDeletion ?? this.enableContentDeletion, + enableContentDeletionFromFolders: enableContentDeletionFromFolders ?? + this.enableContentDeletionFromFolders, + enableContentDownloading: + enableContentDownloading ?? this.enableContentDownloading, + enableSyncTranscoding: + enableSyncTranscoding ?? this.enableSyncTranscoding, + enableMediaConversion: + enableMediaConversion ?? this.enableMediaConversion, + enabledDevices: enabledDevices ?? this.enabledDevices, + enableAllDevices: enableAllDevices ?? this.enableAllDevices, + enabledChannels: enabledChannels ?? this.enabledChannels, + enableAllChannels: enableAllChannels ?? this.enableAllChannels, + enabledFolders: enabledFolders ?? this.enabledFolders, + enableAllFolders: enableAllFolders ?? this.enableAllFolders, + invalidLoginAttemptCount: + invalidLoginAttemptCount ?? this.invalidLoginAttemptCount, + loginAttemptsBeforeLockout: + loginAttemptsBeforeLockout ?? this.loginAttemptsBeforeLockout, + maxActiveSessions: maxActiveSessions ?? this.maxActiveSessions, + enablePublicSharing: enablePublicSharing ?? this.enablePublicSharing, + blockedMediaFolders: blockedMediaFolders ?? this.blockedMediaFolders, + blockedChannels: blockedChannels ?? this.blockedChannels, + remoteClientBitrateLimit: + remoteClientBitrateLimit ?? this.remoteClientBitrateLimit, + authenticationProviderId: + authenticationProviderId ?? this.authenticationProviderId, + passwordResetProviderId: + passwordResetProviderId ?? this.passwordResetProviderId, + syncPlayAccess: syncPlayAccess ?? this.syncPlayAccess); + } + + UserPolicy copyWithWrapped( + {Wrapped? isAdministrator, + Wrapped? isHidden, + Wrapped? enableCollectionManagement, + Wrapped? enableSubtitleManagement, + Wrapped? enableLyricManagement, + Wrapped? isDisabled, + Wrapped? maxParentalRating, + Wrapped?>? blockedTags, + Wrapped?>? allowedTags, + Wrapped? enableUserPreferenceAccess, + Wrapped?>? accessSchedules, + Wrapped?>? blockUnratedItems, + Wrapped? enableRemoteControlOfOtherUsers, + Wrapped? enableSharedDeviceControl, + Wrapped? enableRemoteAccess, + Wrapped? enableLiveTvManagement, + Wrapped? enableLiveTvAccess, + Wrapped? enableMediaPlayback, + Wrapped? enableAudioPlaybackTranscoding, + Wrapped? enableVideoPlaybackTranscoding, + Wrapped? enablePlaybackRemuxing, + Wrapped? forceRemoteSourceTranscoding, + Wrapped? enableContentDeletion, + Wrapped?>? enableContentDeletionFromFolders, + Wrapped? enableContentDownloading, + Wrapped? enableSyncTranscoding, + Wrapped? enableMediaConversion, + Wrapped?>? enabledDevices, + Wrapped? enableAllDevices, + Wrapped?>? enabledChannels, + Wrapped? enableAllChannels, + Wrapped?>? enabledFolders, + Wrapped? enableAllFolders, + Wrapped? invalidLoginAttemptCount, + Wrapped? loginAttemptsBeforeLockout, + Wrapped? maxActiveSessions, + Wrapped? enablePublicSharing, + Wrapped?>? blockedMediaFolders, + Wrapped?>? blockedChannels, + Wrapped? remoteClientBitrateLimit, + Wrapped? authenticationProviderId, + Wrapped? passwordResetProviderId, + Wrapped? syncPlayAccess}) { + return UserPolicy( + isAdministrator: (isAdministrator != null + ? isAdministrator.value + : this.isAdministrator), + isHidden: (isHidden != null ? isHidden.value : this.isHidden), + enableCollectionManagement: (enableCollectionManagement != null + ? enableCollectionManagement.value + : this.enableCollectionManagement), + enableSubtitleManagement: (enableSubtitleManagement != null + ? enableSubtitleManagement.value + : this.enableSubtitleManagement), + enableLyricManagement: (enableLyricManagement != null + ? enableLyricManagement.value + : this.enableLyricManagement), + isDisabled: (isDisabled != null ? isDisabled.value : this.isDisabled), + maxParentalRating: (maxParentalRating != null + ? maxParentalRating.value + : this.maxParentalRating), + blockedTags: + (blockedTags != null ? blockedTags.value : this.blockedTags), + allowedTags: + (allowedTags != null ? allowedTags.value : this.allowedTags), + enableUserPreferenceAccess: (enableUserPreferenceAccess != null + ? enableUserPreferenceAccess.value + : this.enableUserPreferenceAccess), + accessSchedules: (accessSchedules != null + ? accessSchedules.value + : this.accessSchedules), + blockUnratedItems: (blockUnratedItems != null + ? blockUnratedItems.value + : this.blockUnratedItems), + enableRemoteControlOfOtherUsers: (enableRemoteControlOfOtherUsers != null + ? enableRemoteControlOfOtherUsers.value + : this.enableRemoteControlOfOtherUsers), + enableSharedDeviceControl: (enableSharedDeviceControl != null + ? enableSharedDeviceControl.value + : this.enableSharedDeviceControl), + enableRemoteAccess: (enableRemoteAccess != null + ? enableRemoteAccess.value + : this.enableRemoteAccess), + enableLiveTvManagement: (enableLiveTvManagement != null + ? enableLiveTvManagement.value + : this.enableLiveTvManagement), + enableLiveTvAccess: (enableLiveTvAccess != null + ? enableLiveTvAccess.value + : this.enableLiveTvAccess), + enableMediaPlayback: (enableMediaPlayback != null + ? enableMediaPlayback.value + : this.enableMediaPlayback), + enableAudioPlaybackTranscoding: (enableAudioPlaybackTranscoding != null + ? enableAudioPlaybackTranscoding.value + : this.enableAudioPlaybackTranscoding), + enableVideoPlaybackTranscoding: (enableVideoPlaybackTranscoding != null + ? enableVideoPlaybackTranscoding.value + : this.enableVideoPlaybackTranscoding), + enablePlaybackRemuxing: (enablePlaybackRemuxing != null + ? enablePlaybackRemuxing.value + : this.enablePlaybackRemuxing), + forceRemoteSourceTranscoding: (forceRemoteSourceTranscoding != null + ? forceRemoteSourceTranscoding.value + : this.forceRemoteSourceTranscoding), + enableContentDeletion: (enableContentDeletion != null + ? enableContentDeletion.value + : this.enableContentDeletion), + enableContentDeletionFromFolders: (enableContentDeletionFromFolders != null + ? enableContentDeletionFromFolders.value + : this.enableContentDeletionFromFolders), + enableContentDownloading: (enableContentDownloading != null + ? enableContentDownloading.value + : this.enableContentDownloading), + enableSyncTranscoding: (enableSyncTranscoding != null + ? enableSyncTranscoding.value + : this.enableSyncTranscoding), + enableMediaConversion: (enableMediaConversion != null + ? enableMediaConversion.value + : this.enableMediaConversion), + enabledDevices: (enabledDevices != null + ? enabledDevices.value + : this.enabledDevices), + enableAllDevices: (enableAllDevices != null + ? enableAllDevices.value + : this.enableAllDevices), + enabledChannels: (enabledChannels != null + ? enabledChannels.value + : this.enabledChannels), + enableAllChannels: (enableAllChannels != null + ? enableAllChannels.value + : this.enableAllChannels), + enabledFolders: (enabledFolders != null + ? enabledFolders.value + : this.enabledFolders), + enableAllFolders: (enableAllFolders != null + ? enableAllFolders.value + : this.enableAllFolders), + invalidLoginAttemptCount: (invalidLoginAttemptCount != null + ? invalidLoginAttemptCount.value + : this.invalidLoginAttemptCount), + loginAttemptsBeforeLockout: (loginAttemptsBeforeLockout != null + ? loginAttemptsBeforeLockout.value + : this.loginAttemptsBeforeLockout), + maxActiveSessions: (maxActiveSessions != null + ? maxActiveSessions.value + : this.maxActiveSessions), + enablePublicSharing: (enablePublicSharing != null + ? enablePublicSharing.value + : this.enablePublicSharing), + blockedMediaFolders: (blockedMediaFolders != null + ? blockedMediaFolders.value + : this.blockedMediaFolders), + blockedChannels: (blockedChannels != null + ? blockedChannels.value + : this.blockedChannels), + remoteClientBitrateLimit: (remoteClientBitrateLimit != null ? remoteClientBitrateLimit.value : this.remoteClientBitrateLimit), + authenticationProviderId: (authenticationProviderId != null ? authenticationProviderId.value : this.authenticationProviderId), + passwordResetProviderId: (passwordResetProviderId != null ? passwordResetProviderId.value : this.passwordResetProviderId), + syncPlayAccess: (syncPlayAccess != null ? syncPlayAccess.value : this.syncPlayAccess)); + } +} + +@JsonSerializable(explicitToJson: true) +class UserUpdatedMessage { + const UserUpdatedMessage({ + this.data, + this.messageId, + this.messageType, + }); + + factory UserUpdatedMessage.fromJson(Map json) => + _$UserUpdatedMessageFromJson(json); + + static const toJsonFactory = _$UserUpdatedMessageToJson; + Map toJson() => _$UserUpdatedMessageToJson(this); + + @JsonKey(name: 'Data', includeIfNull: false) + final UserDto? data; + @JsonKey(name: 'MessageId', includeIfNull: false) + final String? messageId; + @JsonKey( + name: 'MessageType', + includeIfNull: false, + toJson: sessionMessageTypeNullableToJson, + fromJson: sessionMessageTypeMessageTypeNullableFromJson, + ) + final enums.SessionMessageType? messageType; + static enums.SessionMessageType? + sessionMessageTypeMessageTypeNullableFromJson(Object? value) => + sessionMessageTypeNullableFromJson( + value, enums.SessionMessageType.userupdated); + + static const fromJsonFactory = _$UserUpdatedMessageFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is UserUpdatedMessage && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data)) && + (identical(other.messageId, messageId) || + const DeepCollectionEquality() + .equals(other.messageId, messageId)) && + (identical(other.messageType, messageType) || + const DeepCollectionEquality() + .equals(other.messageType, messageType))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(data) ^ + const DeepCollectionEquality().hash(messageId) ^ + const DeepCollectionEquality().hash(messageType) ^ + runtimeType.hashCode; +} + +extension $UserUpdatedMessageExtension on UserUpdatedMessage { + UserUpdatedMessage copyWith( + {UserDto? data, + String? messageId, + enums.SessionMessageType? messageType}) { + return UserUpdatedMessage( + data: data ?? this.data, + messageId: messageId ?? this.messageId, + messageType: messageType ?? this.messageType); + } + + UserUpdatedMessage copyWithWrapped( + {Wrapped? data, + Wrapped? messageId, + Wrapped? messageType}) { + return UserUpdatedMessage( + data: (data != null ? data.value : this.data), + messageId: (messageId != null ? messageId.value : this.messageId), + messageType: + (messageType != null ? messageType.value : this.messageType)); + } +} + +@JsonSerializable(explicitToJson: true) +class UtcTimeResponse { + const UtcTimeResponse({ + this.requestReceptionTime, + this.responseTransmissionTime, + }); + + factory UtcTimeResponse.fromJson(Map json) => + _$UtcTimeResponseFromJson(json); + + static const toJsonFactory = _$UtcTimeResponseToJson; + Map toJson() => _$UtcTimeResponseToJson(this); + + @JsonKey(name: 'RequestReceptionTime', includeIfNull: false) + final DateTime? requestReceptionTime; + @JsonKey(name: 'ResponseTransmissionTime', includeIfNull: false) + final DateTime? responseTransmissionTime; + static const fromJsonFactory = _$UtcTimeResponseFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is UtcTimeResponse && + (identical(other.requestReceptionTime, requestReceptionTime) || + const DeepCollectionEquality().equals( + other.requestReceptionTime, requestReceptionTime)) && + (identical( + other.responseTransmissionTime, responseTransmissionTime) || + const DeepCollectionEquality().equals( + other.responseTransmissionTime, responseTransmissionTime))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(requestReceptionTime) ^ + const DeepCollectionEquality().hash(responseTransmissionTime) ^ + runtimeType.hashCode; +} + +extension $UtcTimeResponseExtension on UtcTimeResponse { + UtcTimeResponse copyWith( + {DateTime? requestReceptionTime, DateTime? responseTransmissionTime}) { + return UtcTimeResponse( + requestReceptionTime: requestReceptionTime ?? this.requestReceptionTime, + responseTransmissionTime: + responseTransmissionTime ?? this.responseTransmissionTime); + } + + UtcTimeResponse copyWithWrapped( + {Wrapped? requestReceptionTime, + Wrapped? responseTransmissionTime}) { + return UtcTimeResponse( + requestReceptionTime: (requestReceptionTime != null + ? requestReceptionTime.value + : this.requestReceptionTime), + responseTransmissionTime: (responseTransmissionTime != null + ? responseTransmissionTime.value + : this.responseTransmissionTime)); + } +} + +@JsonSerializable(explicitToJson: true) +class ValidatePathDto { + const ValidatePathDto({ + this.validateWritable, + this.path, + this.isFile, + }); + + factory ValidatePathDto.fromJson(Map json) => + _$ValidatePathDtoFromJson(json); + + static const toJsonFactory = _$ValidatePathDtoToJson; + Map toJson() => _$ValidatePathDtoToJson(this); + + @JsonKey(name: 'ValidateWritable', includeIfNull: false) + final bool? validateWritable; + @JsonKey(name: 'Path', includeIfNull: false) + final String? path; + @JsonKey(name: 'IsFile', includeIfNull: false) + final bool? isFile; + static const fromJsonFactory = _$ValidatePathDtoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is ValidatePathDto && + (identical(other.validateWritable, validateWritable) || + const DeepCollectionEquality() + .equals(other.validateWritable, validateWritable)) && + (identical(other.path, path) || + const DeepCollectionEquality().equals(other.path, path)) && + (identical(other.isFile, isFile) || + const DeepCollectionEquality().equals(other.isFile, isFile))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(validateWritable) ^ + const DeepCollectionEquality().hash(path) ^ + const DeepCollectionEquality().hash(isFile) ^ + runtimeType.hashCode; +} + +extension $ValidatePathDtoExtension on ValidatePathDto { + ValidatePathDto copyWith( + {bool? validateWritable, String? path, bool? isFile}) { + return ValidatePathDto( + validateWritable: validateWritable ?? this.validateWritable, + path: path ?? this.path, + isFile: isFile ?? this.isFile); + } + + ValidatePathDto copyWithWrapped( + {Wrapped? validateWritable, + Wrapped? path, + Wrapped? isFile}) { + return ValidatePathDto( + validateWritable: (validateWritable != null + ? validateWritable.value + : this.validateWritable), + path: (path != null ? path.value : this.path), + isFile: (isFile != null ? isFile.value : this.isFile)); + } +} + +@JsonSerializable(explicitToJson: true) +class VersionInfo { + const VersionInfo({ + this.version, + this.versionNumber, + this.changelog, + this.targetAbi, + this.sourceUrl, + this.checksum, + this.timestamp, + this.repositoryName, + this.repositoryUrl, + }); + + factory VersionInfo.fromJson(Map json) => + _$VersionInfoFromJson(json); + + static const toJsonFactory = _$VersionInfoToJson; + Map toJson() => _$VersionInfoToJson(this); + + @JsonKey(name: 'version', includeIfNull: false) + final String? version; + @JsonKey(name: 'VersionNumber', includeIfNull: false) + final String? versionNumber; + @JsonKey(name: 'changelog', includeIfNull: false) + final String? changelog; + @JsonKey(name: 'targetAbi', includeIfNull: false) + final String? targetAbi; + @JsonKey(name: 'sourceUrl', includeIfNull: false) + final String? sourceUrl; + @JsonKey(name: 'checksum', includeIfNull: false) + final String? checksum; + @JsonKey(name: 'timestamp', includeIfNull: false) + final String? timestamp; + @JsonKey(name: 'repositoryName', includeIfNull: false) + final String? repositoryName; + @JsonKey(name: 'repositoryUrl', includeIfNull: false) + final String? repositoryUrl; + static const fromJsonFactory = _$VersionInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is VersionInfo && + (identical(other.version, version) || + const DeepCollectionEquality() + .equals(other.version, version)) && + (identical(other.versionNumber, versionNumber) || + const DeepCollectionEquality() + .equals(other.versionNumber, versionNumber)) && + (identical(other.changelog, changelog) || + const DeepCollectionEquality() + .equals(other.changelog, changelog)) && + (identical(other.targetAbi, targetAbi) || + const DeepCollectionEquality() + .equals(other.targetAbi, targetAbi)) && + (identical(other.sourceUrl, sourceUrl) || + const DeepCollectionEquality() + .equals(other.sourceUrl, sourceUrl)) && + (identical(other.checksum, checksum) || + const DeepCollectionEquality() + .equals(other.checksum, checksum)) && + (identical(other.timestamp, timestamp) || + const DeepCollectionEquality() + .equals(other.timestamp, timestamp)) && + (identical(other.repositoryName, repositoryName) || + const DeepCollectionEquality() + .equals(other.repositoryName, repositoryName)) && + (identical(other.repositoryUrl, repositoryUrl) || + const DeepCollectionEquality() + .equals(other.repositoryUrl, repositoryUrl))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(version) ^ + const DeepCollectionEquality().hash(versionNumber) ^ + const DeepCollectionEquality().hash(changelog) ^ + const DeepCollectionEquality().hash(targetAbi) ^ + const DeepCollectionEquality().hash(sourceUrl) ^ + const DeepCollectionEquality().hash(checksum) ^ + const DeepCollectionEquality().hash(timestamp) ^ + const DeepCollectionEquality().hash(repositoryName) ^ + const DeepCollectionEquality().hash(repositoryUrl) ^ + runtimeType.hashCode; +} + +extension $VersionInfoExtension on VersionInfo { + VersionInfo copyWith( + {String? version, + String? versionNumber, + String? changelog, + String? targetAbi, + String? sourceUrl, + String? checksum, + String? timestamp, + String? repositoryName, + String? repositoryUrl}) { + return VersionInfo( + version: version ?? this.version, + versionNumber: versionNumber ?? this.versionNumber, + changelog: changelog ?? this.changelog, + targetAbi: targetAbi ?? this.targetAbi, + sourceUrl: sourceUrl ?? this.sourceUrl, + checksum: checksum ?? this.checksum, + timestamp: timestamp ?? this.timestamp, + repositoryName: repositoryName ?? this.repositoryName, + repositoryUrl: repositoryUrl ?? this.repositoryUrl); + } + + VersionInfo copyWithWrapped( + {Wrapped? version, + Wrapped? versionNumber, + Wrapped? changelog, + Wrapped? targetAbi, + Wrapped? sourceUrl, + Wrapped? checksum, + Wrapped? timestamp, + Wrapped? repositoryName, + Wrapped? repositoryUrl}) { + return VersionInfo( + version: (version != null ? version.value : this.version), + versionNumber: + (versionNumber != null ? versionNumber.value : this.versionNumber), + changelog: (changelog != null ? changelog.value : this.changelog), + targetAbi: (targetAbi != null ? targetAbi.value : this.targetAbi), + sourceUrl: (sourceUrl != null ? sourceUrl.value : this.sourceUrl), + checksum: (checksum != null ? checksum.value : this.checksum), + timestamp: (timestamp != null ? timestamp.value : this.timestamp), + repositoryName: (repositoryName != null + ? repositoryName.value + : this.repositoryName), + repositoryUrl: + (repositoryUrl != null ? repositoryUrl.value : this.repositoryUrl)); + } +} + +@JsonSerializable(explicitToJson: true) +class VirtualFolderInfo { + const VirtualFolderInfo({ + this.name, + this.locations, + this.collectionType, + this.libraryOptions, + this.itemId, + this.primaryImageItemId, + this.refreshProgress, + this.refreshStatus, + }); + + factory VirtualFolderInfo.fromJson(Map json) => + _$VirtualFolderInfoFromJson(json); + + static const toJsonFactory = _$VirtualFolderInfoToJson; + Map toJson() => _$VirtualFolderInfoToJson(this); + + @JsonKey(name: 'Name', includeIfNull: false) + final String? name; + @JsonKey(name: 'Locations', includeIfNull: false, defaultValue: []) + final List? locations; + @JsonKey( + name: 'CollectionType', + includeIfNull: false, + toJson: collectionTypeOptionsNullableToJson, + fromJson: collectionTypeOptionsNullableFromJson, + ) + final enums.CollectionTypeOptions? collectionType; + @JsonKey(name: 'LibraryOptions', includeIfNull: false) + final LibraryOptions? libraryOptions; + @JsonKey(name: 'ItemId', includeIfNull: false) + final String? itemId; + @JsonKey(name: 'PrimaryImageItemId', includeIfNull: false) + final String? primaryImageItemId; + @JsonKey(name: 'RefreshProgress', includeIfNull: false) + final double? refreshProgress; + @JsonKey(name: 'RefreshStatus', includeIfNull: false) + final String? refreshStatus; + static const fromJsonFactory = _$VirtualFolderInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is VirtualFolderInfo && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.locations, locations) || + const DeepCollectionEquality() + .equals(other.locations, locations)) && + (identical(other.collectionType, collectionType) || + const DeepCollectionEquality() + .equals(other.collectionType, collectionType)) && + (identical(other.libraryOptions, libraryOptions) || + const DeepCollectionEquality() + .equals(other.libraryOptions, libraryOptions)) && + (identical(other.itemId, itemId) || + const DeepCollectionEquality().equals(other.itemId, itemId)) && + (identical(other.primaryImageItemId, primaryImageItemId) || + const DeepCollectionEquality() + .equals(other.primaryImageItemId, primaryImageItemId)) && + (identical(other.refreshProgress, refreshProgress) || + const DeepCollectionEquality() + .equals(other.refreshProgress, refreshProgress)) && + (identical(other.refreshStatus, refreshStatus) || + const DeepCollectionEquality() + .equals(other.refreshStatus, refreshStatus))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(locations) ^ + const DeepCollectionEquality().hash(collectionType) ^ + const DeepCollectionEquality().hash(libraryOptions) ^ + const DeepCollectionEquality().hash(itemId) ^ + const DeepCollectionEquality().hash(primaryImageItemId) ^ + const DeepCollectionEquality().hash(refreshProgress) ^ + const DeepCollectionEquality().hash(refreshStatus) ^ + runtimeType.hashCode; +} + +extension $VirtualFolderInfoExtension on VirtualFolderInfo { + VirtualFolderInfo copyWith( + {String? name, + List? locations, + enums.CollectionTypeOptions? collectionType, + LibraryOptions? libraryOptions, + String? itemId, + String? primaryImageItemId, + double? refreshProgress, + String? refreshStatus}) { + return VirtualFolderInfo( + name: name ?? this.name, + locations: locations ?? this.locations, + collectionType: collectionType ?? this.collectionType, + libraryOptions: libraryOptions ?? this.libraryOptions, + itemId: itemId ?? this.itemId, + primaryImageItemId: primaryImageItemId ?? this.primaryImageItemId, + refreshProgress: refreshProgress ?? this.refreshProgress, + refreshStatus: refreshStatus ?? this.refreshStatus); + } + + VirtualFolderInfo copyWithWrapped( + {Wrapped? name, + Wrapped?>? locations, + Wrapped? collectionType, + Wrapped? libraryOptions, + Wrapped? itemId, + Wrapped? primaryImageItemId, + Wrapped? refreshProgress, + Wrapped? refreshStatus}) { + return VirtualFolderInfo( + name: (name != null ? name.value : this.name), + locations: (locations != null ? locations.value : this.locations), + collectionType: (collectionType != null + ? collectionType.value + : this.collectionType), + libraryOptions: (libraryOptions != null + ? libraryOptions.value + : this.libraryOptions), + itemId: (itemId != null ? itemId.value : this.itemId), + primaryImageItemId: (primaryImageItemId != null + ? primaryImageItemId.value + : this.primaryImageItemId), + refreshProgress: (refreshProgress != null + ? refreshProgress.value + : this.refreshProgress), + refreshStatus: + (refreshStatus != null ? refreshStatus.value : this.refreshStatus)); + } +} + +@JsonSerializable(explicitToJson: true) +class WakeOnLanInfo { + const WakeOnLanInfo({ + this.macAddress, + this.port, + }); + + factory WakeOnLanInfo.fromJson(Map json) => + _$WakeOnLanInfoFromJson(json); + + static const toJsonFactory = _$WakeOnLanInfoToJson; + Map toJson() => _$WakeOnLanInfoToJson(this); + + @JsonKey(name: 'MacAddress', includeIfNull: false) + final String? macAddress; + @JsonKey(name: 'Port', includeIfNull: false) + final int? port; + static const fromJsonFactory = _$WakeOnLanInfoFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is WakeOnLanInfo && + (identical(other.macAddress, macAddress) || + const DeepCollectionEquality() + .equals(other.macAddress, macAddress)) && + (identical(other.port, port) || + const DeepCollectionEquality().equals(other.port, port))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(macAddress) ^ + const DeepCollectionEquality().hash(port) ^ + runtimeType.hashCode; +} + +extension $WakeOnLanInfoExtension on WakeOnLanInfo { + WakeOnLanInfo copyWith({String? macAddress, int? port}) { + return WakeOnLanInfo( + macAddress: macAddress ?? this.macAddress, port: port ?? this.port); + } + + WakeOnLanInfo copyWithWrapped( + {Wrapped? macAddress, Wrapped? port}) { + return WakeOnLanInfo( + macAddress: (macAddress != null ? macAddress.value : this.macAddress), + port: (port != null ? port.value : this.port)); + } +} + +@JsonSerializable(explicitToJson: true) +class WebSocketMessage { + const WebSocketMessage(); + + factory WebSocketMessage.fromJson(Map json) => + _$WebSocketMessageFromJson(json); + + static const toJsonFactory = _$WebSocketMessageToJson; + Map toJson() => _$WebSocketMessageToJson(this); + + static const fromJsonFactory = _$WebSocketMessageFromJson; + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => runtimeType.hashCode; +} + +@JsonSerializable(explicitToJson: true) +class XbmcMetadataOptions { + const XbmcMetadataOptions({ + this.userId, + this.releaseDateFormat, + this.saveImagePathsInNfo, + this.enablePathSubstitution, + this.enableExtraThumbsDuplication, + }); + + factory XbmcMetadataOptions.fromJson(Map json) => + _$XbmcMetadataOptionsFromJson(json); + + static const toJsonFactory = _$XbmcMetadataOptionsToJson; + Map toJson() => _$XbmcMetadataOptionsToJson(this); + + @JsonKey(name: 'UserId', includeIfNull: false) + final String? userId; + @JsonKey(name: 'ReleaseDateFormat', includeIfNull: false) + final String? releaseDateFormat; + @JsonKey(name: 'SaveImagePathsInNfo', includeIfNull: false) + final bool? saveImagePathsInNfo; + @JsonKey(name: 'EnablePathSubstitution', includeIfNull: false) + final bool? enablePathSubstitution; + @JsonKey(name: 'EnableExtraThumbsDuplication', includeIfNull: false) + final bool? enableExtraThumbsDuplication; + static const fromJsonFactory = _$XbmcMetadataOptionsFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is XbmcMetadataOptions && + (identical(other.userId, userId) || + const DeepCollectionEquality().equals(other.userId, userId)) && + (identical(other.releaseDateFormat, releaseDateFormat) || + const DeepCollectionEquality() + .equals(other.releaseDateFormat, releaseDateFormat)) && + (identical(other.saveImagePathsInNfo, saveImagePathsInNfo) || + const DeepCollectionEquality() + .equals(other.saveImagePathsInNfo, saveImagePathsInNfo)) && + (identical(other.enablePathSubstitution, enablePathSubstitution) || + const DeepCollectionEquality().equals( + other.enablePathSubstitution, enablePathSubstitution)) && + (identical(other.enableExtraThumbsDuplication, + enableExtraThumbsDuplication) || + const DeepCollectionEquality().equals( + other.enableExtraThumbsDuplication, + enableExtraThumbsDuplication))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(userId) ^ + const DeepCollectionEquality().hash(releaseDateFormat) ^ + const DeepCollectionEquality().hash(saveImagePathsInNfo) ^ + const DeepCollectionEquality().hash(enablePathSubstitution) ^ + const DeepCollectionEquality().hash(enableExtraThumbsDuplication) ^ + runtimeType.hashCode; +} + +extension $XbmcMetadataOptionsExtension on XbmcMetadataOptions { + XbmcMetadataOptions copyWith( + {String? userId, + String? releaseDateFormat, + bool? saveImagePathsInNfo, + bool? enablePathSubstitution, + bool? enableExtraThumbsDuplication}) { + return XbmcMetadataOptions( + userId: userId ?? this.userId, + releaseDateFormat: releaseDateFormat ?? this.releaseDateFormat, + saveImagePathsInNfo: saveImagePathsInNfo ?? this.saveImagePathsInNfo, + enablePathSubstitution: + enablePathSubstitution ?? this.enablePathSubstitution, + enableExtraThumbsDuplication: + enableExtraThumbsDuplication ?? this.enableExtraThumbsDuplication); + } + + XbmcMetadataOptions copyWithWrapped( + {Wrapped? userId, + Wrapped? releaseDateFormat, + Wrapped? saveImagePathsInNfo, + Wrapped? enablePathSubstitution, + Wrapped? enableExtraThumbsDuplication}) { + return XbmcMetadataOptions( + userId: (userId != null ? userId.value : this.userId), + releaseDateFormat: (releaseDateFormat != null + ? releaseDateFormat.value + : this.releaseDateFormat), + saveImagePathsInNfo: (saveImagePathsInNfo != null + ? saveImagePathsInNfo.value + : this.saveImagePathsInNfo), + enablePathSubstitution: (enablePathSubstitution != null + ? enablePathSubstitution.value + : this.enablePathSubstitution), + enableExtraThumbsDuplication: (enableExtraThumbsDuplication != null + ? enableExtraThumbsDuplication.value + : this.enableExtraThumbsDuplication)); + } +} + +@JsonSerializable(explicitToJson: true) +class BaseItemDto$ImageBlurHashes { + const BaseItemDto$ImageBlurHashes({ + this.primary, + this.art, + this.backdrop, + this.banner, + this.logo, + this.thumb, + this.disc, + this.box, + this.screenshot, + this.menu, + this.chapter, + this.boxRear, + this.profile, + }); + + factory BaseItemDto$ImageBlurHashes.fromJson(Map json) => + _$BaseItemDto$ImageBlurHashesFromJson(json); + + static const toJsonFactory = _$BaseItemDto$ImageBlurHashesToJson; + Map toJson() => _$BaseItemDto$ImageBlurHashesToJson(this); + + @JsonKey(name: 'Primary', includeIfNull: false) + final Map? primary; + @JsonKey(name: 'Art', includeIfNull: false) + final Map? art; + @JsonKey(name: 'Backdrop', includeIfNull: false) + final Map? backdrop; + @JsonKey(name: 'Banner', includeIfNull: false) + final Map? banner; + @JsonKey(name: 'Logo', includeIfNull: false) + final Map? logo; + @JsonKey(name: 'Thumb', includeIfNull: false) + final Map? thumb; + @JsonKey(name: 'Disc', includeIfNull: false) + final Map? disc; + @JsonKey(name: 'Box', includeIfNull: false) + final Map? box; + @JsonKey(name: 'Screenshot', includeIfNull: false) + final Map? screenshot; + @JsonKey(name: 'Menu', includeIfNull: false) + final Map? menu; + @JsonKey(name: 'Chapter', includeIfNull: false) + final Map? chapter; + @JsonKey(name: 'BoxRear', includeIfNull: false) + final Map? boxRear; + @JsonKey(name: 'Profile', includeIfNull: false) + final Map? profile; + static const fromJsonFactory = _$BaseItemDto$ImageBlurHashesFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is BaseItemDto$ImageBlurHashes && + (identical(other.primary, primary) || + const DeepCollectionEquality() + .equals(other.primary, primary)) && + (identical(other.art, art) || + const DeepCollectionEquality().equals(other.art, art)) && + (identical(other.backdrop, backdrop) || + const DeepCollectionEquality() + .equals(other.backdrop, backdrop)) && + (identical(other.banner, banner) || + const DeepCollectionEquality().equals(other.banner, banner)) && + (identical(other.logo, logo) || + const DeepCollectionEquality().equals(other.logo, logo)) && + (identical(other.thumb, thumb) || + const DeepCollectionEquality().equals(other.thumb, thumb)) && + (identical(other.disc, disc) || + const DeepCollectionEquality().equals(other.disc, disc)) && + (identical(other.box, box) || + const DeepCollectionEquality().equals(other.box, box)) && + (identical(other.screenshot, screenshot) || + const DeepCollectionEquality() + .equals(other.screenshot, screenshot)) && + (identical(other.menu, menu) || + const DeepCollectionEquality().equals(other.menu, menu)) && + (identical(other.chapter, chapter) || + const DeepCollectionEquality() + .equals(other.chapter, chapter)) && + (identical(other.boxRear, boxRear) || + const DeepCollectionEquality() + .equals(other.boxRear, boxRear)) && + (identical(other.profile, profile) || + const DeepCollectionEquality().equals(other.profile, profile))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(primary) ^ + const DeepCollectionEquality().hash(art) ^ + const DeepCollectionEquality().hash(backdrop) ^ + const DeepCollectionEquality().hash(banner) ^ + const DeepCollectionEquality().hash(logo) ^ + const DeepCollectionEquality().hash(thumb) ^ + const DeepCollectionEquality().hash(disc) ^ + const DeepCollectionEquality().hash(box) ^ + const DeepCollectionEquality().hash(screenshot) ^ + const DeepCollectionEquality().hash(menu) ^ + const DeepCollectionEquality().hash(chapter) ^ + const DeepCollectionEquality().hash(boxRear) ^ + const DeepCollectionEquality().hash(profile) ^ + runtimeType.hashCode; +} + +extension $BaseItemDto$ImageBlurHashesExtension on BaseItemDto$ImageBlurHashes { + BaseItemDto$ImageBlurHashes copyWith( + {Map? primary, + Map? art, + Map? backdrop, + Map? banner, + Map? logo, + Map? thumb, + Map? disc, + Map? box, + Map? screenshot, + Map? menu, + Map? chapter, + Map? boxRear, + Map? profile}) { + return BaseItemDto$ImageBlurHashes( + primary: primary ?? this.primary, + art: art ?? this.art, + backdrop: backdrop ?? this.backdrop, + banner: banner ?? this.banner, + logo: logo ?? this.logo, + thumb: thumb ?? this.thumb, + disc: disc ?? this.disc, + box: box ?? this.box, + screenshot: screenshot ?? this.screenshot, + menu: menu ?? this.menu, + chapter: chapter ?? this.chapter, + boxRear: boxRear ?? this.boxRear, + profile: profile ?? this.profile); + } + + BaseItemDto$ImageBlurHashes copyWithWrapped( + {Wrapped?>? primary, + Wrapped?>? art, + Wrapped?>? backdrop, + Wrapped?>? banner, + Wrapped?>? logo, + Wrapped?>? thumb, + Wrapped?>? disc, + Wrapped?>? box, + Wrapped?>? screenshot, + Wrapped?>? menu, + Wrapped?>? chapter, + Wrapped?>? boxRear, + Wrapped?>? profile}) { + return BaseItemDto$ImageBlurHashes( + primary: (primary != null ? primary.value : this.primary), + art: (art != null ? art.value : this.art), + backdrop: (backdrop != null ? backdrop.value : this.backdrop), + banner: (banner != null ? banner.value : this.banner), + logo: (logo != null ? logo.value : this.logo), + thumb: (thumb != null ? thumb.value : this.thumb), + disc: (disc != null ? disc.value : this.disc), + box: (box != null ? box.value : this.box), + screenshot: (screenshot != null ? screenshot.value : this.screenshot), + menu: (menu != null ? menu.value : this.menu), + chapter: (chapter != null ? chapter.value : this.chapter), + boxRear: (boxRear != null ? boxRear.value : this.boxRear), + profile: (profile != null ? profile.value : this.profile)); + } +} + +@JsonSerializable(explicitToJson: true) +class BaseItemPerson$ImageBlurHashes { + const BaseItemPerson$ImageBlurHashes({ + this.primary, + this.art, + this.backdrop, + this.banner, + this.logo, + this.thumb, + this.disc, + this.box, + this.screenshot, + this.menu, + this.chapter, + this.boxRear, + this.profile, + }); + + factory BaseItemPerson$ImageBlurHashes.fromJson(Map json) => + _$BaseItemPerson$ImageBlurHashesFromJson(json); + + static const toJsonFactory = _$BaseItemPerson$ImageBlurHashesToJson; + Map toJson() => _$BaseItemPerson$ImageBlurHashesToJson(this); + + @JsonKey(name: 'Primary', includeIfNull: false) + final Map? primary; + @JsonKey(name: 'Art', includeIfNull: false) + final Map? art; + @JsonKey(name: 'Backdrop', includeIfNull: false) + final Map? backdrop; + @JsonKey(name: 'Banner', includeIfNull: false) + final Map? banner; + @JsonKey(name: 'Logo', includeIfNull: false) + final Map? logo; + @JsonKey(name: 'Thumb', includeIfNull: false) + final Map? thumb; + @JsonKey(name: 'Disc', includeIfNull: false) + final Map? disc; + @JsonKey(name: 'Box', includeIfNull: false) + final Map? box; + @JsonKey(name: 'Screenshot', includeIfNull: false) + final Map? screenshot; + @JsonKey(name: 'Menu', includeIfNull: false) + final Map? menu; + @JsonKey(name: 'Chapter', includeIfNull: false) + final Map? chapter; + @JsonKey(name: 'BoxRear', includeIfNull: false) + final Map? boxRear; + @JsonKey(name: 'Profile', includeIfNull: false) + final Map? profile; + static const fromJsonFactory = _$BaseItemPerson$ImageBlurHashesFromJson; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other is BaseItemPerson$ImageBlurHashes && + (identical(other.primary, primary) || + const DeepCollectionEquality() + .equals(other.primary, primary)) && + (identical(other.art, art) || + const DeepCollectionEquality().equals(other.art, art)) && + (identical(other.backdrop, backdrop) || + const DeepCollectionEquality() + .equals(other.backdrop, backdrop)) && + (identical(other.banner, banner) || + const DeepCollectionEquality().equals(other.banner, banner)) && + (identical(other.logo, logo) || + const DeepCollectionEquality().equals(other.logo, logo)) && + (identical(other.thumb, thumb) || + const DeepCollectionEquality().equals(other.thumb, thumb)) && + (identical(other.disc, disc) || + const DeepCollectionEquality().equals(other.disc, disc)) && + (identical(other.box, box) || + const DeepCollectionEquality().equals(other.box, box)) && + (identical(other.screenshot, screenshot) || + const DeepCollectionEquality() + .equals(other.screenshot, screenshot)) && + (identical(other.menu, menu) || + const DeepCollectionEquality().equals(other.menu, menu)) && + (identical(other.chapter, chapter) || + const DeepCollectionEquality() + .equals(other.chapter, chapter)) && + (identical(other.boxRear, boxRear) || + const DeepCollectionEquality() + .equals(other.boxRear, boxRear)) && + (identical(other.profile, profile) || + const DeepCollectionEquality().equals(other.profile, profile))); + } + + @override + String toString() => jsonEncode(this); + + @override + int get hashCode => + const DeepCollectionEquality().hash(primary) ^ + const DeepCollectionEquality().hash(art) ^ + const DeepCollectionEquality().hash(backdrop) ^ + const DeepCollectionEquality().hash(banner) ^ + const DeepCollectionEquality().hash(logo) ^ + const DeepCollectionEquality().hash(thumb) ^ + const DeepCollectionEquality().hash(disc) ^ + const DeepCollectionEquality().hash(box) ^ + const DeepCollectionEquality().hash(screenshot) ^ + const DeepCollectionEquality().hash(menu) ^ + const DeepCollectionEquality().hash(chapter) ^ + const DeepCollectionEquality().hash(boxRear) ^ + const DeepCollectionEquality().hash(profile) ^ + runtimeType.hashCode; +} + +extension $BaseItemPerson$ImageBlurHashesExtension + on BaseItemPerson$ImageBlurHashes { + BaseItemPerson$ImageBlurHashes copyWith( + {Map? primary, + Map? art, + Map? backdrop, + Map? banner, + Map? logo, + Map? thumb, + Map? disc, + Map? box, + Map? screenshot, + Map? menu, + Map? chapter, + Map? boxRear, + Map? profile}) { + return BaseItemPerson$ImageBlurHashes( + primary: primary ?? this.primary, + art: art ?? this.art, + backdrop: backdrop ?? this.backdrop, + banner: banner ?? this.banner, + logo: logo ?? this.logo, + thumb: thumb ?? this.thumb, + disc: disc ?? this.disc, + box: box ?? this.box, + screenshot: screenshot ?? this.screenshot, + menu: menu ?? this.menu, + chapter: chapter ?? this.chapter, + boxRear: boxRear ?? this.boxRear, + profile: profile ?? this.profile); + } + + BaseItemPerson$ImageBlurHashes copyWithWrapped( + {Wrapped?>? primary, + Wrapped?>? art, + Wrapped?>? backdrop, + Wrapped?>? banner, + Wrapped?>? logo, + Wrapped?>? thumb, + Wrapped?>? disc, + Wrapped?>? box, + Wrapped?>? screenshot, + Wrapped?>? menu, + Wrapped?>? chapter, + Wrapped?>? boxRear, + Wrapped?>? profile}) { + return BaseItemPerson$ImageBlurHashes( + primary: (primary != null ? primary.value : this.primary), + art: (art != null ? art.value : this.art), + backdrop: (backdrop != null ? backdrop.value : this.backdrop), + banner: (banner != null ? banner.value : this.banner), + logo: (logo != null ? logo.value : this.logo), + thumb: (thumb != null ? thumb.value : this.thumb), + disc: (disc != null ? disc.value : this.disc), + box: (box != null ? box.value : this.box), + screenshot: (screenshot != null ? screenshot.value : this.screenshot), + menu: (menu != null ? menu.value : this.menu), + chapter: (chapter != null ? chapter.value : this.chapter), + boxRear: (boxRear != null ? boxRear.value : this.boxRear), + profile: (profile != null ? profile.value : this.profile)); + } +} + +String? analysisModeNullableToJson(enums.AnalysisMode? analysisMode) { + return analysisMode?.value; +} + +String? analysisModeToJson(enums.AnalysisMode analysisMode) { + return analysisMode.value; +} + +enums.AnalysisMode analysisModeFromJson( + Object? analysisMode, [ + enums.AnalysisMode? defaultValue, +]) { + return enums.AnalysisMode.values + .firstWhereOrNull((e) => e.value == analysisMode) ?? + defaultValue ?? + enums.AnalysisMode.swaggerGeneratedUnknown; +} + +enums.AnalysisMode? analysisModeNullableFromJson( + Object? analysisMode, [ + enums.AnalysisMode? defaultValue, +]) { + if (analysisMode == null) { + return null; + } + return enums.AnalysisMode.values + .firstWhereOrNull((e) => e.value == analysisMode) ?? + defaultValue; +} + +String analysisModeExplodedListToJson(List? analysisMode) { + return analysisMode?.map((e) => e.value!).join(',') ?? ''; +} + +List analysisModeListToJson(List? analysisMode) { + if (analysisMode == null) { + return []; + } + + return analysisMode.map((e) => e.value!).toList(); +} + +List analysisModeListFromJson( + List? analysisMode, [ + List? defaultValue, +]) { + if (analysisMode == null) { + return defaultValue ?? []; + } + + return analysisMode.map((e) => analysisModeFromJson(e.toString())).toList(); +} + +List? analysisModeNullableListFromJson( + List? analysisMode, [ + List? defaultValue, +]) { + if (analysisMode == null) { + return defaultValue; + } + + return analysisMode.map((e) => analysisModeFromJson(e.toString())).toList(); +} + +String? audioSpatialFormatNullableToJson( + enums.AudioSpatialFormat? audioSpatialFormat) { + return audioSpatialFormat?.value; +} + +String? audioSpatialFormatToJson(enums.AudioSpatialFormat audioSpatialFormat) { + return audioSpatialFormat.value; +} + +enums.AudioSpatialFormat audioSpatialFormatFromJson( + Object? audioSpatialFormat, [ + enums.AudioSpatialFormat? defaultValue, +]) { + return enums.AudioSpatialFormat.values + .firstWhereOrNull((e) => e.value == audioSpatialFormat) ?? + defaultValue ?? + enums.AudioSpatialFormat.swaggerGeneratedUnknown; +} + +enums.AudioSpatialFormat? audioSpatialFormatNullableFromJson( + Object? audioSpatialFormat, [ + enums.AudioSpatialFormat? defaultValue, +]) { + if (audioSpatialFormat == null) { + return null; + } + return enums.AudioSpatialFormat.values + .firstWhereOrNull((e) => e.value == audioSpatialFormat) ?? + defaultValue; +} + +String audioSpatialFormatExplodedListToJson( + List? audioSpatialFormat) { + return audioSpatialFormat?.map((e) => e.value!).join(',') ?? ''; +} + +List audioSpatialFormatListToJson( + List? audioSpatialFormat) { + if (audioSpatialFormat == null) { + return []; + } + + return audioSpatialFormat.map((e) => e.value!).toList(); +} + +List audioSpatialFormatListFromJson( + List? audioSpatialFormat, [ + List? defaultValue, +]) { + if (audioSpatialFormat == null) { + return defaultValue ?? []; + } + + return audioSpatialFormat + .map((e) => audioSpatialFormatFromJson(e.toString())) + .toList(); +} + +List? audioSpatialFormatNullableListFromJson( + List? audioSpatialFormat, [ + List? defaultValue, +]) { + if (audioSpatialFormat == null) { + return defaultValue; + } + + return audioSpatialFormat + .map((e) => audioSpatialFormatFromJson(e.toString())) + .toList(); +} + +String? baseItemKindNullableToJson(enums.BaseItemKind? baseItemKind) { + return baseItemKind?.value; +} + +String? baseItemKindToJson(enums.BaseItemKind baseItemKind) { + return baseItemKind.value; +} + +enums.BaseItemKind baseItemKindFromJson( + Object? baseItemKind, [ + enums.BaseItemKind? defaultValue, +]) { + return enums.BaseItemKind.values + .firstWhereOrNull((e) => e.value == baseItemKind) ?? + defaultValue ?? + enums.BaseItemKind.swaggerGeneratedUnknown; +} + +enums.BaseItemKind? baseItemKindNullableFromJson( + Object? baseItemKind, [ + enums.BaseItemKind? defaultValue, +]) { + if (baseItemKind == null) { + return null; + } + return enums.BaseItemKind.values + .firstWhereOrNull((e) => e.value == baseItemKind) ?? + defaultValue; +} + +String baseItemKindExplodedListToJson(List? baseItemKind) { + return baseItemKind?.map((e) => e.value!).join(',') ?? ''; +} + +List baseItemKindListToJson(List? baseItemKind) { + if (baseItemKind == null) { + return []; + } + + return baseItemKind.map((e) => e.value!).toList(); +} + +List baseItemKindListFromJson( + List? baseItemKind, [ + List? defaultValue, +]) { + if (baseItemKind == null) { + return defaultValue ?? []; + } + + return baseItemKind.map((e) => baseItemKindFromJson(e.toString())).toList(); +} + +List? baseItemKindNullableListFromJson( + List? baseItemKind, [ + List? defaultValue, +]) { + if (baseItemKind == null) { + return defaultValue; + } + + return baseItemKind.map((e) => baseItemKindFromJson(e.toString())).toList(); +} + +String? channelItemSortFieldNullableToJson( + enums.ChannelItemSortField? channelItemSortField) { + return channelItemSortField?.value; +} + +String? channelItemSortFieldToJson( + enums.ChannelItemSortField channelItemSortField) { + return channelItemSortField.value; +} + +enums.ChannelItemSortField channelItemSortFieldFromJson( + Object? channelItemSortField, [ + enums.ChannelItemSortField? defaultValue, +]) { + return enums.ChannelItemSortField.values + .firstWhereOrNull((e) => e.value == channelItemSortField) ?? + defaultValue ?? + enums.ChannelItemSortField.swaggerGeneratedUnknown; +} + +enums.ChannelItemSortField? channelItemSortFieldNullableFromJson( + Object? channelItemSortField, [ + enums.ChannelItemSortField? defaultValue, +]) { + if (channelItemSortField == null) { + return null; + } + return enums.ChannelItemSortField.values + .firstWhereOrNull((e) => e.value == channelItemSortField) ?? + defaultValue; +} + +String channelItemSortFieldExplodedListToJson( + List? channelItemSortField) { + return channelItemSortField?.map((e) => e.value!).join(',') ?? ''; +} + +List channelItemSortFieldListToJson( + List? channelItemSortField) { + if (channelItemSortField == null) { + return []; + } + + return channelItemSortField.map((e) => e.value!).toList(); +} + +List channelItemSortFieldListFromJson( + List? channelItemSortField, [ + List? defaultValue, +]) { + if (channelItemSortField == null) { + return defaultValue ?? []; + } + + return channelItemSortField + .map((e) => channelItemSortFieldFromJson(e.toString())) + .toList(); +} + +List? channelItemSortFieldNullableListFromJson( + List? channelItemSortField, [ + List? defaultValue, +]) { + if (channelItemSortField == null) { + return defaultValue; + } + + return channelItemSortField + .map((e) => channelItemSortFieldFromJson(e.toString())) + .toList(); +} + +String? channelMediaContentTypeNullableToJson( + enums.ChannelMediaContentType? channelMediaContentType) { + return channelMediaContentType?.value; +} + +String? channelMediaContentTypeToJson( + enums.ChannelMediaContentType channelMediaContentType) { + return channelMediaContentType.value; +} + +enums.ChannelMediaContentType channelMediaContentTypeFromJson( + Object? channelMediaContentType, [ + enums.ChannelMediaContentType? defaultValue, +]) { + return enums.ChannelMediaContentType.values + .firstWhereOrNull((e) => e.value == channelMediaContentType) ?? + defaultValue ?? + enums.ChannelMediaContentType.swaggerGeneratedUnknown; +} + +enums.ChannelMediaContentType? channelMediaContentTypeNullableFromJson( + Object? channelMediaContentType, [ + enums.ChannelMediaContentType? defaultValue, +]) { + if (channelMediaContentType == null) { + return null; + } + return enums.ChannelMediaContentType.values + .firstWhereOrNull((e) => e.value == channelMediaContentType) ?? + defaultValue; +} + +String channelMediaContentTypeExplodedListToJson( + List? channelMediaContentType) { + return channelMediaContentType?.map((e) => e.value!).join(',') ?? ''; +} + +List channelMediaContentTypeListToJson( + List? channelMediaContentType) { + if (channelMediaContentType == null) { + return []; + } + + return channelMediaContentType.map((e) => e.value!).toList(); +} + +List channelMediaContentTypeListFromJson( + List? channelMediaContentType, [ + List? defaultValue, +]) { + if (channelMediaContentType == null) { + return defaultValue ?? []; + } + + return channelMediaContentType + .map((e) => channelMediaContentTypeFromJson(e.toString())) + .toList(); +} + +List? + channelMediaContentTypeNullableListFromJson( + List? channelMediaContentType, [ + List? defaultValue, +]) { + if (channelMediaContentType == null) { + return defaultValue; + } + + return channelMediaContentType + .map((e) => channelMediaContentTypeFromJson(e.toString())) + .toList(); +} + +String? channelMediaTypeNullableToJson( + enums.ChannelMediaType? channelMediaType) { + return channelMediaType?.value; +} + +String? channelMediaTypeToJson(enums.ChannelMediaType channelMediaType) { + return channelMediaType.value; +} + +enums.ChannelMediaType channelMediaTypeFromJson( + Object? channelMediaType, [ + enums.ChannelMediaType? defaultValue, +]) { + return enums.ChannelMediaType.values + .firstWhereOrNull((e) => e.value == channelMediaType) ?? + defaultValue ?? + enums.ChannelMediaType.swaggerGeneratedUnknown; +} + +enums.ChannelMediaType? channelMediaTypeNullableFromJson( + Object? channelMediaType, [ + enums.ChannelMediaType? defaultValue, +]) { + if (channelMediaType == null) { + return null; + } + return enums.ChannelMediaType.values + .firstWhereOrNull((e) => e.value == channelMediaType) ?? + defaultValue; +} + +String channelMediaTypeExplodedListToJson( + List? channelMediaType) { + return channelMediaType?.map((e) => e.value!).join(',') ?? ''; +} + +List channelMediaTypeListToJson( + List? channelMediaType) { + if (channelMediaType == null) { + return []; + } + + return channelMediaType.map((e) => e.value!).toList(); +} + +List channelMediaTypeListFromJson( + List? channelMediaType, [ + List? defaultValue, +]) { + if (channelMediaType == null) { + return defaultValue ?? []; + } + + return channelMediaType + .map((e) => channelMediaTypeFromJson(e.toString())) + .toList(); +} + +List? channelMediaTypeNullableListFromJson( + List? channelMediaType, [ + List? defaultValue, +]) { + if (channelMediaType == null) { + return defaultValue; + } + + return channelMediaType + .map((e) => channelMediaTypeFromJson(e.toString())) + .toList(); +} + +String? channelTypeNullableToJson(enums.ChannelType? channelType) { + return channelType?.value; +} + +String? channelTypeToJson(enums.ChannelType channelType) { + return channelType.value; +} + +enums.ChannelType channelTypeFromJson( + Object? channelType, [ + enums.ChannelType? defaultValue, +]) { + return enums.ChannelType.values + .firstWhereOrNull((e) => e.value == channelType) ?? + defaultValue ?? + enums.ChannelType.swaggerGeneratedUnknown; +} + +enums.ChannelType? channelTypeNullableFromJson( + Object? channelType, [ + enums.ChannelType? defaultValue, +]) { + if (channelType == null) { + return null; + } + return enums.ChannelType.values + .firstWhereOrNull((e) => e.value == channelType) ?? + defaultValue; +} + +String channelTypeExplodedListToJson(List? channelType) { + return channelType?.map((e) => e.value!).join(',') ?? ''; +} + +List channelTypeListToJson(List? channelType) { + if (channelType == null) { + return []; + } + + return channelType.map((e) => e.value!).toList(); +} + +List channelTypeListFromJson( + List? channelType, [ + List? defaultValue, +]) { + if (channelType == null) { + return defaultValue ?? []; + } + + return channelType.map((e) => channelTypeFromJson(e.toString())).toList(); +} + +List? channelTypeNullableListFromJson( + List? channelType, [ + List? defaultValue, +]) { + if (channelType == null) { + return defaultValue; + } + + return channelType.map((e) => channelTypeFromJson(e.toString())).toList(); +} + +String? codecTypeNullableToJson(enums.CodecType? codecType) { + return codecType?.value; +} + +String? codecTypeToJson(enums.CodecType codecType) { + return codecType.value; +} + +enums.CodecType codecTypeFromJson( + Object? codecType, [ + enums.CodecType? defaultValue, +]) { + return enums.CodecType.values.firstWhereOrNull((e) => e.value == codecType) ?? + defaultValue ?? + enums.CodecType.swaggerGeneratedUnknown; +} + +enums.CodecType? codecTypeNullableFromJson( + Object? codecType, [ + enums.CodecType? defaultValue, +]) { + if (codecType == null) { + return null; + } + return enums.CodecType.values.firstWhereOrNull((e) => e.value == codecType) ?? + defaultValue; +} + +String codecTypeExplodedListToJson(List? codecType) { + return codecType?.map((e) => e.value!).join(',') ?? ''; +} + +List codecTypeListToJson(List? codecType) { + if (codecType == null) { + return []; + } + + return codecType.map((e) => e.value!).toList(); +} + +List codecTypeListFromJson( + List? codecType, [ + List? defaultValue, +]) { + if (codecType == null) { + return defaultValue ?? []; + } + + return codecType.map((e) => codecTypeFromJson(e.toString())).toList(); +} + +List? codecTypeNullableListFromJson( + List? codecType, [ + List? defaultValue, +]) { + if (codecType == null) { + return defaultValue; + } + + return codecType.map((e) => codecTypeFromJson(e.toString())).toList(); +} + +String? collectionTypeNullableToJson(enums.CollectionType? collectionType) { + return collectionType?.value; +} + +String? collectionTypeToJson(enums.CollectionType collectionType) { + return collectionType.value; +} + +enums.CollectionType collectionTypeFromJson( + Object? collectionType, [ + enums.CollectionType? defaultValue, +]) { + return enums.CollectionType.values + .firstWhereOrNull((e) => e.value == collectionType) ?? + defaultValue ?? + enums.CollectionType.swaggerGeneratedUnknown; +} + +enums.CollectionType? collectionTypeNullableFromJson( + Object? collectionType, [ + enums.CollectionType? defaultValue, +]) { + if (collectionType == null) { + return null; + } + return enums.CollectionType.values + .firstWhereOrNull((e) => e.value == collectionType) ?? + defaultValue; +} + +String collectionTypeExplodedListToJson( + List? collectionType) { + return collectionType?.map((e) => e.value!).join(',') ?? ''; +} + +List collectionTypeListToJson( + List? collectionType) { + if (collectionType == null) { + return []; + } + + return collectionType.map((e) => e.value!).toList(); +} + +List collectionTypeListFromJson( + List? collectionType, [ + List? defaultValue, +]) { + if (collectionType == null) { + return defaultValue ?? []; + } + + return collectionType + .map((e) => collectionTypeFromJson(e.toString())) + .toList(); +} + +List? collectionTypeNullableListFromJson( + List? collectionType, [ + List? defaultValue, +]) { + if (collectionType == null) { + return defaultValue; + } + + return collectionType + .map((e) => collectionTypeFromJson(e.toString())) + .toList(); +} + +String? collectionTypeOptionsNullableToJson( + enums.CollectionTypeOptions? collectionTypeOptions) { + return collectionTypeOptions?.value; +} + +String? collectionTypeOptionsToJson( + enums.CollectionTypeOptions collectionTypeOptions) { + return collectionTypeOptions.value; +} + +enums.CollectionTypeOptions collectionTypeOptionsFromJson( + Object? collectionTypeOptions, [ + enums.CollectionTypeOptions? defaultValue, +]) { + return enums.CollectionTypeOptions.values + .firstWhereOrNull((e) => e.value == collectionTypeOptions) ?? + defaultValue ?? + enums.CollectionTypeOptions.swaggerGeneratedUnknown; +} + +enums.CollectionTypeOptions? collectionTypeOptionsNullableFromJson( + Object? collectionTypeOptions, [ + enums.CollectionTypeOptions? defaultValue, +]) { + if (collectionTypeOptions == null) { + return null; + } + return enums.CollectionTypeOptions.values + .firstWhereOrNull((e) => e.value == collectionTypeOptions) ?? + defaultValue; +} + +String collectionTypeOptionsExplodedListToJson( + List? collectionTypeOptions) { + return collectionTypeOptions?.map((e) => e.value!).join(',') ?? ''; +} + +List collectionTypeOptionsListToJson( + List? collectionTypeOptions) { + if (collectionTypeOptions == null) { + return []; + } + + return collectionTypeOptions.map((e) => e.value!).toList(); +} + +List collectionTypeOptionsListFromJson( + List? collectionTypeOptions, [ + List? defaultValue, +]) { + if (collectionTypeOptions == null) { + return defaultValue ?? []; + } + + return collectionTypeOptions + .map((e) => collectionTypeOptionsFromJson(e.toString())) + .toList(); +} + +List? collectionTypeOptionsNullableListFromJson( + List? collectionTypeOptions, [ + List? defaultValue, +]) { + if (collectionTypeOptions == null) { + return defaultValue; + } + + return collectionTypeOptions + .map((e) => collectionTypeOptionsFromJson(e.toString())) + .toList(); +} + +String? dayOfWeekNullableToJson(enums.DayOfWeek? dayOfWeek) { + return dayOfWeek?.value; +} + +String? dayOfWeekToJson(enums.DayOfWeek dayOfWeek) { + return dayOfWeek.value; +} + +enums.DayOfWeek dayOfWeekFromJson( + Object? dayOfWeek, [ + enums.DayOfWeek? defaultValue, +]) { + return enums.DayOfWeek.values.firstWhereOrNull((e) => e.value == dayOfWeek) ?? + defaultValue ?? + enums.DayOfWeek.swaggerGeneratedUnknown; +} + +enums.DayOfWeek? dayOfWeekNullableFromJson( + Object? dayOfWeek, [ + enums.DayOfWeek? defaultValue, +]) { + if (dayOfWeek == null) { + return null; + } + return enums.DayOfWeek.values.firstWhereOrNull((e) => e.value == dayOfWeek) ?? + defaultValue; +} + +String dayOfWeekExplodedListToJson(List? dayOfWeek) { + return dayOfWeek?.map((e) => e.value!).join(',') ?? ''; +} + +List dayOfWeekListToJson(List? dayOfWeek) { + if (dayOfWeek == null) { + return []; + } + + return dayOfWeek.map((e) => e.value!).toList(); +} + +List dayOfWeekListFromJson( + List? dayOfWeek, [ + List? defaultValue, +]) { + if (dayOfWeek == null) { + return defaultValue ?? []; + } + + return dayOfWeek.map((e) => dayOfWeekFromJson(e.toString())).toList(); +} + +List? dayOfWeekNullableListFromJson( + List? dayOfWeek, [ + List? defaultValue, +]) { + if (dayOfWeek == null) { + return defaultValue; + } + + return dayOfWeek.map((e) => dayOfWeekFromJson(e.toString())).toList(); +} + +String? dayPatternNullableToJson(enums.DayPattern? dayPattern) { + return dayPattern?.value; +} + +String? dayPatternToJson(enums.DayPattern dayPattern) { + return dayPattern.value; +} + +enums.DayPattern dayPatternFromJson( + Object? dayPattern, [ + enums.DayPattern? defaultValue, +]) { + return enums.DayPattern.values + .firstWhereOrNull((e) => e.value == dayPattern) ?? + defaultValue ?? + enums.DayPattern.swaggerGeneratedUnknown; +} + +enums.DayPattern? dayPatternNullableFromJson( + Object? dayPattern, [ + enums.DayPattern? defaultValue, +]) { + if (dayPattern == null) { + return null; + } + return enums.DayPattern.values + .firstWhereOrNull((e) => e.value == dayPattern) ?? + defaultValue; +} + +String dayPatternExplodedListToJson(List? dayPattern) { + return dayPattern?.map((e) => e.value!).join(',') ?? ''; +} + +List dayPatternListToJson(List? dayPattern) { + if (dayPattern == null) { + return []; + } + + return dayPattern.map((e) => e.value!).toList(); +} + +List dayPatternListFromJson( + List? dayPattern, [ + List? defaultValue, +]) { + if (dayPattern == null) { + return defaultValue ?? []; + } + + return dayPattern.map((e) => dayPatternFromJson(e.toString())).toList(); +} + +List? dayPatternNullableListFromJson( + List? dayPattern, [ + List? defaultValue, +]) { + if (dayPattern == null) { + return defaultValue; + } + + return dayPattern.map((e) => dayPatternFromJson(e.toString())).toList(); +} + +String? dlnaProfileTypeNullableToJson(enums.DlnaProfileType? dlnaProfileType) { + return dlnaProfileType?.value; +} + +String? dlnaProfileTypeToJson(enums.DlnaProfileType dlnaProfileType) { + return dlnaProfileType.value; +} + +enums.DlnaProfileType dlnaProfileTypeFromJson( + Object? dlnaProfileType, [ + enums.DlnaProfileType? defaultValue, +]) { + return enums.DlnaProfileType.values + .firstWhereOrNull((e) => e.value == dlnaProfileType) ?? + defaultValue ?? + enums.DlnaProfileType.swaggerGeneratedUnknown; +} + +enums.DlnaProfileType? dlnaProfileTypeNullableFromJson( + Object? dlnaProfileType, [ + enums.DlnaProfileType? defaultValue, +]) { + if (dlnaProfileType == null) { + return null; + } + return enums.DlnaProfileType.values + .firstWhereOrNull((e) => e.value == dlnaProfileType) ?? + defaultValue; +} + +String dlnaProfileTypeExplodedListToJson( + List? dlnaProfileType) { + return dlnaProfileType?.map((e) => e.value!).join(',') ?? ''; +} + +List dlnaProfileTypeListToJson( + List? dlnaProfileType) { + if (dlnaProfileType == null) { + return []; + } + + return dlnaProfileType.map((e) => e.value!).toList(); +} + +List dlnaProfileTypeListFromJson( + List? dlnaProfileType, [ + List? defaultValue, +]) { + if (dlnaProfileType == null) { + return defaultValue ?? []; + } + + return dlnaProfileType + .map((e) => dlnaProfileTypeFromJson(e.toString())) + .toList(); +} + +List? dlnaProfileTypeNullableListFromJson( + List? dlnaProfileType, [ + List? defaultValue, +]) { + if (dlnaProfileType == null) { + return defaultValue; + } + + return dlnaProfileType + .map((e) => dlnaProfileTypeFromJson(e.toString())) + .toList(); +} + +String? downMixStereoAlgorithmsNullableToJson( + enums.DownMixStereoAlgorithms? downMixStereoAlgorithms) { + return downMixStereoAlgorithms?.value; +} + +String? downMixStereoAlgorithmsToJson( + enums.DownMixStereoAlgorithms downMixStereoAlgorithms) { + return downMixStereoAlgorithms.value; +} + +enums.DownMixStereoAlgorithms downMixStereoAlgorithmsFromJson( + Object? downMixStereoAlgorithms, [ + enums.DownMixStereoAlgorithms? defaultValue, +]) { + return enums.DownMixStereoAlgorithms.values + .firstWhereOrNull((e) => e.value == downMixStereoAlgorithms) ?? + defaultValue ?? + enums.DownMixStereoAlgorithms.swaggerGeneratedUnknown; +} + +enums.DownMixStereoAlgorithms? downMixStereoAlgorithmsNullableFromJson( + Object? downMixStereoAlgorithms, [ + enums.DownMixStereoAlgorithms? defaultValue, +]) { + if (downMixStereoAlgorithms == null) { + return null; + } + return enums.DownMixStereoAlgorithms.values + .firstWhereOrNull((e) => e.value == downMixStereoAlgorithms) ?? + defaultValue; +} + +String downMixStereoAlgorithmsExplodedListToJson( + List? downMixStereoAlgorithms) { + return downMixStereoAlgorithms?.map((e) => e.value!).join(',') ?? ''; +} + +List downMixStereoAlgorithmsListToJson( + List? downMixStereoAlgorithms) { + if (downMixStereoAlgorithms == null) { + return []; + } + + return downMixStereoAlgorithms.map((e) => e.value!).toList(); +} + +List downMixStereoAlgorithmsListFromJson( + List? downMixStereoAlgorithms, [ + List? defaultValue, +]) { + if (downMixStereoAlgorithms == null) { + return defaultValue ?? []; + } + + return downMixStereoAlgorithms + .map((e) => downMixStereoAlgorithmsFromJson(e.toString())) + .toList(); +} + +List? + downMixStereoAlgorithmsNullableListFromJson( + List? downMixStereoAlgorithms, [ + List? defaultValue, +]) { + if (downMixStereoAlgorithms == null) { + return defaultValue; + } + + return downMixStereoAlgorithms + .map((e) => downMixStereoAlgorithmsFromJson(e.toString())) + .toList(); +} + +String? dynamicDayOfWeekNullableToJson( + enums.DynamicDayOfWeek? dynamicDayOfWeek) { + return dynamicDayOfWeek?.value; +} + +String? dynamicDayOfWeekToJson(enums.DynamicDayOfWeek dynamicDayOfWeek) { + return dynamicDayOfWeek.value; +} + +enums.DynamicDayOfWeek dynamicDayOfWeekFromJson( + Object? dynamicDayOfWeek, [ + enums.DynamicDayOfWeek? defaultValue, +]) { + return enums.DynamicDayOfWeek.values + .firstWhereOrNull((e) => e.value == dynamicDayOfWeek) ?? + defaultValue ?? + enums.DynamicDayOfWeek.swaggerGeneratedUnknown; +} + +enums.DynamicDayOfWeek? dynamicDayOfWeekNullableFromJson( + Object? dynamicDayOfWeek, [ + enums.DynamicDayOfWeek? defaultValue, +]) { + if (dynamicDayOfWeek == null) { + return null; + } + return enums.DynamicDayOfWeek.values + .firstWhereOrNull((e) => e.value == dynamicDayOfWeek) ?? + defaultValue; +} + +String dynamicDayOfWeekExplodedListToJson( + List? dynamicDayOfWeek) { + return dynamicDayOfWeek?.map((e) => e.value!).join(',') ?? ''; +} + +List dynamicDayOfWeekListToJson( + List? dynamicDayOfWeek) { + if (dynamicDayOfWeek == null) { + return []; + } + + return dynamicDayOfWeek.map((e) => e.value!).toList(); +} + +List dynamicDayOfWeekListFromJson( + List? dynamicDayOfWeek, [ + List? defaultValue, +]) { + if (dynamicDayOfWeek == null) { + return defaultValue ?? []; + } + + return dynamicDayOfWeek + .map((e) => dynamicDayOfWeekFromJson(e.toString())) + .toList(); +} + +List? dynamicDayOfWeekNullableListFromJson( + List? dynamicDayOfWeek, [ + List? defaultValue, +]) { + if (dynamicDayOfWeek == null) { + return defaultValue; + } + + return dynamicDayOfWeek + .map((e) => dynamicDayOfWeekFromJson(e.toString())) + .toList(); +} + +String? embeddedSubtitleOptionsNullableToJson( + enums.EmbeddedSubtitleOptions? embeddedSubtitleOptions) { + return embeddedSubtitleOptions?.value; +} + +String? embeddedSubtitleOptionsToJson( + enums.EmbeddedSubtitleOptions embeddedSubtitleOptions) { + return embeddedSubtitleOptions.value; +} + +enums.EmbeddedSubtitleOptions embeddedSubtitleOptionsFromJson( + Object? embeddedSubtitleOptions, [ + enums.EmbeddedSubtitleOptions? defaultValue, +]) { + return enums.EmbeddedSubtitleOptions.values + .firstWhereOrNull((e) => e.value == embeddedSubtitleOptions) ?? + defaultValue ?? + enums.EmbeddedSubtitleOptions.swaggerGeneratedUnknown; +} + +enums.EmbeddedSubtitleOptions? embeddedSubtitleOptionsNullableFromJson( + Object? embeddedSubtitleOptions, [ + enums.EmbeddedSubtitleOptions? defaultValue, +]) { + if (embeddedSubtitleOptions == null) { + return null; + } + return enums.EmbeddedSubtitleOptions.values + .firstWhereOrNull((e) => e.value == embeddedSubtitleOptions) ?? + defaultValue; +} + +String embeddedSubtitleOptionsExplodedListToJson( + List? embeddedSubtitleOptions) { + return embeddedSubtitleOptions?.map((e) => e.value!).join(',') ?? ''; +} + +List embeddedSubtitleOptionsListToJson( + List? embeddedSubtitleOptions) { + if (embeddedSubtitleOptions == null) { + return []; + } + + return embeddedSubtitleOptions.map((e) => e.value!).toList(); +} + +List embeddedSubtitleOptionsListFromJson( + List? embeddedSubtitleOptions, [ + List? defaultValue, +]) { + if (embeddedSubtitleOptions == null) { + return defaultValue ?? []; + } + + return embeddedSubtitleOptions + .map((e) => embeddedSubtitleOptionsFromJson(e.toString())) + .toList(); +} + +List? + embeddedSubtitleOptionsNullableListFromJson( + List? embeddedSubtitleOptions, [ + List? defaultValue, +]) { + if (embeddedSubtitleOptions == null) { + return defaultValue; + } + + return embeddedSubtitleOptions + .map((e) => embeddedSubtitleOptionsFromJson(e.toString())) + .toList(); +} + +String? encodingContextNullableToJson(enums.EncodingContext? encodingContext) { + return encodingContext?.value; +} + +String? encodingContextToJson(enums.EncodingContext encodingContext) { + return encodingContext.value; +} + +enums.EncodingContext encodingContextFromJson( + Object? encodingContext, [ + enums.EncodingContext? defaultValue, +]) { + return enums.EncodingContext.values + .firstWhereOrNull((e) => e.value == encodingContext) ?? + defaultValue ?? + enums.EncodingContext.swaggerGeneratedUnknown; +} + +enums.EncodingContext? encodingContextNullableFromJson( + Object? encodingContext, [ + enums.EncodingContext? defaultValue, +]) { + if (encodingContext == null) { + return null; + } + return enums.EncodingContext.values + .firstWhereOrNull((e) => e.value == encodingContext) ?? + defaultValue; +} + +String encodingContextExplodedListToJson( + List? encodingContext) { + return encodingContext?.map((e) => e.value!).join(',') ?? ''; +} + +List encodingContextListToJson( + List? encodingContext) { + if (encodingContext == null) { + return []; + } + + return encodingContext.map((e) => e.value!).toList(); +} + +List encodingContextListFromJson( + List? encodingContext, [ + List? defaultValue, +]) { + if (encodingContext == null) { + return defaultValue ?? []; + } + + return encodingContext + .map((e) => encodingContextFromJson(e.toString())) + .toList(); +} + +List? encodingContextNullableListFromJson( + List? encodingContext, [ + List? defaultValue, +]) { + if (encodingContext == null) { + return defaultValue; + } + + return encodingContext + .map((e) => encodingContextFromJson(e.toString())) + .toList(); +} + +String? externalIdMediaTypeNullableToJson( + enums.ExternalIdMediaType? externalIdMediaType) { + return externalIdMediaType?.value; +} + +String? externalIdMediaTypeToJson( + enums.ExternalIdMediaType externalIdMediaType) { + return externalIdMediaType.value; +} + +enums.ExternalIdMediaType externalIdMediaTypeFromJson( + Object? externalIdMediaType, [ + enums.ExternalIdMediaType? defaultValue, +]) { + return enums.ExternalIdMediaType.values + .firstWhereOrNull((e) => e.value == externalIdMediaType) ?? + defaultValue ?? + enums.ExternalIdMediaType.swaggerGeneratedUnknown; +} + +enums.ExternalIdMediaType? externalIdMediaTypeNullableFromJson( + Object? externalIdMediaType, [ + enums.ExternalIdMediaType? defaultValue, +]) { + if (externalIdMediaType == null) { + return null; + } + return enums.ExternalIdMediaType.values + .firstWhereOrNull((e) => e.value == externalIdMediaType) ?? + defaultValue; +} + +String externalIdMediaTypeExplodedListToJson( + List? externalIdMediaType) { + return externalIdMediaType?.map((e) => e.value!).join(',') ?? ''; +} + +List externalIdMediaTypeListToJson( + List? externalIdMediaType) { + if (externalIdMediaType == null) { + return []; + } + + return externalIdMediaType.map((e) => e.value!).toList(); +} + +List externalIdMediaTypeListFromJson( + List? externalIdMediaType, [ + List? defaultValue, +]) { + if (externalIdMediaType == null) { + return defaultValue ?? []; + } + + return externalIdMediaType + .map((e) => externalIdMediaTypeFromJson(e.toString())) + .toList(); +} + +List? externalIdMediaTypeNullableListFromJson( + List? externalIdMediaType, [ + List? defaultValue, +]) { + if (externalIdMediaType == null) { + return defaultValue; + } + + return externalIdMediaType + .map((e) => externalIdMediaTypeFromJson(e.toString())) + .toList(); +} + +String? extraTypeNullableToJson(enums.ExtraType? extraType) { + return extraType?.value; +} + +String? extraTypeToJson(enums.ExtraType extraType) { + return extraType.value; +} + +enums.ExtraType extraTypeFromJson( + Object? extraType, [ + enums.ExtraType? defaultValue, +]) { + return enums.ExtraType.values.firstWhereOrNull((e) => e.value == extraType) ?? + defaultValue ?? + enums.ExtraType.swaggerGeneratedUnknown; +} + +enums.ExtraType? extraTypeNullableFromJson( + Object? extraType, [ + enums.ExtraType? defaultValue, +]) { + if (extraType == null) { + return null; + } + return enums.ExtraType.values.firstWhereOrNull((e) => e.value == extraType) ?? + defaultValue; +} + +String extraTypeExplodedListToJson(List? extraType) { + return extraType?.map((e) => e.value!).join(',') ?? ''; +} + +List extraTypeListToJson(List? extraType) { + if (extraType == null) { + return []; + } + + return extraType.map((e) => e.value!).toList(); +} + +List extraTypeListFromJson( + List? extraType, [ + List? defaultValue, +]) { + if (extraType == null) { + return defaultValue ?? []; + } + + return extraType.map((e) => extraTypeFromJson(e.toString())).toList(); +} + +List? extraTypeNullableListFromJson( + List? extraType, [ + List? defaultValue, +]) { + if (extraType == null) { + return defaultValue; + } + + return extraType.map((e) => extraTypeFromJson(e.toString())).toList(); +} + +String? fileSystemEntryTypeNullableToJson( + enums.FileSystemEntryType? fileSystemEntryType) { + return fileSystemEntryType?.value; +} + +String? fileSystemEntryTypeToJson( + enums.FileSystemEntryType fileSystemEntryType) { + return fileSystemEntryType.value; +} + +enums.FileSystemEntryType fileSystemEntryTypeFromJson( + Object? fileSystemEntryType, [ + enums.FileSystemEntryType? defaultValue, +]) { + return enums.FileSystemEntryType.values + .firstWhereOrNull((e) => e.value == fileSystemEntryType) ?? + defaultValue ?? + enums.FileSystemEntryType.swaggerGeneratedUnknown; +} + +enums.FileSystemEntryType? fileSystemEntryTypeNullableFromJson( + Object? fileSystemEntryType, [ + enums.FileSystemEntryType? defaultValue, +]) { + if (fileSystemEntryType == null) { + return null; + } + return enums.FileSystemEntryType.values + .firstWhereOrNull((e) => e.value == fileSystemEntryType) ?? + defaultValue; +} + +String fileSystemEntryTypeExplodedListToJson( + List? fileSystemEntryType) { + return fileSystemEntryType?.map((e) => e.value!).join(',') ?? ''; +} + +List fileSystemEntryTypeListToJson( + List? fileSystemEntryType) { + if (fileSystemEntryType == null) { + return []; + } + + return fileSystemEntryType.map((e) => e.value!).toList(); +} + +List fileSystemEntryTypeListFromJson( + List? fileSystemEntryType, [ + List? defaultValue, +]) { + if (fileSystemEntryType == null) { + return defaultValue ?? []; + } + + return fileSystemEntryType + .map((e) => fileSystemEntryTypeFromJson(e.toString())) + .toList(); +} + +List? fileSystemEntryTypeNullableListFromJson( + List? fileSystemEntryType, [ + List? defaultValue, +]) { + if (fileSystemEntryType == null) { + return defaultValue; + } + + return fileSystemEntryType + .map((e) => fileSystemEntryTypeFromJson(e.toString())) + .toList(); +} + +String? forgotPasswordActionNullableToJson( + enums.ForgotPasswordAction? forgotPasswordAction) { + return forgotPasswordAction?.value; +} + +String? forgotPasswordActionToJson( + enums.ForgotPasswordAction forgotPasswordAction) { + return forgotPasswordAction.value; +} + +enums.ForgotPasswordAction forgotPasswordActionFromJson( + Object? forgotPasswordAction, [ + enums.ForgotPasswordAction? defaultValue, +]) { + return enums.ForgotPasswordAction.values + .firstWhereOrNull((e) => e.value == forgotPasswordAction) ?? + defaultValue ?? + enums.ForgotPasswordAction.swaggerGeneratedUnknown; +} + +enums.ForgotPasswordAction? forgotPasswordActionNullableFromJson( + Object? forgotPasswordAction, [ + enums.ForgotPasswordAction? defaultValue, +]) { + if (forgotPasswordAction == null) { + return null; + } + return enums.ForgotPasswordAction.values + .firstWhereOrNull((e) => e.value == forgotPasswordAction) ?? + defaultValue; +} + +String forgotPasswordActionExplodedListToJson( + List? forgotPasswordAction) { + return forgotPasswordAction?.map((e) => e.value!).join(',') ?? ''; +} + +List forgotPasswordActionListToJson( + List? forgotPasswordAction) { + if (forgotPasswordAction == null) { + return []; + } + + return forgotPasswordAction.map((e) => e.value!).toList(); +} + +List forgotPasswordActionListFromJson( + List? forgotPasswordAction, [ + List? defaultValue, +]) { + if (forgotPasswordAction == null) { + return defaultValue ?? []; + } + + return forgotPasswordAction + .map((e) => forgotPasswordActionFromJson(e.toString())) + .toList(); +} + +List? forgotPasswordActionNullableListFromJson( + List? forgotPasswordAction, [ + List? defaultValue, +]) { + if (forgotPasswordAction == null) { + return defaultValue; + } + + return forgotPasswordAction + .map((e) => forgotPasswordActionFromJson(e.toString())) + .toList(); +} + +String? generalCommandTypeNullableToJson( + enums.GeneralCommandType? generalCommandType) { + return generalCommandType?.value; +} + +String? generalCommandTypeToJson(enums.GeneralCommandType generalCommandType) { + return generalCommandType.value; +} + +enums.GeneralCommandType generalCommandTypeFromJson( + Object? generalCommandType, [ + enums.GeneralCommandType? defaultValue, +]) { + return enums.GeneralCommandType.values + .firstWhereOrNull((e) => e.value == generalCommandType) ?? + defaultValue ?? + enums.GeneralCommandType.swaggerGeneratedUnknown; +} + +enums.GeneralCommandType? generalCommandTypeNullableFromJson( + Object? generalCommandType, [ + enums.GeneralCommandType? defaultValue, +]) { + if (generalCommandType == null) { + return null; + } + return enums.GeneralCommandType.values + .firstWhereOrNull((e) => e.value == generalCommandType) ?? + defaultValue; +} + +String generalCommandTypeExplodedListToJson( + List? generalCommandType) { + return generalCommandType?.map((e) => e.value!).join(',') ?? ''; +} + +List generalCommandTypeListToJson( + List? generalCommandType) { + if (generalCommandType == null) { + return []; + } + + return generalCommandType.map((e) => e.value!).toList(); +} + +List generalCommandTypeListFromJson( + List? generalCommandType, [ + List? defaultValue, +]) { + if (generalCommandType == null) { + return defaultValue ?? []; + } + + return generalCommandType + .map((e) => generalCommandTypeFromJson(e.toString())) + .toList(); +} + +List? generalCommandTypeNullableListFromJson( + List? generalCommandType, [ + List? defaultValue, +]) { + if (generalCommandType == null) { + return defaultValue; + } + + return generalCommandType + .map((e) => generalCommandTypeFromJson(e.toString())) + .toList(); +} + +String? groupQueueModeNullableToJson(enums.GroupQueueMode? groupQueueMode) { + return groupQueueMode?.value; +} + +String? groupQueueModeToJson(enums.GroupQueueMode groupQueueMode) { + return groupQueueMode.value; +} + +enums.GroupQueueMode groupQueueModeFromJson( + Object? groupQueueMode, [ + enums.GroupQueueMode? defaultValue, +]) { + return enums.GroupQueueMode.values + .firstWhereOrNull((e) => e.value == groupQueueMode) ?? + defaultValue ?? + enums.GroupQueueMode.swaggerGeneratedUnknown; +} + +enums.GroupQueueMode? groupQueueModeNullableFromJson( + Object? groupQueueMode, [ + enums.GroupQueueMode? defaultValue, +]) { + if (groupQueueMode == null) { + return null; + } + return enums.GroupQueueMode.values + .firstWhereOrNull((e) => e.value == groupQueueMode) ?? + defaultValue; +} + +String groupQueueModeExplodedListToJson( + List? groupQueueMode) { + return groupQueueMode?.map((e) => e.value!).join(',') ?? ''; +} + +List groupQueueModeListToJson( + List? groupQueueMode) { + if (groupQueueMode == null) { + return []; + } + + return groupQueueMode.map((e) => e.value!).toList(); +} + +List groupQueueModeListFromJson( + List? groupQueueMode, [ + List? defaultValue, +]) { + if (groupQueueMode == null) { + return defaultValue ?? []; + } + + return groupQueueMode + .map((e) => groupQueueModeFromJson(e.toString())) + .toList(); +} + +List? groupQueueModeNullableListFromJson( + List? groupQueueMode, [ + List? defaultValue, +]) { + if (groupQueueMode == null) { + return defaultValue; + } + + return groupQueueMode + .map((e) => groupQueueModeFromJson(e.toString())) + .toList(); +} + +String? groupRepeatModeNullableToJson(enums.GroupRepeatMode? groupRepeatMode) { + return groupRepeatMode?.value; +} + +String? groupRepeatModeToJson(enums.GroupRepeatMode groupRepeatMode) { + return groupRepeatMode.value; +} + +enums.GroupRepeatMode groupRepeatModeFromJson( + Object? groupRepeatMode, [ + enums.GroupRepeatMode? defaultValue, +]) { + return enums.GroupRepeatMode.values + .firstWhereOrNull((e) => e.value == groupRepeatMode) ?? + defaultValue ?? + enums.GroupRepeatMode.swaggerGeneratedUnknown; +} + +enums.GroupRepeatMode? groupRepeatModeNullableFromJson( + Object? groupRepeatMode, [ + enums.GroupRepeatMode? defaultValue, +]) { + if (groupRepeatMode == null) { + return null; + } + return enums.GroupRepeatMode.values + .firstWhereOrNull((e) => e.value == groupRepeatMode) ?? + defaultValue; +} + +String groupRepeatModeExplodedListToJson( + List? groupRepeatMode) { + return groupRepeatMode?.map((e) => e.value!).join(',') ?? ''; +} + +List groupRepeatModeListToJson( + List? groupRepeatMode) { + if (groupRepeatMode == null) { + return []; + } + + return groupRepeatMode.map((e) => e.value!).toList(); +} + +List groupRepeatModeListFromJson( + List? groupRepeatMode, [ + List? defaultValue, +]) { + if (groupRepeatMode == null) { + return defaultValue ?? []; + } + + return groupRepeatMode + .map((e) => groupRepeatModeFromJson(e.toString())) + .toList(); +} + +List? groupRepeatModeNullableListFromJson( + List? groupRepeatMode, [ + List? defaultValue, +]) { + if (groupRepeatMode == null) { + return defaultValue; + } + + return groupRepeatMode + .map((e) => groupRepeatModeFromJson(e.toString())) + .toList(); +} + +String? groupShuffleModeNullableToJson( + enums.GroupShuffleMode? groupShuffleMode) { + return groupShuffleMode?.value; +} + +String? groupShuffleModeToJson(enums.GroupShuffleMode groupShuffleMode) { + return groupShuffleMode.value; +} + +enums.GroupShuffleMode groupShuffleModeFromJson( + Object? groupShuffleMode, [ + enums.GroupShuffleMode? defaultValue, +]) { + return enums.GroupShuffleMode.values + .firstWhereOrNull((e) => e.value == groupShuffleMode) ?? + defaultValue ?? + enums.GroupShuffleMode.swaggerGeneratedUnknown; +} + +enums.GroupShuffleMode? groupShuffleModeNullableFromJson( + Object? groupShuffleMode, [ + enums.GroupShuffleMode? defaultValue, +]) { + if (groupShuffleMode == null) { + return null; + } + return enums.GroupShuffleMode.values + .firstWhereOrNull((e) => e.value == groupShuffleMode) ?? + defaultValue; +} + +String groupShuffleModeExplodedListToJson( + List? groupShuffleMode) { + return groupShuffleMode?.map((e) => e.value!).join(',') ?? ''; +} + +List groupShuffleModeListToJson( + List? groupShuffleMode) { + if (groupShuffleMode == null) { + return []; + } + + return groupShuffleMode.map((e) => e.value!).toList(); +} + +List groupShuffleModeListFromJson( + List? groupShuffleMode, [ + List? defaultValue, +]) { + if (groupShuffleMode == null) { + return defaultValue ?? []; + } + + return groupShuffleMode + .map((e) => groupShuffleModeFromJson(e.toString())) + .toList(); +} + +List? groupShuffleModeNullableListFromJson( + List? groupShuffleMode, [ + List? defaultValue, +]) { + if (groupShuffleMode == null) { + return defaultValue; + } + + return groupShuffleMode + .map((e) => groupShuffleModeFromJson(e.toString())) + .toList(); +} + +String? groupStateTypeNullableToJson(enums.GroupStateType? groupStateType) { + return groupStateType?.value; +} + +String? groupStateTypeToJson(enums.GroupStateType groupStateType) { + return groupStateType.value; +} + +enums.GroupStateType groupStateTypeFromJson( + Object? groupStateType, [ + enums.GroupStateType? defaultValue, +]) { + return enums.GroupStateType.values + .firstWhereOrNull((e) => e.value == groupStateType) ?? + defaultValue ?? + enums.GroupStateType.swaggerGeneratedUnknown; +} + +enums.GroupStateType? groupStateTypeNullableFromJson( + Object? groupStateType, [ + enums.GroupStateType? defaultValue, +]) { + if (groupStateType == null) { + return null; + } + return enums.GroupStateType.values + .firstWhereOrNull((e) => e.value == groupStateType) ?? + defaultValue; +} + +String groupStateTypeExplodedListToJson( + List? groupStateType) { + return groupStateType?.map((e) => e.value!).join(',') ?? ''; +} + +List groupStateTypeListToJson( + List? groupStateType) { + if (groupStateType == null) { + return []; + } + + return groupStateType.map((e) => e.value!).toList(); +} + +List groupStateTypeListFromJson( + List? groupStateType, [ + List? defaultValue, +]) { + if (groupStateType == null) { + return defaultValue ?? []; + } + + return groupStateType + .map((e) => groupStateTypeFromJson(e.toString())) + .toList(); +} + +List? groupStateTypeNullableListFromJson( + List? groupStateType, [ + List? defaultValue, +]) { + if (groupStateType == null) { + return defaultValue; + } + + return groupStateType + .map((e) => groupStateTypeFromJson(e.toString())) + .toList(); +} + +String? groupUpdateTypeNullableToJson(enums.GroupUpdateType? groupUpdateType) { + return groupUpdateType?.value; +} + +String? groupUpdateTypeToJson(enums.GroupUpdateType groupUpdateType) { + return groupUpdateType.value; +} + +enums.GroupUpdateType groupUpdateTypeFromJson( + Object? groupUpdateType, [ + enums.GroupUpdateType? defaultValue, +]) { + return enums.GroupUpdateType.values + .firstWhereOrNull((e) => e.value == groupUpdateType) ?? + defaultValue ?? + enums.GroupUpdateType.swaggerGeneratedUnknown; +} + +enums.GroupUpdateType? groupUpdateTypeNullableFromJson( + Object? groupUpdateType, [ + enums.GroupUpdateType? defaultValue, +]) { + if (groupUpdateType == null) { + return null; + } + return enums.GroupUpdateType.values + .firstWhereOrNull((e) => e.value == groupUpdateType) ?? + defaultValue; +} + +String groupUpdateTypeExplodedListToJson( + List? groupUpdateType) { + return groupUpdateType?.map((e) => e.value!).join(',') ?? ''; +} + +List groupUpdateTypeListToJson( + List? groupUpdateType) { + if (groupUpdateType == null) { + return []; + } + + return groupUpdateType.map((e) => e.value!).toList(); +} + +List groupUpdateTypeListFromJson( + List? groupUpdateType, [ + List? defaultValue, +]) { + if (groupUpdateType == null) { + return defaultValue ?? []; + } + + return groupUpdateType + .map((e) => groupUpdateTypeFromJson(e.toString())) + .toList(); +} + +List? groupUpdateTypeNullableListFromJson( + List? groupUpdateType, [ + List? defaultValue, +]) { + if (groupUpdateType == null) { + return defaultValue; + } + + return groupUpdateType + .map((e) => groupUpdateTypeFromJson(e.toString())) + .toList(); +} + +String? hardwareEncodingTypeNullableToJson( + enums.HardwareEncodingType? hardwareEncodingType) { + return hardwareEncodingType?.value; +} + +String? hardwareEncodingTypeToJson( + enums.HardwareEncodingType hardwareEncodingType) { + return hardwareEncodingType.value; +} + +enums.HardwareEncodingType hardwareEncodingTypeFromJson( + Object? hardwareEncodingType, [ + enums.HardwareEncodingType? defaultValue, +]) { + return enums.HardwareEncodingType.values + .firstWhereOrNull((e) => e.value == hardwareEncodingType) ?? + defaultValue ?? + enums.HardwareEncodingType.swaggerGeneratedUnknown; +} + +enums.HardwareEncodingType? hardwareEncodingTypeNullableFromJson( + Object? hardwareEncodingType, [ + enums.HardwareEncodingType? defaultValue, +]) { + if (hardwareEncodingType == null) { + return null; + } + return enums.HardwareEncodingType.values + .firstWhereOrNull((e) => e.value == hardwareEncodingType) ?? + defaultValue; +} + +String hardwareEncodingTypeExplodedListToJson( + List? hardwareEncodingType) { + return hardwareEncodingType?.map((e) => e.value!).join(',') ?? ''; +} + +List hardwareEncodingTypeListToJson( + List? hardwareEncodingType) { + if (hardwareEncodingType == null) { + return []; + } + + return hardwareEncodingType.map((e) => e.value!).toList(); +} + +List hardwareEncodingTypeListFromJson( + List? hardwareEncodingType, [ + List? defaultValue, +]) { + if (hardwareEncodingType == null) { + return defaultValue ?? []; + } + + return hardwareEncodingType + .map((e) => hardwareEncodingTypeFromJson(e.toString())) + .toList(); +} + +List? hardwareEncodingTypeNullableListFromJson( + List? hardwareEncodingType, [ + List? defaultValue, +]) { + if (hardwareEncodingType == null) { + return defaultValue; + } + + return hardwareEncodingType + .map((e) => hardwareEncodingTypeFromJson(e.toString())) + .toList(); +} + +String? imageFormatNullableToJson(enums.ImageFormat? imageFormat) { + return imageFormat?.value; +} + +String? imageFormatToJson(enums.ImageFormat imageFormat) { + return imageFormat.value; +} + +enums.ImageFormat imageFormatFromJson( + Object? imageFormat, [ + enums.ImageFormat? defaultValue, +]) { + return enums.ImageFormat.values + .firstWhereOrNull((e) => e.value == imageFormat) ?? + defaultValue ?? + enums.ImageFormat.swaggerGeneratedUnknown; +} + +enums.ImageFormat? imageFormatNullableFromJson( + Object? imageFormat, [ + enums.ImageFormat? defaultValue, +]) { + if (imageFormat == null) { + return null; + } + return enums.ImageFormat.values + .firstWhereOrNull((e) => e.value == imageFormat) ?? + defaultValue; +} + +String imageFormatExplodedListToJson(List? imageFormat) { + return imageFormat?.map((e) => e.value!).join(',') ?? ''; +} + +List imageFormatListToJson(List? imageFormat) { + if (imageFormat == null) { + return []; + } + + return imageFormat.map((e) => e.value!).toList(); +} + +List imageFormatListFromJson( + List? imageFormat, [ + List? defaultValue, +]) { + if (imageFormat == null) { + return defaultValue ?? []; + } + + return imageFormat.map((e) => imageFormatFromJson(e.toString())).toList(); +} + +List? imageFormatNullableListFromJson( + List? imageFormat, [ + List? defaultValue, +]) { + if (imageFormat == null) { + return defaultValue; + } + + return imageFormat.map((e) => imageFormatFromJson(e.toString())).toList(); +} + +String? imageOrientationNullableToJson( + enums.ImageOrientation? imageOrientation) { + return imageOrientation?.value; +} + +String? imageOrientationToJson(enums.ImageOrientation imageOrientation) { + return imageOrientation.value; +} + +enums.ImageOrientation imageOrientationFromJson( + Object? imageOrientation, [ + enums.ImageOrientation? defaultValue, +]) { + return enums.ImageOrientation.values + .firstWhereOrNull((e) => e.value == imageOrientation) ?? + defaultValue ?? + enums.ImageOrientation.swaggerGeneratedUnknown; +} + +enums.ImageOrientation? imageOrientationNullableFromJson( + Object? imageOrientation, [ + enums.ImageOrientation? defaultValue, +]) { + if (imageOrientation == null) { + return null; + } + return enums.ImageOrientation.values + .firstWhereOrNull((e) => e.value == imageOrientation) ?? + defaultValue; +} + +String imageOrientationExplodedListToJson( + List? imageOrientation) { + return imageOrientation?.map((e) => e.value!).join(',') ?? ''; +} + +List imageOrientationListToJson( + List? imageOrientation) { + if (imageOrientation == null) { + return []; + } + + return imageOrientation.map((e) => e.value!).toList(); +} + +List imageOrientationListFromJson( + List? imageOrientation, [ + List? defaultValue, +]) { + if (imageOrientation == null) { + return defaultValue ?? []; + } + + return imageOrientation + .map((e) => imageOrientationFromJson(e.toString())) + .toList(); +} + +List? imageOrientationNullableListFromJson( + List? imageOrientation, [ + List? defaultValue, +]) { + if (imageOrientation == null) { + return defaultValue; + } + + return imageOrientation + .map((e) => imageOrientationFromJson(e.toString())) + .toList(); +} + +String? imageResolutionNullableToJson(enums.ImageResolution? imageResolution) { + return imageResolution?.value; +} + +String? imageResolutionToJson(enums.ImageResolution imageResolution) { + return imageResolution.value; +} + +enums.ImageResolution imageResolutionFromJson( + Object? imageResolution, [ + enums.ImageResolution? defaultValue, +]) { + return enums.ImageResolution.values + .firstWhereOrNull((e) => e.value == imageResolution) ?? + defaultValue ?? + enums.ImageResolution.swaggerGeneratedUnknown; +} + +enums.ImageResolution? imageResolutionNullableFromJson( + Object? imageResolution, [ + enums.ImageResolution? defaultValue, +]) { + if (imageResolution == null) { + return null; + } + return enums.ImageResolution.values + .firstWhereOrNull((e) => e.value == imageResolution) ?? + defaultValue; +} + +String imageResolutionExplodedListToJson( + List? imageResolution) { + return imageResolution?.map((e) => e.value!).join(',') ?? ''; +} + +List imageResolutionListToJson( + List? imageResolution) { + if (imageResolution == null) { + return []; + } + + return imageResolution.map((e) => e.value!).toList(); +} + +List imageResolutionListFromJson( + List? imageResolution, [ + List? defaultValue, +]) { + if (imageResolution == null) { + return defaultValue ?? []; + } + + return imageResolution + .map((e) => imageResolutionFromJson(e.toString())) + .toList(); +} + +List? imageResolutionNullableListFromJson( + List? imageResolution, [ + List? defaultValue, +]) { + if (imageResolution == null) { + return defaultValue; + } + + return imageResolution + .map((e) => imageResolutionFromJson(e.toString())) + .toList(); +} + +String? imageSavingConventionNullableToJson( + enums.ImageSavingConvention? imageSavingConvention) { + return imageSavingConvention?.value; +} + +String? imageSavingConventionToJson( + enums.ImageSavingConvention imageSavingConvention) { + return imageSavingConvention.value; +} + +enums.ImageSavingConvention imageSavingConventionFromJson( + Object? imageSavingConvention, [ + enums.ImageSavingConvention? defaultValue, +]) { + return enums.ImageSavingConvention.values + .firstWhereOrNull((e) => e.value == imageSavingConvention) ?? + defaultValue ?? + enums.ImageSavingConvention.swaggerGeneratedUnknown; +} + +enums.ImageSavingConvention? imageSavingConventionNullableFromJson( + Object? imageSavingConvention, [ + enums.ImageSavingConvention? defaultValue, +]) { + if (imageSavingConvention == null) { + return null; + } + return enums.ImageSavingConvention.values + .firstWhereOrNull((e) => e.value == imageSavingConvention) ?? + defaultValue; +} + +String imageSavingConventionExplodedListToJson( + List? imageSavingConvention) { + return imageSavingConvention?.map((e) => e.value!).join(',') ?? ''; +} + +List imageSavingConventionListToJson( + List? imageSavingConvention) { + if (imageSavingConvention == null) { + return []; + } + + return imageSavingConvention.map((e) => e.value!).toList(); +} + +List imageSavingConventionListFromJson( + List? imageSavingConvention, [ + List? defaultValue, +]) { + if (imageSavingConvention == null) { + return defaultValue ?? []; + } + + return imageSavingConvention + .map((e) => imageSavingConventionFromJson(e.toString())) + .toList(); +} + +List? imageSavingConventionNullableListFromJson( + List? imageSavingConvention, [ + List? defaultValue, +]) { + if (imageSavingConvention == null) { + return defaultValue; + } + + return imageSavingConvention + .map((e) => imageSavingConventionFromJson(e.toString())) + .toList(); +} + +String? imageTypeNullableToJson(enums.ImageType? imageType) { + return imageType?.value; +} + +String? imageTypeToJson(enums.ImageType imageType) { + return imageType.value; +} + +enums.ImageType imageTypeFromJson( + Object? imageType, [ + enums.ImageType? defaultValue, +]) { + return enums.ImageType.values.firstWhereOrNull((e) => e.value == imageType) ?? + defaultValue ?? + enums.ImageType.swaggerGeneratedUnknown; +} + +enums.ImageType? imageTypeNullableFromJson( + Object? imageType, [ + enums.ImageType? defaultValue, +]) { + if (imageType == null) { + return null; + } + return enums.ImageType.values.firstWhereOrNull((e) => e.value == imageType) ?? + defaultValue; +} + +String imageTypeExplodedListToJson(List? imageType) { + return imageType?.map((e) => e.value!).join(',') ?? ''; +} + +List imageTypeListToJson(List? imageType) { + if (imageType == null) { + return []; + } + + return imageType.map((e) => e.value!).toList(); +} + +List imageTypeListFromJson( + List? imageType, [ + List? defaultValue, +]) { + if (imageType == null) { + return defaultValue ?? []; + } + + return imageType.map((e) => imageTypeFromJson(e.toString())).toList(); +} + +List? imageTypeNullableListFromJson( + List? imageType, [ + List? defaultValue, +]) { + if (imageType == null) { + return defaultValue; + } + + return imageType.map((e) => imageTypeFromJson(e.toString())).toList(); +} + +String? isoTypeNullableToJson(enums.IsoType? isoType) { + return isoType?.value; +} + +String? isoTypeToJson(enums.IsoType isoType) { + return isoType.value; +} + +enums.IsoType isoTypeFromJson( + Object? isoType, [ + enums.IsoType? defaultValue, +]) { + return enums.IsoType.values.firstWhereOrNull((e) => e.value == isoType) ?? + defaultValue ?? + enums.IsoType.swaggerGeneratedUnknown; +} + +enums.IsoType? isoTypeNullableFromJson( + Object? isoType, [ + enums.IsoType? defaultValue, +]) { + if (isoType == null) { + return null; + } + return enums.IsoType.values.firstWhereOrNull((e) => e.value == isoType) ?? + defaultValue; +} + +String isoTypeExplodedListToJson(List? isoType) { + return isoType?.map((e) => e.value!).join(',') ?? ''; +} + +List isoTypeListToJson(List? isoType) { + if (isoType == null) { + return []; + } + + return isoType.map((e) => e.value!).toList(); +} + +List isoTypeListFromJson( + List? isoType, [ + List? defaultValue, +]) { + if (isoType == null) { + return defaultValue ?? []; + } + + return isoType.map((e) => isoTypeFromJson(e.toString())).toList(); +} + +List? isoTypeNullableListFromJson( + List? isoType, [ + List? defaultValue, +]) { + if (isoType == null) { + return defaultValue; + } + + return isoType.map((e) => isoTypeFromJson(e.toString())).toList(); +} + +String? itemFieldsNullableToJson(enums.ItemFields? itemFields) { + return itemFields?.value; +} + +String? itemFieldsToJson(enums.ItemFields itemFields) { + return itemFields.value; +} + +enums.ItemFields itemFieldsFromJson( + Object? itemFields, [ + enums.ItemFields? defaultValue, +]) { + return enums.ItemFields.values + .firstWhereOrNull((e) => e.value == itemFields) ?? + defaultValue ?? + enums.ItemFields.swaggerGeneratedUnknown; +} + +enums.ItemFields? itemFieldsNullableFromJson( + Object? itemFields, [ + enums.ItemFields? defaultValue, +]) { + if (itemFields == null) { + return null; + } + return enums.ItemFields.values + .firstWhereOrNull((e) => e.value == itemFields) ?? + defaultValue; +} + +String itemFieldsExplodedListToJson(List? itemFields) { + return itemFields?.map((e) => e.value!).join(',') ?? ''; +} + +List itemFieldsListToJson(List? itemFields) { + if (itemFields == null) { + return []; + } + + return itemFields.map((e) => e.value!).toList(); +} + +List itemFieldsListFromJson( + List? itemFields, [ + List? defaultValue, +]) { + if (itemFields == null) { + return defaultValue ?? []; + } + + return itemFields.map((e) => itemFieldsFromJson(e.toString())).toList(); +} + +List? itemFieldsNullableListFromJson( + List? itemFields, [ + List? defaultValue, +]) { + if (itemFields == null) { + return defaultValue; + } + + return itemFields.map((e) => itemFieldsFromJson(e.toString())).toList(); +} + +String? itemFilterNullableToJson(enums.ItemFilter? itemFilter) { + return itemFilter?.value; +} + +String? itemFilterToJson(enums.ItemFilter itemFilter) { + return itemFilter.value; +} + +enums.ItemFilter itemFilterFromJson( + Object? itemFilter, [ + enums.ItemFilter? defaultValue, +]) { + return enums.ItemFilter.values + .firstWhereOrNull((e) => e.value == itemFilter) ?? + defaultValue ?? + enums.ItemFilter.swaggerGeneratedUnknown; +} + +enums.ItemFilter? itemFilterNullableFromJson( + Object? itemFilter, [ + enums.ItemFilter? defaultValue, +]) { + if (itemFilter == null) { + return null; + } + return enums.ItemFilter.values + .firstWhereOrNull((e) => e.value == itemFilter) ?? + defaultValue; +} + +String itemFilterExplodedListToJson(List? itemFilter) { + return itemFilter?.map((e) => e.value!).join(',') ?? ''; +} + +List itemFilterListToJson(List? itemFilter) { + if (itemFilter == null) { + return []; + } + + return itemFilter.map((e) => e.value!).toList(); +} + +List itemFilterListFromJson( + List? itemFilter, [ + List? defaultValue, +]) { + if (itemFilter == null) { + return defaultValue ?? []; + } + + return itemFilter.map((e) => itemFilterFromJson(e.toString())).toList(); +} + +List? itemFilterNullableListFromJson( + List? itemFilter, [ + List? defaultValue, +]) { + if (itemFilter == null) { + return defaultValue; + } + + return itemFilter.map((e) => itemFilterFromJson(e.toString())).toList(); +} + +String? itemSortByNullableToJson(enums.ItemSortBy? itemSortBy) { + return itemSortBy?.value; +} + +String? itemSortByToJson(enums.ItemSortBy itemSortBy) { + return itemSortBy.value; +} + +enums.ItemSortBy itemSortByFromJson( + Object? itemSortBy, [ + enums.ItemSortBy? defaultValue, +]) { + return enums.ItemSortBy.values + .firstWhereOrNull((e) => e.value == itemSortBy) ?? + defaultValue ?? + enums.ItemSortBy.swaggerGeneratedUnknown; +} + +enums.ItemSortBy? itemSortByNullableFromJson( + Object? itemSortBy, [ + enums.ItemSortBy? defaultValue, +]) { + if (itemSortBy == null) { + return null; + } + return enums.ItemSortBy.values + .firstWhereOrNull((e) => e.value == itemSortBy) ?? + defaultValue; +} + +String itemSortByExplodedListToJson(List? itemSortBy) { + return itemSortBy?.map((e) => e.value!).join(',') ?? ''; +} + +List itemSortByListToJson(List? itemSortBy) { + if (itemSortBy == null) { + return []; + } + + return itemSortBy.map((e) => e.value!).toList(); +} + +List itemSortByListFromJson( + List? itemSortBy, [ + List? defaultValue, +]) { + if (itemSortBy == null) { + return defaultValue ?? []; + } + + return itemSortBy.map((e) => itemSortByFromJson(e.toString())).toList(); +} + +List? itemSortByNullableListFromJson( + List? itemSortBy, [ + List? defaultValue, +]) { + if (itemSortBy == null) { + return defaultValue; + } + + return itemSortBy.map((e) => itemSortByFromJson(e.toString())).toList(); +} + +String? keepUntilNullableToJson(enums.KeepUntil? keepUntil) { + return keepUntil?.value; +} + +String? keepUntilToJson(enums.KeepUntil keepUntil) { + return keepUntil.value; +} + +enums.KeepUntil keepUntilFromJson( + Object? keepUntil, [ + enums.KeepUntil? defaultValue, +]) { + return enums.KeepUntil.values.firstWhereOrNull((e) => e.value == keepUntil) ?? + defaultValue ?? + enums.KeepUntil.swaggerGeneratedUnknown; +} + +enums.KeepUntil? keepUntilNullableFromJson( + Object? keepUntil, [ + enums.KeepUntil? defaultValue, +]) { + if (keepUntil == null) { + return null; + } + return enums.KeepUntil.values.firstWhereOrNull((e) => e.value == keepUntil) ?? + defaultValue; +} + +String keepUntilExplodedListToJson(List? keepUntil) { + return keepUntil?.map((e) => e.value!).join(',') ?? ''; +} + +List keepUntilListToJson(List? keepUntil) { + if (keepUntil == null) { + return []; + } + + return keepUntil.map((e) => e.value!).toList(); +} + +List keepUntilListFromJson( + List? keepUntil, [ + List? defaultValue, +]) { + if (keepUntil == null) { + return defaultValue ?? []; + } + + return keepUntil.map((e) => keepUntilFromJson(e.toString())).toList(); +} + +List? keepUntilNullableListFromJson( + List? keepUntil, [ + List? defaultValue, +]) { + if (keepUntil == null) { + return defaultValue; + } + + return keepUntil.map((e) => keepUntilFromJson(e.toString())).toList(); +} + +String? liveTvServiceStatusNullableToJson( + enums.LiveTvServiceStatus? liveTvServiceStatus) { + return liveTvServiceStatus?.value; +} + +String? liveTvServiceStatusToJson( + enums.LiveTvServiceStatus liveTvServiceStatus) { + return liveTvServiceStatus.value; +} + +enums.LiveTvServiceStatus liveTvServiceStatusFromJson( + Object? liveTvServiceStatus, [ + enums.LiveTvServiceStatus? defaultValue, +]) { + return enums.LiveTvServiceStatus.values + .firstWhereOrNull((e) => e.value == liveTvServiceStatus) ?? + defaultValue ?? + enums.LiveTvServiceStatus.swaggerGeneratedUnknown; +} + +enums.LiveTvServiceStatus? liveTvServiceStatusNullableFromJson( + Object? liveTvServiceStatus, [ + enums.LiveTvServiceStatus? defaultValue, +]) { + if (liveTvServiceStatus == null) { + return null; + } + return enums.LiveTvServiceStatus.values + .firstWhereOrNull((e) => e.value == liveTvServiceStatus) ?? + defaultValue; +} + +String liveTvServiceStatusExplodedListToJson( + List? liveTvServiceStatus) { + return liveTvServiceStatus?.map((e) => e.value!).join(',') ?? ''; +} + +List liveTvServiceStatusListToJson( + List? liveTvServiceStatus) { + if (liveTvServiceStatus == null) { + return []; + } + + return liveTvServiceStatus.map((e) => e.value!).toList(); +} + +List liveTvServiceStatusListFromJson( + List? liveTvServiceStatus, [ + List? defaultValue, +]) { + if (liveTvServiceStatus == null) { + return defaultValue ?? []; + } + + return liveTvServiceStatus + .map((e) => liveTvServiceStatusFromJson(e.toString())) + .toList(); +} + +List? liveTvServiceStatusNullableListFromJson( + List? liveTvServiceStatus, [ + List? defaultValue, +]) { + if (liveTvServiceStatus == null) { + return defaultValue; + } + + return liveTvServiceStatus + .map((e) => liveTvServiceStatusFromJson(e.toString())) + .toList(); +} + +String? locationTypeNullableToJson(enums.LocationType? locationType) { + return locationType?.value; +} + +String? locationTypeToJson(enums.LocationType locationType) { + return locationType.value; +} + +enums.LocationType locationTypeFromJson( + Object? locationType, [ + enums.LocationType? defaultValue, +]) { + return enums.LocationType.values + .firstWhereOrNull((e) => e.value == locationType) ?? + defaultValue ?? + enums.LocationType.swaggerGeneratedUnknown; +} + +enums.LocationType? locationTypeNullableFromJson( + Object? locationType, [ + enums.LocationType? defaultValue, +]) { + if (locationType == null) { + return null; + } + return enums.LocationType.values + .firstWhereOrNull((e) => e.value == locationType) ?? + defaultValue; +} + +String locationTypeExplodedListToJson(List? locationType) { + return locationType?.map((e) => e.value!).join(',') ?? ''; +} + +List locationTypeListToJson(List? locationType) { + if (locationType == null) { + return []; + } + + return locationType.map((e) => e.value!).toList(); +} + +List locationTypeListFromJson( + List? locationType, [ + List? defaultValue, +]) { + if (locationType == null) { + return defaultValue ?? []; + } + + return locationType.map((e) => locationTypeFromJson(e.toString())).toList(); +} + +List? locationTypeNullableListFromJson( + List? locationType, [ + List? defaultValue, +]) { + if (locationType == null) { + return defaultValue; + } + + return locationType.map((e) => locationTypeFromJson(e.toString())).toList(); +} + +String? logLevelNullableToJson(enums.LogLevel? logLevel) { + return logLevel?.value; +} + +String? logLevelToJson(enums.LogLevel logLevel) { + return logLevel.value; +} + +enums.LogLevel logLevelFromJson( + Object? logLevel, [ + enums.LogLevel? defaultValue, +]) { + return enums.LogLevel.values.firstWhereOrNull((e) => e.value == logLevel) ?? + defaultValue ?? + enums.LogLevel.swaggerGeneratedUnknown; +} + +enums.LogLevel? logLevelNullableFromJson( + Object? logLevel, [ + enums.LogLevel? defaultValue, +]) { + if (logLevel == null) { + return null; + } + return enums.LogLevel.values.firstWhereOrNull((e) => e.value == logLevel) ?? + defaultValue; +} + +String logLevelExplodedListToJson(List? logLevel) { + return logLevel?.map((e) => e.value!).join(',') ?? ''; +} + +List logLevelListToJson(List? logLevel) { + if (logLevel == null) { + return []; + } + + return logLevel.map((e) => e.value!).toList(); +} + +List logLevelListFromJson( + List? logLevel, [ + List? defaultValue, +]) { + if (logLevel == null) { + return defaultValue ?? []; + } + + return logLevel.map((e) => logLevelFromJson(e.toString())).toList(); +} + +List? logLevelNullableListFromJson( + List? logLevel, [ + List? defaultValue, +]) { + if (logLevel == null) { + return defaultValue; + } + + return logLevel.map((e) => logLevelFromJson(e.toString())).toList(); +} + +String? mediaProtocolNullableToJson(enums.MediaProtocol? mediaProtocol) { + return mediaProtocol?.value; +} + +String? mediaProtocolToJson(enums.MediaProtocol mediaProtocol) { + return mediaProtocol.value; +} + +enums.MediaProtocol mediaProtocolFromJson( + Object? mediaProtocol, [ + enums.MediaProtocol? defaultValue, +]) { + return enums.MediaProtocol.values + .firstWhereOrNull((e) => e.value == mediaProtocol) ?? + defaultValue ?? + enums.MediaProtocol.swaggerGeneratedUnknown; +} + +enums.MediaProtocol? mediaProtocolNullableFromJson( + Object? mediaProtocol, [ + enums.MediaProtocol? defaultValue, +]) { + if (mediaProtocol == null) { + return null; + } + return enums.MediaProtocol.values + .firstWhereOrNull((e) => e.value == mediaProtocol) ?? + defaultValue; +} + +String mediaProtocolExplodedListToJson( + List? mediaProtocol) { + return mediaProtocol?.map((e) => e.value!).join(',') ?? ''; +} + +List mediaProtocolListToJson(List? mediaProtocol) { + if (mediaProtocol == null) { + return []; + } + + return mediaProtocol.map((e) => e.value!).toList(); +} + +List mediaProtocolListFromJson( + List? mediaProtocol, [ + List? defaultValue, +]) { + if (mediaProtocol == null) { + return defaultValue ?? []; + } + + return mediaProtocol.map((e) => mediaProtocolFromJson(e.toString())).toList(); +} + +List? mediaProtocolNullableListFromJson( + List? mediaProtocol, [ + List? defaultValue, +]) { + if (mediaProtocol == null) { + return defaultValue; + } + + return mediaProtocol.map((e) => mediaProtocolFromJson(e.toString())).toList(); +} + +String? mediaSourceTypeNullableToJson(enums.MediaSourceType? mediaSourceType) { + return mediaSourceType?.value; +} + +String? mediaSourceTypeToJson(enums.MediaSourceType mediaSourceType) { + return mediaSourceType.value; +} + +enums.MediaSourceType mediaSourceTypeFromJson( + Object? mediaSourceType, [ + enums.MediaSourceType? defaultValue, +]) { + return enums.MediaSourceType.values + .firstWhereOrNull((e) => e.value == mediaSourceType) ?? + defaultValue ?? + enums.MediaSourceType.swaggerGeneratedUnknown; +} + +enums.MediaSourceType? mediaSourceTypeNullableFromJson( + Object? mediaSourceType, [ + enums.MediaSourceType? defaultValue, +]) { + if (mediaSourceType == null) { + return null; + } + return enums.MediaSourceType.values + .firstWhereOrNull((e) => e.value == mediaSourceType) ?? + defaultValue; +} + +String mediaSourceTypeExplodedListToJson( + List? mediaSourceType) { + return mediaSourceType?.map((e) => e.value!).join(',') ?? ''; +} + +List mediaSourceTypeListToJson( + List? mediaSourceType) { + if (mediaSourceType == null) { + return []; + } + + return mediaSourceType.map((e) => e.value!).toList(); +} + +List mediaSourceTypeListFromJson( + List? mediaSourceType, [ + List? defaultValue, +]) { + if (mediaSourceType == null) { + return defaultValue ?? []; + } + + return mediaSourceType + .map((e) => mediaSourceTypeFromJson(e.toString())) + .toList(); +} + +List? mediaSourceTypeNullableListFromJson( + List? mediaSourceType, [ + List? defaultValue, +]) { + if (mediaSourceType == null) { + return defaultValue; + } + + return mediaSourceType + .map((e) => mediaSourceTypeFromJson(e.toString())) + .toList(); +} + +String? mediaStreamProtocolNullableToJson( + enums.MediaStreamProtocol? mediaStreamProtocol) { + return mediaStreamProtocol?.value; +} + +String? mediaStreamProtocolToJson( + enums.MediaStreamProtocol mediaStreamProtocol) { + return mediaStreamProtocol.value; +} + +enums.MediaStreamProtocol mediaStreamProtocolFromJson( + Object? mediaStreamProtocol, [ + enums.MediaStreamProtocol? defaultValue, +]) { + return enums.MediaStreamProtocol.values + .firstWhereOrNull((e) => e.value == mediaStreamProtocol) ?? + defaultValue ?? + enums.MediaStreamProtocol.swaggerGeneratedUnknown; +} + +enums.MediaStreamProtocol? mediaStreamProtocolNullableFromJson( + Object? mediaStreamProtocol, [ + enums.MediaStreamProtocol? defaultValue, +]) { + if (mediaStreamProtocol == null) { + return null; + } + return enums.MediaStreamProtocol.values + .firstWhereOrNull((e) => e.value == mediaStreamProtocol) ?? + defaultValue; +} + +String mediaStreamProtocolExplodedListToJson( + List? mediaStreamProtocol) { + return mediaStreamProtocol?.map((e) => e.value!).join(',') ?? ''; +} + +List mediaStreamProtocolListToJson( + List? mediaStreamProtocol) { + if (mediaStreamProtocol == null) { + return []; + } + + return mediaStreamProtocol.map((e) => e.value!).toList(); +} + +List mediaStreamProtocolListFromJson( + List? mediaStreamProtocol, [ + List? defaultValue, +]) { + if (mediaStreamProtocol == null) { + return defaultValue ?? []; + } + + return mediaStreamProtocol + .map((e) => mediaStreamProtocolFromJson(e.toString())) + .toList(); +} + +List? mediaStreamProtocolNullableListFromJson( + List? mediaStreamProtocol, [ + List? defaultValue, +]) { + if (mediaStreamProtocol == null) { + return defaultValue; + } + + return mediaStreamProtocol + .map((e) => mediaStreamProtocolFromJson(e.toString())) + .toList(); +} + +String? mediaStreamTypeNullableToJson(enums.MediaStreamType? mediaStreamType) { + return mediaStreamType?.value; +} + +String? mediaStreamTypeToJson(enums.MediaStreamType mediaStreamType) { + return mediaStreamType.value; +} + +enums.MediaStreamType mediaStreamTypeFromJson( + Object? mediaStreamType, [ + enums.MediaStreamType? defaultValue, +]) { + return enums.MediaStreamType.values + .firstWhereOrNull((e) => e.value == mediaStreamType) ?? + defaultValue ?? + enums.MediaStreamType.swaggerGeneratedUnknown; +} + +enums.MediaStreamType? mediaStreamTypeNullableFromJson( + Object? mediaStreamType, [ + enums.MediaStreamType? defaultValue, +]) { + if (mediaStreamType == null) { + return null; + } + return enums.MediaStreamType.values + .firstWhereOrNull((e) => e.value == mediaStreamType) ?? + defaultValue; +} + +String mediaStreamTypeExplodedListToJson( + List? mediaStreamType) { + return mediaStreamType?.map((e) => e.value!).join(',') ?? ''; +} + +List mediaStreamTypeListToJson( + List? mediaStreamType) { + if (mediaStreamType == null) { + return []; + } + + return mediaStreamType.map((e) => e.value!).toList(); +} + +List mediaStreamTypeListFromJson( + List? mediaStreamType, [ + List? defaultValue, +]) { + if (mediaStreamType == null) { + return defaultValue ?? []; + } + + return mediaStreamType + .map((e) => mediaStreamTypeFromJson(e.toString())) + .toList(); +} + +List? mediaStreamTypeNullableListFromJson( + List? mediaStreamType, [ + List? defaultValue, +]) { + if (mediaStreamType == null) { + return defaultValue; + } + + return mediaStreamType + .map((e) => mediaStreamTypeFromJson(e.toString())) + .toList(); +} + +String? mediaTypeNullableToJson(enums.MediaType? mediaType) { + return mediaType?.value; +} + +String? mediaTypeToJson(enums.MediaType mediaType) { + return mediaType.value; +} + +enums.MediaType mediaTypeFromJson( + Object? mediaType, [ + enums.MediaType? defaultValue, +]) { + return enums.MediaType.values.firstWhereOrNull((e) => e.value == mediaType) ?? + defaultValue ?? + enums.MediaType.swaggerGeneratedUnknown; +} + +enums.MediaType? mediaTypeNullableFromJson( + Object? mediaType, [ + enums.MediaType? defaultValue, +]) { + if (mediaType == null) { + return null; + } + return enums.MediaType.values.firstWhereOrNull((e) => e.value == mediaType) ?? + defaultValue; +} + +String mediaTypeExplodedListToJson(List? mediaType) { + return mediaType?.map((e) => e.value!).join(',') ?? ''; +} + +List mediaTypeListToJson(List? mediaType) { + if (mediaType == null) { + return []; + } + + return mediaType.map((e) => e.value!).toList(); +} + +List mediaTypeListFromJson( + List? mediaType, [ + List? defaultValue, +]) { + if (mediaType == null) { + return defaultValue ?? []; + } + + return mediaType.map((e) => mediaTypeFromJson(e.toString())).toList(); +} + +List? mediaTypeNullableListFromJson( + List? mediaType, [ + List? defaultValue, +]) { + if (mediaType == null) { + return defaultValue; + } + + return mediaType.map((e) => mediaTypeFromJson(e.toString())).toList(); +} + +String? metadataFieldNullableToJson(enums.MetadataField? metadataField) { + return metadataField?.value; +} + +String? metadataFieldToJson(enums.MetadataField metadataField) { + return metadataField.value; +} + +enums.MetadataField metadataFieldFromJson( + Object? metadataField, [ + enums.MetadataField? defaultValue, +]) { + return enums.MetadataField.values + .firstWhereOrNull((e) => e.value == metadataField) ?? + defaultValue ?? + enums.MetadataField.swaggerGeneratedUnknown; +} + +enums.MetadataField? metadataFieldNullableFromJson( + Object? metadataField, [ + enums.MetadataField? defaultValue, +]) { + if (metadataField == null) { + return null; + } + return enums.MetadataField.values + .firstWhereOrNull((e) => e.value == metadataField) ?? + defaultValue; +} + +String metadataFieldExplodedListToJson( + List? metadataField) { + return metadataField?.map((e) => e.value!).join(',') ?? ''; +} + +List metadataFieldListToJson(List? metadataField) { + if (metadataField == null) { + return []; + } + + return metadataField.map((e) => e.value!).toList(); +} + +List metadataFieldListFromJson( + List? metadataField, [ + List? defaultValue, +]) { + if (metadataField == null) { + return defaultValue ?? []; + } + + return metadataField.map((e) => metadataFieldFromJson(e.toString())).toList(); +} + +List? metadataFieldNullableListFromJson( + List? metadataField, [ + List? defaultValue, +]) { + if (metadataField == null) { + return defaultValue; + } + + return metadataField.map((e) => metadataFieldFromJson(e.toString())).toList(); +} + +String? metadataRefreshModeNullableToJson( + enums.MetadataRefreshMode? metadataRefreshMode) { + return metadataRefreshMode?.value; +} + +String? metadataRefreshModeToJson( + enums.MetadataRefreshMode metadataRefreshMode) { + return metadataRefreshMode.value; +} + +enums.MetadataRefreshMode metadataRefreshModeFromJson( + Object? metadataRefreshMode, [ + enums.MetadataRefreshMode? defaultValue, +]) { + return enums.MetadataRefreshMode.values + .firstWhereOrNull((e) => e.value == metadataRefreshMode) ?? + defaultValue ?? + enums.MetadataRefreshMode.swaggerGeneratedUnknown; +} + +enums.MetadataRefreshMode? metadataRefreshModeNullableFromJson( + Object? metadataRefreshMode, [ + enums.MetadataRefreshMode? defaultValue, +]) { + if (metadataRefreshMode == null) { + return null; + } + return enums.MetadataRefreshMode.values + .firstWhereOrNull((e) => e.value == metadataRefreshMode) ?? + defaultValue; +} + +String metadataRefreshModeExplodedListToJson( + List? metadataRefreshMode) { + return metadataRefreshMode?.map((e) => e.value!).join(',') ?? ''; +} + +List metadataRefreshModeListToJson( + List? metadataRefreshMode) { + if (metadataRefreshMode == null) { + return []; + } + + return metadataRefreshMode.map((e) => e.value!).toList(); +} + +List metadataRefreshModeListFromJson( + List? metadataRefreshMode, [ + List? defaultValue, +]) { + if (metadataRefreshMode == null) { + return defaultValue ?? []; + } + + return metadataRefreshMode + .map((e) => metadataRefreshModeFromJson(e.toString())) + .toList(); +} + +List? metadataRefreshModeNullableListFromJson( + List? metadataRefreshMode, [ + List? defaultValue, +]) { + if (metadataRefreshMode == null) { + return defaultValue; + } + + return metadataRefreshMode + .map((e) => metadataRefreshModeFromJson(e.toString())) + .toList(); +} + +String? personKindNullableToJson(enums.PersonKind? personKind) { + return personKind?.value; +} + +String? personKindToJson(enums.PersonKind personKind) { + return personKind.value; +} + +enums.PersonKind personKindFromJson( + Object? personKind, [ + enums.PersonKind? defaultValue, +]) { + return enums.PersonKind.values + .firstWhereOrNull((e) => e.value == personKind) ?? + defaultValue ?? + enums.PersonKind.swaggerGeneratedUnknown; +} + +enums.PersonKind? personKindNullableFromJson( + Object? personKind, [ + enums.PersonKind? defaultValue, +]) { + if (personKind == null) { + return null; + } + return enums.PersonKind.values + .firstWhereOrNull((e) => e.value == personKind) ?? + defaultValue; +} + +String personKindExplodedListToJson(List? personKind) { + return personKind?.map((e) => e.value!).join(',') ?? ''; +} + +List personKindListToJson(List? personKind) { + if (personKind == null) { + return []; + } + + return personKind.map((e) => e.value!).toList(); +} + +List personKindListFromJson( + List? personKind, [ + List? defaultValue, +]) { + if (personKind == null) { + return defaultValue ?? []; + } + + return personKind.map((e) => personKindFromJson(e.toString())).toList(); +} + +List? personKindNullableListFromJson( + List? personKind, [ + List? defaultValue, +]) { + if (personKind == null) { + return defaultValue; + } + + return personKind.map((e) => personKindFromJson(e.toString())).toList(); +} + +String? playAccessNullableToJson(enums.PlayAccess? playAccess) { + return playAccess?.value; +} + +String? playAccessToJson(enums.PlayAccess playAccess) { + return playAccess.value; +} + +enums.PlayAccess playAccessFromJson( + Object? playAccess, [ + enums.PlayAccess? defaultValue, +]) { + return enums.PlayAccess.values + .firstWhereOrNull((e) => e.value == playAccess) ?? + defaultValue ?? + enums.PlayAccess.swaggerGeneratedUnknown; +} + +enums.PlayAccess? playAccessNullableFromJson( + Object? playAccess, [ + enums.PlayAccess? defaultValue, +]) { + if (playAccess == null) { + return null; + } + return enums.PlayAccess.values + .firstWhereOrNull((e) => e.value == playAccess) ?? + defaultValue; +} + +String playAccessExplodedListToJson(List? playAccess) { + return playAccess?.map((e) => e.value!).join(',') ?? ''; +} + +List playAccessListToJson(List? playAccess) { + if (playAccess == null) { + return []; + } + + return playAccess.map((e) => e.value!).toList(); +} + +List playAccessListFromJson( + List? playAccess, [ + List? defaultValue, +]) { + if (playAccess == null) { + return defaultValue ?? []; + } + + return playAccess.map((e) => playAccessFromJson(e.toString())).toList(); +} + +List? playAccessNullableListFromJson( + List? playAccess, [ + List? defaultValue, +]) { + if (playAccess == null) { + return defaultValue; + } + + return playAccess.map((e) => playAccessFromJson(e.toString())).toList(); +} + +String? playbackErrorCodeNullableToJson( + enums.PlaybackErrorCode? playbackErrorCode) { + return playbackErrorCode?.value; +} + +String? playbackErrorCodeToJson(enums.PlaybackErrorCode playbackErrorCode) { + return playbackErrorCode.value; +} + +enums.PlaybackErrorCode playbackErrorCodeFromJson( + Object? playbackErrorCode, [ + enums.PlaybackErrorCode? defaultValue, +]) { + return enums.PlaybackErrorCode.values + .firstWhereOrNull((e) => e.value == playbackErrorCode) ?? + defaultValue ?? + enums.PlaybackErrorCode.swaggerGeneratedUnknown; +} + +enums.PlaybackErrorCode? playbackErrorCodeNullableFromJson( + Object? playbackErrorCode, [ + enums.PlaybackErrorCode? defaultValue, +]) { + if (playbackErrorCode == null) { + return null; + } + return enums.PlaybackErrorCode.values + .firstWhereOrNull((e) => e.value == playbackErrorCode) ?? + defaultValue; +} + +String playbackErrorCodeExplodedListToJson( + List? playbackErrorCode) { + return playbackErrorCode?.map((e) => e.value!).join(',') ?? ''; +} + +List playbackErrorCodeListToJson( + List? playbackErrorCode) { + if (playbackErrorCode == null) { + return []; + } + + return playbackErrorCode.map((e) => e.value!).toList(); +} + +List playbackErrorCodeListFromJson( + List? playbackErrorCode, [ + List? defaultValue, +]) { + if (playbackErrorCode == null) { + return defaultValue ?? []; + } + + return playbackErrorCode + .map((e) => playbackErrorCodeFromJson(e.toString())) + .toList(); +} + +List? playbackErrorCodeNullableListFromJson( + List? playbackErrorCode, [ + List? defaultValue, +]) { + if (playbackErrorCode == null) { + return defaultValue; + } + + return playbackErrorCode + .map((e) => playbackErrorCodeFromJson(e.toString())) + .toList(); +} + +String? playbackOrderNullableToJson(enums.PlaybackOrder? playbackOrder) { + return playbackOrder?.value; +} + +String? playbackOrderToJson(enums.PlaybackOrder playbackOrder) { + return playbackOrder.value; +} + +enums.PlaybackOrder playbackOrderFromJson( + Object? playbackOrder, [ + enums.PlaybackOrder? defaultValue, +]) { + return enums.PlaybackOrder.values + .firstWhereOrNull((e) => e.value == playbackOrder) ?? + defaultValue ?? + enums.PlaybackOrder.swaggerGeneratedUnknown; +} + +enums.PlaybackOrder? playbackOrderNullableFromJson( + Object? playbackOrder, [ + enums.PlaybackOrder? defaultValue, +]) { + if (playbackOrder == null) { + return null; + } + return enums.PlaybackOrder.values + .firstWhereOrNull((e) => e.value == playbackOrder) ?? + defaultValue; +} + +String playbackOrderExplodedListToJson( + List? playbackOrder) { + return playbackOrder?.map((e) => e.value!).join(',') ?? ''; +} + +List playbackOrderListToJson(List? playbackOrder) { + if (playbackOrder == null) { + return []; + } + + return playbackOrder.map((e) => e.value!).toList(); +} + +List playbackOrderListFromJson( + List? playbackOrder, [ + List? defaultValue, +]) { + if (playbackOrder == null) { + return defaultValue ?? []; + } + + return playbackOrder.map((e) => playbackOrderFromJson(e.toString())).toList(); +} + +List? playbackOrderNullableListFromJson( + List? playbackOrder, [ + List? defaultValue, +]) { + if (playbackOrder == null) { + return defaultValue; + } + + return playbackOrder.map((e) => playbackOrderFromJson(e.toString())).toList(); +} + +String? playbackRequestTypeNullableToJson( + enums.PlaybackRequestType? playbackRequestType) { + return playbackRequestType?.value; +} + +String? playbackRequestTypeToJson( + enums.PlaybackRequestType playbackRequestType) { + return playbackRequestType.value; +} + +enums.PlaybackRequestType playbackRequestTypeFromJson( + Object? playbackRequestType, [ + enums.PlaybackRequestType? defaultValue, +]) { + return enums.PlaybackRequestType.values + .firstWhereOrNull((e) => e.value == playbackRequestType) ?? + defaultValue ?? + enums.PlaybackRequestType.swaggerGeneratedUnknown; +} + +enums.PlaybackRequestType? playbackRequestTypeNullableFromJson( + Object? playbackRequestType, [ + enums.PlaybackRequestType? defaultValue, +]) { + if (playbackRequestType == null) { + return null; + } + return enums.PlaybackRequestType.values + .firstWhereOrNull((e) => e.value == playbackRequestType) ?? + defaultValue; +} + +String playbackRequestTypeExplodedListToJson( + List? playbackRequestType) { + return playbackRequestType?.map((e) => e.value!).join(',') ?? ''; +} + +List playbackRequestTypeListToJson( + List? playbackRequestType) { + if (playbackRequestType == null) { + return []; + } + + return playbackRequestType.map((e) => e.value!).toList(); +} + +List playbackRequestTypeListFromJson( + List? playbackRequestType, [ + List? defaultValue, +]) { + if (playbackRequestType == null) { + return defaultValue ?? []; + } + + return playbackRequestType + .map((e) => playbackRequestTypeFromJson(e.toString())) + .toList(); +} + +List? playbackRequestTypeNullableListFromJson( + List? playbackRequestType, [ + List? defaultValue, +]) { + if (playbackRequestType == null) { + return defaultValue; + } + + return playbackRequestType + .map((e) => playbackRequestTypeFromJson(e.toString())) + .toList(); +} + +String? playCommandNullableToJson(enums.PlayCommand? playCommand) { + return playCommand?.value; +} + +String? playCommandToJson(enums.PlayCommand playCommand) { + return playCommand.value; +} + +enums.PlayCommand playCommandFromJson( + Object? playCommand, [ + enums.PlayCommand? defaultValue, +]) { + return enums.PlayCommand.values + .firstWhereOrNull((e) => e.value == playCommand) ?? + defaultValue ?? + enums.PlayCommand.swaggerGeneratedUnknown; +} + +enums.PlayCommand? playCommandNullableFromJson( + Object? playCommand, [ + enums.PlayCommand? defaultValue, +]) { + if (playCommand == null) { + return null; + } + return enums.PlayCommand.values + .firstWhereOrNull((e) => e.value == playCommand) ?? + defaultValue; +} + +String playCommandExplodedListToJson(List? playCommand) { + return playCommand?.map((e) => e.value!).join(',') ?? ''; +} + +List playCommandListToJson(List? playCommand) { + if (playCommand == null) { + return []; + } + + return playCommand.map((e) => e.value!).toList(); +} + +List playCommandListFromJson( + List? playCommand, [ + List? defaultValue, +]) { + if (playCommand == null) { + return defaultValue ?? []; + } + + return playCommand.map((e) => playCommandFromJson(e.toString())).toList(); +} + +List? playCommandNullableListFromJson( + List? playCommand, [ + List? defaultValue, +]) { + if (playCommand == null) { + return defaultValue; + } + + return playCommand.map((e) => playCommandFromJson(e.toString())).toList(); +} + +String? playMethodNullableToJson(enums.PlayMethod? playMethod) { + return playMethod?.value; +} + +String? playMethodToJson(enums.PlayMethod playMethod) { + return playMethod.value; +} + +enums.PlayMethod playMethodFromJson( + Object? playMethod, [ + enums.PlayMethod? defaultValue, +]) { + return enums.PlayMethod.values + .firstWhereOrNull((e) => e.value == playMethod) ?? + defaultValue ?? + enums.PlayMethod.swaggerGeneratedUnknown; +} + +enums.PlayMethod? playMethodNullableFromJson( + Object? playMethod, [ + enums.PlayMethod? defaultValue, +]) { + if (playMethod == null) { + return null; + } + return enums.PlayMethod.values + .firstWhereOrNull((e) => e.value == playMethod) ?? + defaultValue; +} + +String playMethodExplodedListToJson(List? playMethod) { + return playMethod?.map((e) => e.value!).join(',') ?? ''; +} + +List playMethodListToJson(List? playMethod) { + if (playMethod == null) { + return []; + } + + return playMethod.map((e) => e.value!).toList(); +} + +List playMethodListFromJson( + List? playMethod, [ + List? defaultValue, +]) { + if (playMethod == null) { + return defaultValue ?? []; + } + + return playMethod.map((e) => playMethodFromJson(e.toString())).toList(); +} + +List? playMethodNullableListFromJson( + List? playMethod, [ + List? defaultValue, +]) { + if (playMethod == null) { + return defaultValue; + } + + return playMethod.map((e) => playMethodFromJson(e.toString())).toList(); +} + +String? playQueueUpdateReasonNullableToJson( + enums.PlayQueueUpdateReason? playQueueUpdateReason) { + return playQueueUpdateReason?.value; +} + +String? playQueueUpdateReasonToJson( + enums.PlayQueueUpdateReason playQueueUpdateReason) { + return playQueueUpdateReason.value; +} + +enums.PlayQueueUpdateReason playQueueUpdateReasonFromJson( + Object? playQueueUpdateReason, [ + enums.PlayQueueUpdateReason? defaultValue, +]) { + return enums.PlayQueueUpdateReason.values + .firstWhereOrNull((e) => e.value == playQueueUpdateReason) ?? + defaultValue ?? + enums.PlayQueueUpdateReason.swaggerGeneratedUnknown; +} + +enums.PlayQueueUpdateReason? playQueueUpdateReasonNullableFromJson( + Object? playQueueUpdateReason, [ + enums.PlayQueueUpdateReason? defaultValue, +]) { + if (playQueueUpdateReason == null) { + return null; + } + return enums.PlayQueueUpdateReason.values + .firstWhereOrNull((e) => e.value == playQueueUpdateReason) ?? + defaultValue; +} + +String playQueueUpdateReasonExplodedListToJson( + List? playQueueUpdateReason) { + return playQueueUpdateReason?.map((e) => e.value!).join(',') ?? ''; +} + +List playQueueUpdateReasonListToJson( + List? playQueueUpdateReason) { + if (playQueueUpdateReason == null) { + return []; + } + + return playQueueUpdateReason.map((e) => e.value!).toList(); +} + +List playQueueUpdateReasonListFromJson( + List? playQueueUpdateReason, [ + List? defaultValue, +]) { + if (playQueueUpdateReason == null) { + return defaultValue ?? []; + } + + return playQueueUpdateReason + .map((e) => playQueueUpdateReasonFromJson(e.toString())) + .toList(); +} + +List? playQueueUpdateReasonNullableListFromJson( + List? playQueueUpdateReason, [ + List? defaultValue, +]) { + if (playQueueUpdateReason == null) { + return defaultValue; + } + + return playQueueUpdateReason + .map((e) => playQueueUpdateReasonFromJson(e.toString())) + .toList(); +} + +String? playstateCommandNullableToJson( + enums.PlaystateCommand? playstateCommand) { + return playstateCommand?.value; +} + +String? playstateCommandToJson(enums.PlaystateCommand playstateCommand) { + return playstateCommand.value; +} + +enums.PlaystateCommand playstateCommandFromJson( + Object? playstateCommand, [ + enums.PlaystateCommand? defaultValue, +]) { + return enums.PlaystateCommand.values + .firstWhereOrNull((e) => e.value == playstateCommand) ?? + defaultValue ?? + enums.PlaystateCommand.swaggerGeneratedUnknown; +} + +enums.PlaystateCommand? playstateCommandNullableFromJson( + Object? playstateCommand, [ + enums.PlaystateCommand? defaultValue, +]) { + if (playstateCommand == null) { + return null; + } + return enums.PlaystateCommand.values + .firstWhereOrNull((e) => e.value == playstateCommand) ?? + defaultValue; +} + +String playstateCommandExplodedListToJson( + List? playstateCommand) { + return playstateCommand?.map((e) => e.value!).join(',') ?? ''; +} + +List playstateCommandListToJson( + List? playstateCommand) { + if (playstateCommand == null) { + return []; + } + + return playstateCommand.map((e) => e.value!).toList(); +} + +List playstateCommandListFromJson( + List? playstateCommand, [ + List? defaultValue, +]) { + if (playstateCommand == null) { + return defaultValue ?? []; + } + + return playstateCommand + .map((e) => playstateCommandFromJson(e.toString())) + .toList(); +} + +List? playstateCommandNullableListFromJson( + List? playstateCommand, [ + List? defaultValue, +]) { + if (playstateCommand == null) { + return defaultValue; + } + + return playstateCommand + .map((e) => playstateCommandFromJson(e.toString())) + .toList(); +} + +String? pluginStatusNullableToJson(enums.PluginStatus? pluginStatus) { + return pluginStatus?.value; +} + +String? pluginStatusToJson(enums.PluginStatus pluginStatus) { + return pluginStatus.value; +} + +enums.PluginStatus pluginStatusFromJson( + Object? pluginStatus, [ + enums.PluginStatus? defaultValue, +]) { + return enums.PluginStatus.values + .firstWhereOrNull((e) => e.value == pluginStatus) ?? + defaultValue ?? + enums.PluginStatus.swaggerGeneratedUnknown; +} + +enums.PluginStatus? pluginStatusNullableFromJson( + Object? pluginStatus, [ + enums.PluginStatus? defaultValue, +]) { + if (pluginStatus == null) { + return null; + } + return enums.PluginStatus.values + .firstWhereOrNull((e) => e.value == pluginStatus) ?? + defaultValue; +} + +String pluginStatusExplodedListToJson(List? pluginStatus) { + return pluginStatus?.map((e) => e.value!).join(',') ?? ''; +} + +List pluginStatusListToJson(List? pluginStatus) { + if (pluginStatus == null) { + return []; + } + + return pluginStatus.map((e) => e.value!).toList(); +} + +List pluginStatusListFromJson( + List? pluginStatus, [ + List? defaultValue, +]) { + if (pluginStatus == null) { + return defaultValue ?? []; + } + + return pluginStatus.map((e) => pluginStatusFromJson(e.toString())).toList(); +} + +List? pluginStatusNullableListFromJson( + List? pluginStatus, [ + List? defaultValue, +]) { + if (pluginStatus == null) { + return defaultValue; + } + + return pluginStatus.map((e) => pluginStatusFromJson(e.toString())).toList(); +} + +String? processPriorityClassNullableToJson( + enums.ProcessPriorityClass? processPriorityClass) { + return processPriorityClass?.value; +} + +String? processPriorityClassToJson( + enums.ProcessPriorityClass processPriorityClass) { + return processPriorityClass.value; +} + +enums.ProcessPriorityClass processPriorityClassFromJson( + Object? processPriorityClass, [ + enums.ProcessPriorityClass? defaultValue, +]) { + return enums.ProcessPriorityClass.values + .firstWhereOrNull((e) => e.value == processPriorityClass) ?? + defaultValue ?? + enums.ProcessPriorityClass.swaggerGeneratedUnknown; +} + +enums.ProcessPriorityClass? processPriorityClassNullableFromJson( + Object? processPriorityClass, [ + enums.ProcessPriorityClass? defaultValue, +]) { + if (processPriorityClass == null) { + return null; + } + return enums.ProcessPriorityClass.values + .firstWhereOrNull((e) => e.value == processPriorityClass) ?? + defaultValue; +} + +String processPriorityClassExplodedListToJson( + List? processPriorityClass) { + return processPriorityClass?.map((e) => e.value!).join(',') ?? ''; +} + +List processPriorityClassListToJson( + List? processPriorityClass) { + if (processPriorityClass == null) { + return []; + } + + return processPriorityClass.map((e) => e.value!).toList(); +} + +List processPriorityClassListFromJson( + List? processPriorityClass, [ + List? defaultValue, +]) { + if (processPriorityClass == null) { + return defaultValue ?? []; + } + + return processPriorityClass + .map((e) => processPriorityClassFromJson(e.toString())) + .toList(); +} + +List? processPriorityClassNullableListFromJson( + List? processPriorityClass, [ + List? defaultValue, +]) { + if (processPriorityClass == null) { + return defaultValue; + } + + return processPriorityClass + .map((e) => processPriorityClassFromJson(e.toString())) + .toList(); +} + +String? profileConditionTypeNullableToJson( + enums.ProfileConditionType? profileConditionType) { + return profileConditionType?.value; +} + +String? profileConditionTypeToJson( + enums.ProfileConditionType profileConditionType) { + return profileConditionType.value; +} + +enums.ProfileConditionType profileConditionTypeFromJson( + Object? profileConditionType, [ + enums.ProfileConditionType? defaultValue, +]) { + return enums.ProfileConditionType.values + .firstWhereOrNull((e) => e.value == profileConditionType) ?? + defaultValue ?? + enums.ProfileConditionType.swaggerGeneratedUnknown; +} + +enums.ProfileConditionType? profileConditionTypeNullableFromJson( + Object? profileConditionType, [ + enums.ProfileConditionType? defaultValue, +]) { + if (profileConditionType == null) { + return null; + } + return enums.ProfileConditionType.values + .firstWhereOrNull((e) => e.value == profileConditionType) ?? + defaultValue; +} + +String profileConditionTypeExplodedListToJson( + List? profileConditionType) { + return profileConditionType?.map((e) => e.value!).join(',') ?? ''; +} + +List profileConditionTypeListToJson( + List? profileConditionType) { + if (profileConditionType == null) { + return []; + } + + return profileConditionType.map((e) => e.value!).toList(); +} + +List profileConditionTypeListFromJson( + List? profileConditionType, [ + List? defaultValue, +]) { + if (profileConditionType == null) { + return defaultValue ?? []; + } + + return profileConditionType + .map((e) => profileConditionTypeFromJson(e.toString())) + .toList(); +} + +List? profileConditionTypeNullableListFromJson( + List? profileConditionType, [ + List? defaultValue, +]) { + if (profileConditionType == null) { + return defaultValue; + } + + return profileConditionType + .map((e) => profileConditionTypeFromJson(e.toString())) + .toList(); +} + +String? profileConditionValueNullableToJson( + enums.ProfileConditionValue? profileConditionValue) { + return profileConditionValue?.value; +} + +String? profileConditionValueToJson( + enums.ProfileConditionValue profileConditionValue) { + return profileConditionValue.value; +} + +enums.ProfileConditionValue profileConditionValueFromJson( + Object? profileConditionValue, [ + enums.ProfileConditionValue? defaultValue, +]) { + return enums.ProfileConditionValue.values + .firstWhereOrNull((e) => e.value == profileConditionValue) ?? + defaultValue ?? + enums.ProfileConditionValue.swaggerGeneratedUnknown; +} + +enums.ProfileConditionValue? profileConditionValueNullableFromJson( + Object? profileConditionValue, [ + enums.ProfileConditionValue? defaultValue, +]) { + if (profileConditionValue == null) { + return null; + } + return enums.ProfileConditionValue.values + .firstWhereOrNull((e) => e.value == profileConditionValue) ?? + defaultValue; +} + +String profileConditionValueExplodedListToJson( + List? profileConditionValue) { + return profileConditionValue?.map((e) => e.value!).join(',') ?? ''; +} + +List profileConditionValueListToJson( + List? profileConditionValue) { + if (profileConditionValue == null) { + return []; + } + + return profileConditionValue.map((e) => e.value!).toList(); +} + +List profileConditionValueListFromJson( + List? profileConditionValue, [ + List? defaultValue, +]) { + if (profileConditionValue == null) { + return defaultValue ?? []; + } + + return profileConditionValue + .map((e) => profileConditionValueFromJson(e.toString())) + .toList(); +} + +List? profileConditionValueNullableListFromJson( + List? profileConditionValue, [ + List? defaultValue, +]) { + if (profileConditionValue == null) { + return defaultValue; + } + + return profileConditionValue + .map((e) => profileConditionValueFromJson(e.toString())) + .toList(); +} + +String? programAudioNullableToJson(enums.ProgramAudio? programAudio) { + return programAudio?.value; +} + +String? programAudioToJson(enums.ProgramAudio programAudio) { + return programAudio.value; +} + +enums.ProgramAudio programAudioFromJson( + Object? programAudio, [ + enums.ProgramAudio? defaultValue, +]) { + return enums.ProgramAudio.values + .firstWhereOrNull((e) => e.value == programAudio) ?? + defaultValue ?? + enums.ProgramAudio.swaggerGeneratedUnknown; +} + +enums.ProgramAudio? programAudioNullableFromJson( + Object? programAudio, [ + enums.ProgramAudio? defaultValue, +]) { + if (programAudio == null) { + return null; + } + return enums.ProgramAudio.values + .firstWhereOrNull((e) => e.value == programAudio) ?? + defaultValue; +} + +String programAudioExplodedListToJson(List? programAudio) { + return programAudio?.map((e) => e.value!).join(',') ?? ''; +} + +List programAudioListToJson(List? programAudio) { + if (programAudio == null) { + return []; + } + + return programAudio.map((e) => e.value!).toList(); +} + +List programAudioListFromJson( + List? programAudio, [ + List? defaultValue, +]) { + if (programAudio == null) { + return defaultValue ?? []; + } + + return programAudio.map((e) => programAudioFromJson(e.toString())).toList(); +} + +List? programAudioNullableListFromJson( + List? programAudio, [ + List? defaultValue, +]) { + if (programAudio == null) { + return defaultValue; + } + + return programAudio.map((e) => programAudioFromJson(e.toString())).toList(); +} + +String? ratingTypeNullableToJson(enums.RatingType? ratingType) { + return ratingType?.value; +} + +String? ratingTypeToJson(enums.RatingType ratingType) { + return ratingType.value; +} + +enums.RatingType ratingTypeFromJson( + Object? ratingType, [ + enums.RatingType? defaultValue, +]) { + return enums.RatingType.values + .firstWhereOrNull((e) => e.value == ratingType) ?? + defaultValue ?? + enums.RatingType.swaggerGeneratedUnknown; +} + +enums.RatingType? ratingTypeNullableFromJson( + Object? ratingType, [ + enums.RatingType? defaultValue, +]) { + if (ratingType == null) { + return null; + } + return enums.RatingType.values + .firstWhereOrNull((e) => e.value == ratingType) ?? + defaultValue; +} + +String ratingTypeExplodedListToJson(List? ratingType) { + return ratingType?.map((e) => e.value!).join(',') ?? ''; +} + +List ratingTypeListToJson(List? ratingType) { + if (ratingType == null) { + return []; + } + + return ratingType.map((e) => e.value!).toList(); +} + +List ratingTypeListFromJson( + List? ratingType, [ + List? defaultValue, +]) { + if (ratingType == null) { + return defaultValue ?? []; + } + + return ratingType.map((e) => ratingTypeFromJson(e.toString())).toList(); +} + +List? ratingTypeNullableListFromJson( + List? ratingType, [ + List? defaultValue, +]) { + if (ratingType == null) { + return defaultValue; + } + + return ratingType.map((e) => ratingTypeFromJson(e.toString())).toList(); +} + +String? recommendationTypeNullableToJson( + enums.RecommendationType? recommendationType) { + return recommendationType?.value; +} + +String? recommendationTypeToJson(enums.RecommendationType recommendationType) { + return recommendationType.value; +} + +enums.RecommendationType recommendationTypeFromJson( + Object? recommendationType, [ + enums.RecommendationType? defaultValue, +]) { + return enums.RecommendationType.values + .firstWhereOrNull((e) => e.value == recommendationType) ?? + defaultValue ?? + enums.RecommendationType.swaggerGeneratedUnknown; +} + +enums.RecommendationType? recommendationTypeNullableFromJson( + Object? recommendationType, [ + enums.RecommendationType? defaultValue, +]) { + if (recommendationType == null) { + return null; + } + return enums.RecommendationType.values + .firstWhereOrNull((e) => e.value == recommendationType) ?? + defaultValue; +} + +String recommendationTypeExplodedListToJson( + List? recommendationType) { + return recommendationType?.map((e) => e.value!).join(',') ?? ''; +} + +List recommendationTypeListToJson( + List? recommendationType) { + if (recommendationType == null) { + return []; + } + + return recommendationType.map((e) => e.value!).toList(); +} + +List recommendationTypeListFromJson( + List? recommendationType, [ + List? defaultValue, +]) { + if (recommendationType == null) { + return defaultValue ?? []; + } + + return recommendationType + .map((e) => recommendationTypeFromJson(e.toString())) + .toList(); +} + +List? recommendationTypeNullableListFromJson( + List? recommendationType, [ + List? defaultValue, +]) { + if (recommendationType == null) { + return defaultValue; + } + + return recommendationType + .map((e) => recommendationTypeFromJson(e.toString())) + .toList(); +} + +String? recordingStatusNullableToJson(enums.RecordingStatus? recordingStatus) { + return recordingStatus?.value; +} + +String? recordingStatusToJson(enums.RecordingStatus recordingStatus) { + return recordingStatus.value; +} + +enums.RecordingStatus recordingStatusFromJson( + Object? recordingStatus, [ + enums.RecordingStatus? defaultValue, +]) { + return enums.RecordingStatus.values + .firstWhereOrNull((e) => e.value == recordingStatus) ?? + defaultValue ?? + enums.RecordingStatus.swaggerGeneratedUnknown; +} + +enums.RecordingStatus? recordingStatusNullableFromJson( + Object? recordingStatus, [ + enums.RecordingStatus? defaultValue, +]) { + if (recordingStatus == null) { + return null; + } + return enums.RecordingStatus.values + .firstWhereOrNull((e) => e.value == recordingStatus) ?? + defaultValue; +} + +String recordingStatusExplodedListToJson( + List? recordingStatus) { + return recordingStatus?.map((e) => e.value!).join(',') ?? ''; +} + +List recordingStatusListToJson( + List? recordingStatus) { + if (recordingStatus == null) { + return []; + } + + return recordingStatus.map((e) => e.value!).toList(); +} + +List recordingStatusListFromJson( + List? recordingStatus, [ + List? defaultValue, +]) { + if (recordingStatus == null) { + return defaultValue ?? []; + } + + return recordingStatus + .map((e) => recordingStatusFromJson(e.toString())) + .toList(); +} + +List? recordingStatusNullableListFromJson( + List? recordingStatus, [ + List? defaultValue, +]) { + if (recordingStatus == null) { + return defaultValue; + } + + return recordingStatus + .map((e) => recordingStatusFromJson(e.toString())) + .toList(); +} + +String? repeatModeNullableToJson(enums.RepeatMode? repeatMode) { + return repeatMode?.value; +} + +String? repeatModeToJson(enums.RepeatMode repeatMode) { + return repeatMode.value; +} + +enums.RepeatMode repeatModeFromJson( + Object? repeatMode, [ + enums.RepeatMode? defaultValue, +]) { + return enums.RepeatMode.values + .firstWhereOrNull((e) => e.value == repeatMode) ?? + defaultValue ?? + enums.RepeatMode.swaggerGeneratedUnknown; +} + +enums.RepeatMode? repeatModeNullableFromJson( + Object? repeatMode, [ + enums.RepeatMode? defaultValue, +]) { + if (repeatMode == null) { + return null; + } + return enums.RepeatMode.values + .firstWhereOrNull((e) => e.value == repeatMode) ?? + defaultValue; +} + +String repeatModeExplodedListToJson(List? repeatMode) { + return repeatMode?.map((e) => e.value!).join(',') ?? ''; +} + +List repeatModeListToJson(List? repeatMode) { + if (repeatMode == null) { + return []; + } + + return repeatMode.map((e) => e.value!).toList(); +} + +List repeatModeListFromJson( + List? repeatMode, [ + List? defaultValue, +]) { + if (repeatMode == null) { + return defaultValue ?? []; + } + + return repeatMode.map((e) => repeatModeFromJson(e.toString())).toList(); +} + +List? repeatModeNullableListFromJson( + List? repeatMode, [ + List? defaultValue, +]) { + if (repeatMode == null) { + return defaultValue; + } + + return repeatMode.map((e) => repeatModeFromJson(e.toString())).toList(); +} + +String? scrollDirectionNullableToJson(enums.ScrollDirection? scrollDirection) { + return scrollDirection?.value; +} + +String? scrollDirectionToJson(enums.ScrollDirection scrollDirection) { + return scrollDirection.value; +} + +enums.ScrollDirection scrollDirectionFromJson( + Object? scrollDirection, [ + enums.ScrollDirection? defaultValue, +]) { + return enums.ScrollDirection.values + .firstWhereOrNull((e) => e.value == scrollDirection) ?? + defaultValue ?? + enums.ScrollDirection.swaggerGeneratedUnknown; +} + +enums.ScrollDirection? scrollDirectionNullableFromJson( + Object? scrollDirection, [ + enums.ScrollDirection? defaultValue, +]) { + if (scrollDirection == null) { + return null; + } + return enums.ScrollDirection.values + .firstWhereOrNull((e) => e.value == scrollDirection) ?? + defaultValue; +} + +String scrollDirectionExplodedListToJson( + List? scrollDirection) { + return scrollDirection?.map((e) => e.value!).join(',') ?? ''; +} + +List scrollDirectionListToJson( + List? scrollDirection) { + if (scrollDirection == null) { + return []; + } + + return scrollDirection.map((e) => e.value!).toList(); +} + +List scrollDirectionListFromJson( + List? scrollDirection, [ + List? defaultValue, +]) { + if (scrollDirection == null) { + return defaultValue ?? []; + } + + return scrollDirection + .map((e) => scrollDirectionFromJson(e.toString())) + .toList(); +} + +List? scrollDirectionNullableListFromJson( + List? scrollDirection, [ + List? defaultValue, +]) { + if (scrollDirection == null) { + return defaultValue; + } + + return scrollDirection + .map((e) => scrollDirectionFromJson(e.toString())) + .toList(); +} + +String? sendCommandTypeNullableToJson(enums.SendCommandType? sendCommandType) { + return sendCommandType?.value; +} + +String? sendCommandTypeToJson(enums.SendCommandType sendCommandType) { + return sendCommandType.value; +} + +enums.SendCommandType sendCommandTypeFromJson( + Object? sendCommandType, [ + enums.SendCommandType? defaultValue, +]) { + return enums.SendCommandType.values + .firstWhereOrNull((e) => e.value == sendCommandType) ?? + defaultValue ?? + enums.SendCommandType.swaggerGeneratedUnknown; +} + +enums.SendCommandType? sendCommandTypeNullableFromJson( + Object? sendCommandType, [ + enums.SendCommandType? defaultValue, +]) { + if (sendCommandType == null) { + return null; + } + return enums.SendCommandType.values + .firstWhereOrNull((e) => e.value == sendCommandType) ?? + defaultValue; +} + +String sendCommandTypeExplodedListToJson( + List? sendCommandType) { + return sendCommandType?.map((e) => e.value!).join(',') ?? ''; +} + +List sendCommandTypeListToJson( + List? sendCommandType) { + if (sendCommandType == null) { + return []; + } + + return sendCommandType.map((e) => e.value!).toList(); +} + +List sendCommandTypeListFromJson( + List? sendCommandType, [ + List? defaultValue, +]) { + if (sendCommandType == null) { + return defaultValue ?? []; + } + + return sendCommandType + .map((e) => sendCommandTypeFromJson(e.toString())) + .toList(); +} + +List? sendCommandTypeNullableListFromJson( + List? sendCommandType, [ + List? defaultValue, +]) { + if (sendCommandType == null) { + return defaultValue; + } + + return sendCommandType + .map((e) => sendCommandTypeFromJson(e.toString())) + .toList(); +} + +String? seriesStatusNullableToJson(enums.SeriesStatus? seriesStatus) { + return seriesStatus?.value; +} + +String? seriesStatusToJson(enums.SeriesStatus seriesStatus) { + return seriesStatus.value; +} + +enums.SeriesStatus seriesStatusFromJson( + Object? seriesStatus, [ + enums.SeriesStatus? defaultValue, +]) { + return enums.SeriesStatus.values + .firstWhereOrNull((e) => e.value == seriesStatus) ?? + defaultValue ?? + enums.SeriesStatus.swaggerGeneratedUnknown; +} + +enums.SeriesStatus? seriesStatusNullableFromJson( + Object? seriesStatus, [ + enums.SeriesStatus? defaultValue, +]) { + if (seriesStatus == null) { + return null; + } + return enums.SeriesStatus.values + .firstWhereOrNull((e) => e.value == seriesStatus) ?? + defaultValue; +} + +String seriesStatusExplodedListToJson(List? seriesStatus) { + return seriesStatus?.map((e) => e.value!).join(',') ?? ''; +} + +List seriesStatusListToJson(List? seriesStatus) { + if (seriesStatus == null) { + return []; + } + + return seriesStatus.map((e) => e.value!).toList(); +} + +List seriesStatusListFromJson( + List? seriesStatus, [ + List? defaultValue, +]) { + if (seriesStatus == null) { + return defaultValue ?? []; + } + + return seriesStatus.map((e) => seriesStatusFromJson(e.toString())).toList(); +} + +List? seriesStatusNullableListFromJson( + List? seriesStatus, [ + List? defaultValue, +]) { + if (seriesStatus == null) { + return defaultValue; + } + + return seriesStatus.map((e) => seriesStatusFromJson(e.toString())).toList(); +} + +String? sessionMessageTypeNullableToJson( + enums.SessionMessageType? sessionMessageType) { + return sessionMessageType?.value; +} + +String? sessionMessageTypeToJson(enums.SessionMessageType sessionMessageType) { + return sessionMessageType.value; +} + +enums.SessionMessageType sessionMessageTypeFromJson( + Object? sessionMessageType, [ + enums.SessionMessageType? defaultValue, +]) { + return enums.SessionMessageType.values + .firstWhereOrNull((e) => e.value == sessionMessageType) ?? + defaultValue ?? + enums.SessionMessageType.swaggerGeneratedUnknown; +} + +enums.SessionMessageType? sessionMessageTypeNullableFromJson( + Object? sessionMessageType, [ + enums.SessionMessageType? defaultValue, +]) { + if (sessionMessageType == null) { + return null; + } + return enums.SessionMessageType.values + .firstWhereOrNull((e) => e.value == sessionMessageType) ?? + defaultValue; +} + +String sessionMessageTypeExplodedListToJson( + List? sessionMessageType) { + return sessionMessageType?.map((e) => e.value!).join(',') ?? ''; +} + +List sessionMessageTypeListToJson( + List? sessionMessageType) { + if (sessionMessageType == null) { + return []; + } + + return sessionMessageType.map((e) => e.value!).toList(); +} + +List sessionMessageTypeListFromJson( + List? sessionMessageType, [ + List? defaultValue, +]) { + if (sessionMessageType == null) { + return defaultValue ?? []; + } + + return sessionMessageType + .map((e) => sessionMessageTypeFromJson(e.toString())) + .toList(); +} + +List? sessionMessageTypeNullableListFromJson( + List? sessionMessageType, [ + List? defaultValue, +]) { + if (sessionMessageType == null) { + return defaultValue; + } + + return sessionMessageType + .map((e) => sessionMessageTypeFromJson(e.toString())) + .toList(); +} + +String? sortOrderNullableToJson(enums.SortOrder? sortOrder) { + return sortOrder?.value; +} + +String? sortOrderToJson(enums.SortOrder sortOrder) { + return sortOrder.value; +} + +enums.SortOrder sortOrderFromJson( + Object? sortOrder, [ + enums.SortOrder? defaultValue, +]) { + return enums.SortOrder.values.firstWhereOrNull((e) => e.value == sortOrder) ?? + defaultValue ?? + enums.SortOrder.swaggerGeneratedUnknown; +} + +enums.SortOrder? sortOrderNullableFromJson( + Object? sortOrder, [ + enums.SortOrder? defaultValue, +]) { + if (sortOrder == null) { + return null; + } + return enums.SortOrder.values.firstWhereOrNull((e) => e.value == sortOrder) ?? + defaultValue; +} + +String sortOrderExplodedListToJson(List? sortOrder) { + return sortOrder?.map((e) => e.value!).join(',') ?? ''; +} + +List sortOrderListToJson(List? sortOrder) { + if (sortOrder == null) { + return []; + } + + return sortOrder.map((e) => e.value!).toList(); +} + +List sortOrderListFromJson( + List? sortOrder, [ + List? defaultValue, +]) { + if (sortOrder == null) { + return defaultValue ?? []; + } + + return sortOrder.map((e) => sortOrderFromJson(e.toString())).toList(); +} + +List? sortOrderNullableListFromJson( + List? sortOrder, [ + List? defaultValue, +]) { + if (sortOrder == null) { + return defaultValue; + } + + return sortOrder.map((e) => sortOrderFromJson(e.toString())).toList(); +} + +String? subtitleDeliveryMethodNullableToJson( + enums.SubtitleDeliveryMethod? subtitleDeliveryMethod) { + return subtitleDeliveryMethod?.value; +} + +String? subtitleDeliveryMethodToJson( + enums.SubtitleDeliveryMethod subtitleDeliveryMethod) { + return subtitleDeliveryMethod.value; +} + +enums.SubtitleDeliveryMethod subtitleDeliveryMethodFromJson( + Object? subtitleDeliveryMethod, [ + enums.SubtitleDeliveryMethod? defaultValue, +]) { + return enums.SubtitleDeliveryMethod.values + .firstWhereOrNull((e) => e.value == subtitleDeliveryMethod) ?? + defaultValue ?? + enums.SubtitleDeliveryMethod.swaggerGeneratedUnknown; +} + +enums.SubtitleDeliveryMethod? subtitleDeliveryMethodNullableFromJson( + Object? subtitleDeliveryMethod, [ + enums.SubtitleDeliveryMethod? defaultValue, +]) { + if (subtitleDeliveryMethod == null) { + return null; + } + return enums.SubtitleDeliveryMethod.values + .firstWhereOrNull((e) => e.value == subtitleDeliveryMethod) ?? + defaultValue; +} + +String subtitleDeliveryMethodExplodedListToJson( + List? subtitleDeliveryMethod) { + return subtitleDeliveryMethod?.map((e) => e.value!).join(',') ?? ''; +} + +List subtitleDeliveryMethodListToJson( + List? subtitleDeliveryMethod) { + if (subtitleDeliveryMethod == null) { + return []; + } + + return subtitleDeliveryMethod.map((e) => e.value!).toList(); +} + +List subtitleDeliveryMethodListFromJson( + List? subtitleDeliveryMethod, [ + List? defaultValue, +]) { + if (subtitleDeliveryMethod == null) { + return defaultValue ?? []; + } + + return subtitleDeliveryMethod + .map((e) => subtitleDeliveryMethodFromJson(e.toString())) + .toList(); +} + +List? subtitleDeliveryMethodNullableListFromJson( + List? subtitleDeliveryMethod, [ + List? defaultValue, +]) { + if (subtitleDeliveryMethod == null) { + return defaultValue; + } + + return subtitleDeliveryMethod + .map((e) => subtitleDeliveryMethodFromJson(e.toString())) + .toList(); +} + +String? subtitlePlaybackModeNullableToJson( + enums.SubtitlePlaybackMode? subtitlePlaybackMode) { + return subtitlePlaybackMode?.value; +} + +String? subtitlePlaybackModeToJson( + enums.SubtitlePlaybackMode subtitlePlaybackMode) { + return subtitlePlaybackMode.value; +} + +enums.SubtitlePlaybackMode subtitlePlaybackModeFromJson( + Object? subtitlePlaybackMode, [ + enums.SubtitlePlaybackMode? defaultValue, +]) { + return enums.SubtitlePlaybackMode.values + .firstWhereOrNull((e) => e.value == subtitlePlaybackMode) ?? + defaultValue ?? + enums.SubtitlePlaybackMode.swaggerGeneratedUnknown; +} + +enums.SubtitlePlaybackMode? subtitlePlaybackModeNullableFromJson( + Object? subtitlePlaybackMode, [ + enums.SubtitlePlaybackMode? defaultValue, +]) { + if (subtitlePlaybackMode == null) { + return null; + } + return enums.SubtitlePlaybackMode.values + .firstWhereOrNull((e) => e.value == subtitlePlaybackMode) ?? + defaultValue; +} + +String subtitlePlaybackModeExplodedListToJson( + List? subtitlePlaybackMode) { + return subtitlePlaybackMode?.map((e) => e.value!).join(',') ?? ''; +} + +List subtitlePlaybackModeListToJson( + List? subtitlePlaybackMode) { + if (subtitlePlaybackMode == null) { + return []; + } + + return subtitlePlaybackMode.map((e) => e.value!).toList(); +} + +List subtitlePlaybackModeListFromJson( + List? subtitlePlaybackMode, [ + List? defaultValue, +]) { + if (subtitlePlaybackMode == null) { + return defaultValue ?? []; + } + + return subtitlePlaybackMode + .map((e) => subtitlePlaybackModeFromJson(e.toString())) + .toList(); +} + +List? subtitlePlaybackModeNullableListFromJson( + List? subtitlePlaybackMode, [ + List? defaultValue, +]) { + if (subtitlePlaybackMode == null) { + return defaultValue; + } + + return subtitlePlaybackMode + .map((e) => subtitlePlaybackModeFromJson(e.toString())) + .toList(); +} + +String? syncPlayUserAccessTypeNullableToJson( + enums.SyncPlayUserAccessType? syncPlayUserAccessType) { + return syncPlayUserAccessType?.value; +} + +String? syncPlayUserAccessTypeToJson( + enums.SyncPlayUserAccessType syncPlayUserAccessType) { + return syncPlayUserAccessType.value; +} + +enums.SyncPlayUserAccessType syncPlayUserAccessTypeFromJson( + Object? syncPlayUserAccessType, [ + enums.SyncPlayUserAccessType? defaultValue, +]) { + return enums.SyncPlayUserAccessType.values + .firstWhereOrNull((e) => e.value == syncPlayUserAccessType) ?? + defaultValue ?? + enums.SyncPlayUserAccessType.swaggerGeneratedUnknown; +} + +enums.SyncPlayUserAccessType? syncPlayUserAccessTypeNullableFromJson( + Object? syncPlayUserAccessType, [ + enums.SyncPlayUserAccessType? defaultValue, +]) { + if (syncPlayUserAccessType == null) { + return null; + } + return enums.SyncPlayUserAccessType.values + .firstWhereOrNull((e) => e.value == syncPlayUserAccessType) ?? + defaultValue; +} + +String syncPlayUserAccessTypeExplodedListToJson( + List? syncPlayUserAccessType) { + return syncPlayUserAccessType?.map((e) => e.value!).join(',') ?? ''; +} + +List syncPlayUserAccessTypeListToJson( + List? syncPlayUserAccessType) { + if (syncPlayUserAccessType == null) { + return []; + } + + return syncPlayUserAccessType.map((e) => e.value!).toList(); +} + +List syncPlayUserAccessTypeListFromJson( + List? syncPlayUserAccessType, [ + List? defaultValue, +]) { + if (syncPlayUserAccessType == null) { + return defaultValue ?? []; + } + + return syncPlayUserAccessType + .map((e) => syncPlayUserAccessTypeFromJson(e.toString())) + .toList(); +} + +List? syncPlayUserAccessTypeNullableListFromJson( + List? syncPlayUserAccessType, [ + List? defaultValue, +]) { + if (syncPlayUserAccessType == null) { + return defaultValue; + } + + return syncPlayUserAccessType + .map((e) => syncPlayUserAccessTypeFromJson(e.toString())) + .toList(); +} + +String? taskCompletionStatusNullableToJson( + enums.TaskCompletionStatus? taskCompletionStatus) { + return taskCompletionStatus?.value; +} + +String? taskCompletionStatusToJson( + enums.TaskCompletionStatus taskCompletionStatus) { + return taskCompletionStatus.value; +} + +enums.TaskCompletionStatus taskCompletionStatusFromJson( + Object? taskCompletionStatus, [ + enums.TaskCompletionStatus? defaultValue, +]) { + return enums.TaskCompletionStatus.values + .firstWhereOrNull((e) => e.value == taskCompletionStatus) ?? + defaultValue ?? + enums.TaskCompletionStatus.swaggerGeneratedUnknown; +} + +enums.TaskCompletionStatus? taskCompletionStatusNullableFromJson( + Object? taskCompletionStatus, [ + enums.TaskCompletionStatus? defaultValue, +]) { + if (taskCompletionStatus == null) { + return null; + } + return enums.TaskCompletionStatus.values + .firstWhereOrNull((e) => e.value == taskCompletionStatus) ?? + defaultValue; +} + +String taskCompletionStatusExplodedListToJson( + List? taskCompletionStatus) { + return taskCompletionStatus?.map((e) => e.value!).join(',') ?? ''; +} + +List taskCompletionStatusListToJson( + List? taskCompletionStatus) { + if (taskCompletionStatus == null) { + return []; + } + + return taskCompletionStatus.map((e) => e.value!).toList(); +} + +List taskCompletionStatusListFromJson( + List? taskCompletionStatus, [ + List? defaultValue, +]) { + if (taskCompletionStatus == null) { + return defaultValue ?? []; + } + + return taskCompletionStatus + .map((e) => taskCompletionStatusFromJson(e.toString())) + .toList(); +} + +List? taskCompletionStatusNullableListFromJson( + List? taskCompletionStatus, [ + List? defaultValue, +]) { + if (taskCompletionStatus == null) { + return defaultValue; + } + + return taskCompletionStatus + .map((e) => taskCompletionStatusFromJson(e.toString())) + .toList(); +} + +String? taskStateNullableToJson(enums.TaskState? taskState) { + return taskState?.value; +} + +String? taskStateToJson(enums.TaskState taskState) { + return taskState.value; +} + +enums.TaskState taskStateFromJson( + Object? taskState, [ + enums.TaskState? defaultValue, +]) { + return enums.TaskState.values.firstWhereOrNull((e) => e.value == taskState) ?? + defaultValue ?? + enums.TaskState.swaggerGeneratedUnknown; +} + +enums.TaskState? taskStateNullableFromJson( + Object? taskState, [ + enums.TaskState? defaultValue, +]) { + if (taskState == null) { + return null; + } + return enums.TaskState.values.firstWhereOrNull((e) => e.value == taskState) ?? + defaultValue; +} + +String taskStateExplodedListToJson(List? taskState) { + return taskState?.map((e) => e.value!).join(',') ?? ''; +} + +List taskStateListToJson(List? taskState) { + if (taskState == null) { + return []; + } + + return taskState.map((e) => e.value!).toList(); +} + +List taskStateListFromJson( + List? taskState, [ + List? defaultValue, +]) { + if (taskState == null) { + return defaultValue ?? []; + } + + return taskState.map((e) => taskStateFromJson(e.toString())).toList(); +} + +List? taskStateNullableListFromJson( + List? taskState, [ + List? defaultValue, +]) { + if (taskState == null) { + return defaultValue; + } + + return taskState.map((e) => taskStateFromJson(e.toString())).toList(); +} + +String? transcodeReasonNullableToJson(enums.TranscodeReason? transcodeReason) { + return transcodeReason?.value; +} + +String? transcodeReasonToJson(enums.TranscodeReason transcodeReason) { + return transcodeReason.value; +} + +enums.TranscodeReason transcodeReasonFromJson( + Object? transcodeReason, [ + enums.TranscodeReason? defaultValue, +]) { + return enums.TranscodeReason.values + .firstWhereOrNull((e) => e.value == transcodeReason) ?? + defaultValue ?? + enums.TranscodeReason.swaggerGeneratedUnknown; +} + +enums.TranscodeReason? transcodeReasonNullableFromJson( + Object? transcodeReason, [ + enums.TranscodeReason? defaultValue, +]) { + if (transcodeReason == null) { + return null; + } + return enums.TranscodeReason.values + .firstWhereOrNull((e) => e.value == transcodeReason) ?? + defaultValue; +} + +String transcodeReasonExplodedListToJson( + List? transcodeReason) { + return transcodeReason?.map((e) => e.value!).join(',') ?? ''; +} + +List transcodeReasonListToJson( + List? transcodeReason) { + if (transcodeReason == null) { + return []; + } + + return transcodeReason.map((e) => e.value!).toList(); +} + +List transcodeReasonListFromJson( + List? transcodeReason, [ + List? defaultValue, +]) { + if (transcodeReason == null) { + return defaultValue ?? []; + } + + return transcodeReason + .map((e) => transcodeReasonFromJson(e.toString())) + .toList(); +} + +List? transcodeReasonNullableListFromJson( + List? transcodeReason, [ + List? defaultValue, +]) { + if (transcodeReason == null) { + return defaultValue; + } + + return transcodeReason + .map((e) => transcodeReasonFromJson(e.toString())) + .toList(); +} + +String? transcodeSeekInfoNullableToJson( + enums.TranscodeSeekInfo? transcodeSeekInfo) { + return transcodeSeekInfo?.value; +} + +String? transcodeSeekInfoToJson(enums.TranscodeSeekInfo transcodeSeekInfo) { + return transcodeSeekInfo.value; +} + +enums.TranscodeSeekInfo transcodeSeekInfoFromJson( + Object? transcodeSeekInfo, [ + enums.TranscodeSeekInfo? defaultValue, +]) { + return enums.TranscodeSeekInfo.values + .firstWhereOrNull((e) => e.value == transcodeSeekInfo) ?? + defaultValue ?? + enums.TranscodeSeekInfo.swaggerGeneratedUnknown; +} + +enums.TranscodeSeekInfo? transcodeSeekInfoNullableFromJson( + Object? transcodeSeekInfo, [ + enums.TranscodeSeekInfo? defaultValue, +]) { + if (transcodeSeekInfo == null) { + return null; + } + return enums.TranscodeSeekInfo.values + .firstWhereOrNull((e) => e.value == transcodeSeekInfo) ?? + defaultValue; +} + +String transcodeSeekInfoExplodedListToJson( + List? transcodeSeekInfo) { + return transcodeSeekInfo?.map((e) => e.value!).join(',') ?? ''; +} + +List transcodeSeekInfoListToJson( + List? transcodeSeekInfo) { + if (transcodeSeekInfo == null) { + return []; + } + + return transcodeSeekInfo.map((e) => e.value!).toList(); +} + +List transcodeSeekInfoListFromJson( + List? transcodeSeekInfo, [ + List? defaultValue, +]) { + if (transcodeSeekInfo == null) { + return defaultValue ?? []; + } + + return transcodeSeekInfo + .map((e) => transcodeSeekInfoFromJson(e.toString())) + .toList(); +} + +List? transcodeSeekInfoNullableListFromJson( + List? transcodeSeekInfo, [ + List? defaultValue, +]) { + if (transcodeSeekInfo == null) { + return defaultValue; + } + + return transcodeSeekInfo + .map((e) => transcodeSeekInfoFromJson(e.toString())) + .toList(); +} + +String? transcodingInfoTranscodeReasonsNullableToJson( + enums.TranscodingInfoTranscodeReasons? transcodingInfoTranscodeReasons) { + return transcodingInfoTranscodeReasons?.value; +} + +String? transcodingInfoTranscodeReasonsToJson( + enums.TranscodingInfoTranscodeReasons transcodingInfoTranscodeReasons) { + return transcodingInfoTranscodeReasons.value; +} + +enums.TranscodingInfoTranscodeReasons transcodingInfoTranscodeReasonsFromJson( + Object? transcodingInfoTranscodeReasons, [ + enums.TranscodingInfoTranscodeReasons? defaultValue, +]) { + return enums.TranscodingInfoTranscodeReasons.values.firstWhereOrNull( + (e) => e.value == transcodingInfoTranscodeReasons) ?? + defaultValue ?? + enums.TranscodingInfoTranscodeReasons.swaggerGeneratedUnknown; +} + +enums.TranscodingInfoTranscodeReasons? + transcodingInfoTranscodeReasonsNullableFromJson( + Object? transcodingInfoTranscodeReasons, [ + enums.TranscodingInfoTranscodeReasons? defaultValue, +]) { + if (transcodingInfoTranscodeReasons == null) { + return null; + } + return enums.TranscodingInfoTranscodeReasons.values.firstWhereOrNull( + (e) => e.value == transcodingInfoTranscodeReasons) ?? + defaultValue; +} + +String transcodingInfoTranscodeReasonsExplodedListToJson( + List? + transcodingInfoTranscodeReasons) { + return transcodingInfoTranscodeReasons?.map((e) => e.value!).join(',') ?? ''; +} + +List transcodingInfoTranscodeReasonsListToJson( + List? + transcodingInfoTranscodeReasons) { + if (transcodingInfoTranscodeReasons == null) { + return []; + } + + return transcodingInfoTranscodeReasons.map((e) => e.value!).toList(); +} + +List + transcodingInfoTranscodeReasonsListFromJson( + List? transcodingInfoTranscodeReasons, [ + List? defaultValue, +]) { + if (transcodingInfoTranscodeReasons == null) { + return defaultValue ?? []; + } + + return transcodingInfoTranscodeReasons + .map((e) => transcodingInfoTranscodeReasonsFromJson(e.toString())) + .toList(); +} + +List? + transcodingInfoTranscodeReasonsNullableListFromJson( + List? transcodingInfoTranscodeReasons, [ + List? defaultValue, +]) { + if (transcodingInfoTranscodeReasons == null) { + return defaultValue; + } + + return transcodingInfoTranscodeReasons + .map((e) => transcodingInfoTranscodeReasonsFromJson(e.toString())) + .toList(); +} + +String? transportStreamTimestampNullableToJson( + enums.TransportStreamTimestamp? transportStreamTimestamp) { + return transportStreamTimestamp?.value; +} + +String? transportStreamTimestampToJson( + enums.TransportStreamTimestamp transportStreamTimestamp) { + return transportStreamTimestamp.value; +} + +enums.TransportStreamTimestamp transportStreamTimestampFromJson( + Object? transportStreamTimestamp, [ + enums.TransportStreamTimestamp? defaultValue, +]) { + return enums.TransportStreamTimestamp.values + .firstWhereOrNull((e) => e.value == transportStreamTimestamp) ?? + defaultValue ?? + enums.TransportStreamTimestamp.swaggerGeneratedUnknown; +} + +enums.TransportStreamTimestamp? transportStreamTimestampNullableFromJson( + Object? transportStreamTimestamp, [ + enums.TransportStreamTimestamp? defaultValue, +]) { + if (transportStreamTimestamp == null) { + return null; + } + return enums.TransportStreamTimestamp.values + .firstWhereOrNull((e) => e.value == transportStreamTimestamp) ?? + defaultValue; +} + +String transportStreamTimestampExplodedListToJson( + List? transportStreamTimestamp) { + return transportStreamTimestamp?.map((e) => e.value!).join(',') ?? ''; +} + +List transportStreamTimestampListToJson( + List? transportStreamTimestamp) { + if (transportStreamTimestamp == null) { + return []; + } + + return transportStreamTimestamp.map((e) => e.value!).toList(); +} + +List transportStreamTimestampListFromJson( + List? transportStreamTimestamp, [ + List? defaultValue, +]) { + if (transportStreamTimestamp == null) { + return defaultValue ?? []; + } + + return transportStreamTimestamp + .map((e) => transportStreamTimestampFromJson(e.toString())) + .toList(); +} + +List? + transportStreamTimestampNullableListFromJson( + List? transportStreamTimestamp, [ + List? defaultValue, +]) { + if (transportStreamTimestamp == null) { + return defaultValue; + } + + return transportStreamTimestamp + .map((e) => transportStreamTimestampFromJson(e.toString())) + .toList(); +} + +String? trickplayScanBehaviorNullableToJson( + enums.TrickplayScanBehavior? trickplayScanBehavior) { + return trickplayScanBehavior?.value; +} + +String? trickplayScanBehaviorToJson( + enums.TrickplayScanBehavior trickplayScanBehavior) { + return trickplayScanBehavior.value; +} + +enums.TrickplayScanBehavior trickplayScanBehaviorFromJson( + Object? trickplayScanBehavior, [ + enums.TrickplayScanBehavior? defaultValue, +]) { + return enums.TrickplayScanBehavior.values + .firstWhereOrNull((e) => e.value == trickplayScanBehavior) ?? + defaultValue ?? + enums.TrickplayScanBehavior.swaggerGeneratedUnknown; +} + +enums.TrickplayScanBehavior? trickplayScanBehaviorNullableFromJson( + Object? trickplayScanBehavior, [ + enums.TrickplayScanBehavior? defaultValue, +]) { + if (trickplayScanBehavior == null) { + return null; + } + return enums.TrickplayScanBehavior.values + .firstWhereOrNull((e) => e.value == trickplayScanBehavior) ?? + defaultValue; +} + +String trickplayScanBehaviorExplodedListToJson( + List? trickplayScanBehavior) { + return trickplayScanBehavior?.map((e) => e.value!).join(',') ?? ''; +} + +List trickplayScanBehaviorListToJson( + List? trickplayScanBehavior) { + if (trickplayScanBehavior == null) { + return []; + } + + return trickplayScanBehavior.map((e) => e.value!).toList(); +} + +List trickplayScanBehaviorListFromJson( + List? trickplayScanBehavior, [ + List? defaultValue, +]) { + if (trickplayScanBehavior == null) { + return defaultValue ?? []; + } + + return trickplayScanBehavior + .map((e) => trickplayScanBehaviorFromJson(e.toString())) + .toList(); +} + +List? trickplayScanBehaviorNullableListFromJson( + List? trickplayScanBehavior, [ + List? defaultValue, +]) { + if (trickplayScanBehavior == null) { + return defaultValue; + } + + return trickplayScanBehavior + .map((e) => trickplayScanBehaviorFromJson(e.toString())) + .toList(); +} + +String? unratedItemNullableToJson(enums.UnratedItem? unratedItem) { + return unratedItem?.value; +} + +String? unratedItemToJson(enums.UnratedItem unratedItem) { + return unratedItem.value; +} + +enums.UnratedItem unratedItemFromJson( + Object? unratedItem, [ + enums.UnratedItem? defaultValue, +]) { + return enums.UnratedItem.values + .firstWhereOrNull((e) => e.value == unratedItem) ?? + defaultValue ?? + enums.UnratedItem.swaggerGeneratedUnknown; +} + +enums.UnratedItem? unratedItemNullableFromJson( + Object? unratedItem, [ + enums.UnratedItem? defaultValue, +]) { + if (unratedItem == null) { + return null; + } + return enums.UnratedItem.values + .firstWhereOrNull((e) => e.value == unratedItem) ?? + defaultValue; +} + +String unratedItemExplodedListToJson(List? unratedItem) { + return unratedItem?.map((e) => e.value!).join(',') ?? ''; +} + +List unratedItemListToJson(List? unratedItem) { + if (unratedItem == null) { + return []; + } + + return unratedItem.map((e) => e.value!).toList(); +} + +List unratedItemListFromJson( + List? unratedItem, [ + List? defaultValue, +]) { + if (unratedItem == null) { + return defaultValue ?? []; + } + + return unratedItem.map((e) => unratedItemFromJson(e.toString())).toList(); +} + +List? unratedItemNullableListFromJson( + List? unratedItem, [ + List? defaultValue, +]) { + if (unratedItem == null) { + return defaultValue; + } + + return unratedItem.map((e) => unratedItemFromJson(e.toString())).toList(); +} + +String? video3DFormatNullableToJson(enums.Video3DFormat? video3DFormat) { + return video3DFormat?.value; +} + +String? video3DFormatToJson(enums.Video3DFormat video3DFormat) { + return video3DFormat.value; +} + +enums.Video3DFormat video3DFormatFromJson( + Object? video3DFormat, [ + enums.Video3DFormat? defaultValue, +]) { + return enums.Video3DFormat.values + .firstWhereOrNull((e) => e.value == video3DFormat) ?? + defaultValue ?? + enums.Video3DFormat.swaggerGeneratedUnknown; +} + +enums.Video3DFormat? video3DFormatNullableFromJson( + Object? video3DFormat, [ + enums.Video3DFormat? defaultValue, +]) { + if (video3DFormat == null) { + return null; + } + return enums.Video3DFormat.values + .firstWhereOrNull((e) => e.value == video3DFormat) ?? + defaultValue; +} + +String video3DFormatExplodedListToJson( + List? video3DFormat) { + return video3DFormat?.map((e) => e.value!).join(',') ?? ''; +} + +List video3DFormatListToJson(List? video3DFormat) { + if (video3DFormat == null) { + return []; + } + + return video3DFormat.map((e) => e.value!).toList(); +} + +List video3DFormatListFromJson( + List? video3DFormat, [ + List? defaultValue, +]) { + if (video3DFormat == null) { + return defaultValue ?? []; + } + + return video3DFormat.map((e) => video3DFormatFromJson(e.toString())).toList(); +} + +List? video3DFormatNullableListFromJson( + List? video3DFormat, [ + List? defaultValue, +]) { + if (video3DFormat == null) { + return defaultValue; + } + + return video3DFormat.map((e) => video3DFormatFromJson(e.toString())).toList(); +} + +String? videoRangeNullableToJson(enums.VideoRange? videoRange) { + return videoRange?.value; +} + +String? videoRangeToJson(enums.VideoRange videoRange) { + return videoRange.value; +} + +enums.VideoRange videoRangeFromJson( + Object? videoRange, [ + enums.VideoRange? defaultValue, +]) { + return enums.VideoRange.values + .firstWhereOrNull((e) => e.value == videoRange) ?? + defaultValue ?? + enums.VideoRange.swaggerGeneratedUnknown; +} + +enums.VideoRange? videoRangeNullableFromJson( + Object? videoRange, [ + enums.VideoRange? defaultValue, +]) { + if (videoRange == null) { + return null; + } + return enums.VideoRange.values + .firstWhereOrNull((e) => e.value == videoRange) ?? + defaultValue; +} + +String videoRangeExplodedListToJson(List? videoRange) { + return videoRange?.map((e) => e.value!).join(',') ?? ''; +} + +List videoRangeListToJson(List? videoRange) { + if (videoRange == null) { + return []; + } + + return videoRange.map((e) => e.value!).toList(); +} + +List videoRangeListFromJson( + List? videoRange, [ + List? defaultValue, +]) { + if (videoRange == null) { + return defaultValue ?? []; + } + + return videoRange.map((e) => videoRangeFromJson(e.toString())).toList(); +} + +List? videoRangeNullableListFromJson( + List? videoRange, [ + List? defaultValue, +]) { + if (videoRange == null) { + return defaultValue; + } + + return videoRange.map((e) => videoRangeFromJson(e.toString())).toList(); +} + +String? videoRangeTypeNullableToJson(enums.VideoRangeType? videoRangeType) { + return videoRangeType?.value; +} + +String? videoRangeTypeToJson(enums.VideoRangeType videoRangeType) { + return videoRangeType.value; +} + +enums.VideoRangeType videoRangeTypeFromJson( + Object? videoRangeType, [ + enums.VideoRangeType? defaultValue, +]) { + return enums.VideoRangeType.values + .firstWhereOrNull((e) => e.value == videoRangeType) ?? + defaultValue ?? + enums.VideoRangeType.swaggerGeneratedUnknown; +} + +enums.VideoRangeType? videoRangeTypeNullableFromJson( + Object? videoRangeType, [ + enums.VideoRangeType? defaultValue, +]) { + if (videoRangeType == null) { + return null; + } + return enums.VideoRangeType.values + .firstWhereOrNull((e) => e.value == videoRangeType) ?? + defaultValue; +} + +String videoRangeTypeExplodedListToJson( + List? videoRangeType) { + return videoRangeType?.map((e) => e.value!).join(',') ?? ''; +} + +List videoRangeTypeListToJson( + List? videoRangeType) { + if (videoRangeType == null) { + return []; + } + + return videoRangeType.map((e) => e.value!).toList(); +} + +List videoRangeTypeListFromJson( + List? videoRangeType, [ + List? defaultValue, +]) { + if (videoRangeType == null) { + return defaultValue ?? []; + } + + return videoRangeType + .map((e) => videoRangeTypeFromJson(e.toString())) + .toList(); +} + +List? videoRangeTypeNullableListFromJson( + List? videoRangeType, [ + List? defaultValue, +]) { + if (videoRangeType == null) { + return defaultValue; + } + + return videoRangeType + .map((e) => videoRangeTypeFromJson(e.toString())) + .toList(); +} + +String? videoTypeNullableToJson(enums.VideoType? videoType) { + return videoType?.value; +} + +String? videoTypeToJson(enums.VideoType videoType) { + return videoType.value; +} + +enums.VideoType videoTypeFromJson( + Object? videoType, [ + enums.VideoType? defaultValue, +]) { + return enums.VideoType.values.firstWhereOrNull((e) => e.value == videoType) ?? + defaultValue ?? + enums.VideoType.swaggerGeneratedUnknown; +} + +enums.VideoType? videoTypeNullableFromJson( + Object? videoType, [ + enums.VideoType? defaultValue, +]) { + if (videoType == null) { + return null; + } + return enums.VideoType.values.firstWhereOrNull((e) => e.value == videoType) ?? + defaultValue; +} + +String videoTypeExplodedListToJson(List? videoType) { + return videoType?.map((e) => e.value!).join(',') ?? ''; +} + +List videoTypeListToJson(List? videoType) { + if (videoType == null) { + return []; + } + + return videoType.map((e) => e.value!).toList(); +} + +List videoTypeListFromJson( + List? videoType, [ + List? defaultValue, +]) { + if (videoType == null) { + return defaultValue ?? []; + } + + return videoType.map((e) => videoTypeFromJson(e.toString())).toList(); +} + +List? videoTypeNullableListFromJson( + List? videoType, [ + List? defaultValue, +]) { + if (videoType == null) { + return defaultValue; + } + + return videoType.map((e) => videoTypeFromJson(e.toString())).toList(); +} + +String? audioItemIdStreamGetSubtitleMethodNullableToJson( + enums.AudioItemIdStreamGetSubtitleMethod? + audioItemIdStreamGetSubtitleMethod) { + return audioItemIdStreamGetSubtitleMethod?.value; +} + +String? audioItemIdStreamGetSubtitleMethodToJson( + enums.AudioItemIdStreamGetSubtitleMethod + audioItemIdStreamGetSubtitleMethod) { + return audioItemIdStreamGetSubtitleMethod.value; +} + +enums.AudioItemIdStreamGetSubtitleMethod + audioItemIdStreamGetSubtitleMethodFromJson( + Object? audioItemIdStreamGetSubtitleMethod, [ + enums.AudioItemIdStreamGetSubtitleMethod? defaultValue, +]) { + return enums.AudioItemIdStreamGetSubtitleMethod.values.firstWhereOrNull( + (e) => e.value == audioItemIdStreamGetSubtitleMethod) ?? + defaultValue ?? + enums.AudioItemIdStreamGetSubtitleMethod.swaggerGeneratedUnknown; +} + +enums.AudioItemIdStreamGetSubtitleMethod? + audioItemIdStreamGetSubtitleMethodNullableFromJson( + Object? audioItemIdStreamGetSubtitleMethod, [ + enums.AudioItemIdStreamGetSubtitleMethod? defaultValue, +]) { + if (audioItemIdStreamGetSubtitleMethod == null) { + return null; + } + return enums.AudioItemIdStreamGetSubtitleMethod.values.firstWhereOrNull( + (e) => e.value == audioItemIdStreamGetSubtitleMethod) ?? + defaultValue; +} + +String audioItemIdStreamGetSubtitleMethodExplodedListToJson( + List? + audioItemIdStreamGetSubtitleMethod) { + return audioItemIdStreamGetSubtitleMethod?.map((e) => e.value!).join(',') ?? + ''; +} + +List audioItemIdStreamGetSubtitleMethodListToJson( + List? + audioItemIdStreamGetSubtitleMethod) { + if (audioItemIdStreamGetSubtitleMethod == null) { + return []; + } + + return audioItemIdStreamGetSubtitleMethod.map((e) => e.value!).toList(); +} + +List + audioItemIdStreamGetSubtitleMethodListFromJson( + List? audioItemIdStreamGetSubtitleMethod, [ + List? defaultValue, +]) { + if (audioItemIdStreamGetSubtitleMethod == null) { + return defaultValue ?? []; + } + + return audioItemIdStreamGetSubtitleMethod + .map((e) => audioItemIdStreamGetSubtitleMethodFromJson(e.toString())) + .toList(); +} + +List? + audioItemIdStreamGetSubtitleMethodNullableListFromJson( + List? audioItemIdStreamGetSubtitleMethod, [ + List? defaultValue, +]) { + if (audioItemIdStreamGetSubtitleMethod == null) { + return defaultValue; + } + + return audioItemIdStreamGetSubtitleMethod + .map((e) => audioItemIdStreamGetSubtitleMethodFromJson(e.toString())) + .toList(); +} + +String? audioItemIdStreamGetContextNullableToJson( + enums.AudioItemIdStreamGetContext? audioItemIdStreamGetContext) { + return audioItemIdStreamGetContext?.value; +} + +String? audioItemIdStreamGetContextToJson( + enums.AudioItemIdStreamGetContext audioItemIdStreamGetContext) { + return audioItemIdStreamGetContext.value; +} + +enums.AudioItemIdStreamGetContext audioItemIdStreamGetContextFromJson( + Object? audioItemIdStreamGetContext, [ + enums.AudioItemIdStreamGetContext? defaultValue, +]) { + return enums.AudioItemIdStreamGetContext.values + .firstWhereOrNull((e) => e.value == audioItemIdStreamGetContext) ?? + defaultValue ?? + enums.AudioItemIdStreamGetContext.swaggerGeneratedUnknown; +} + +enums.AudioItemIdStreamGetContext? audioItemIdStreamGetContextNullableFromJson( + Object? audioItemIdStreamGetContext, [ + enums.AudioItemIdStreamGetContext? defaultValue, +]) { + if (audioItemIdStreamGetContext == null) { + return null; + } + return enums.AudioItemIdStreamGetContext.values + .firstWhereOrNull((e) => e.value == audioItemIdStreamGetContext) ?? + defaultValue; +} + +String audioItemIdStreamGetContextExplodedListToJson( + List? audioItemIdStreamGetContext) { + return audioItemIdStreamGetContext?.map((e) => e.value!).join(',') ?? ''; +} + +List audioItemIdStreamGetContextListToJson( + List? audioItemIdStreamGetContext) { + if (audioItemIdStreamGetContext == null) { + return []; + } + + return audioItemIdStreamGetContext.map((e) => e.value!).toList(); +} + +List audioItemIdStreamGetContextListFromJson( + List? audioItemIdStreamGetContext, [ + List? defaultValue, +]) { + if (audioItemIdStreamGetContext == null) { + return defaultValue ?? []; + } + + return audioItemIdStreamGetContext + .map((e) => audioItemIdStreamGetContextFromJson(e.toString())) + .toList(); +} + +List? + audioItemIdStreamGetContextNullableListFromJson( + List? audioItemIdStreamGetContext, [ + List? defaultValue, +]) { + if (audioItemIdStreamGetContext == null) { + return defaultValue; + } + + return audioItemIdStreamGetContext + .map((e) => audioItemIdStreamGetContextFromJson(e.toString())) + .toList(); +} + +String? audioItemIdStreamHeadSubtitleMethodNullableToJson( + enums.AudioItemIdStreamHeadSubtitleMethod? + audioItemIdStreamHeadSubtitleMethod) { + return audioItemIdStreamHeadSubtitleMethod?.value; +} + +String? audioItemIdStreamHeadSubtitleMethodToJson( + enums.AudioItemIdStreamHeadSubtitleMethod + audioItemIdStreamHeadSubtitleMethod) { + return audioItemIdStreamHeadSubtitleMethod.value; +} + +enums.AudioItemIdStreamHeadSubtitleMethod + audioItemIdStreamHeadSubtitleMethodFromJson( + Object? audioItemIdStreamHeadSubtitleMethod, [ + enums.AudioItemIdStreamHeadSubtitleMethod? defaultValue, +]) { + return enums.AudioItemIdStreamHeadSubtitleMethod.values.firstWhereOrNull( + (e) => e.value == audioItemIdStreamHeadSubtitleMethod) ?? + defaultValue ?? + enums.AudioItemIdStreamHeadSubtitleMethod.swaggerGeneratedUnknown; +} + +enums.AudioItemIdStreamHeadSubtitleMethod? + audioItemIdStreamHeadSubtitleMethodNullableFromJson( + Object? audioItemIdStreamHeadSubtitleMethod, [ + enums.AudioItemIdStreamHeadSubtitleMethod? defaultValue, +]) { + if (audioItemIdStreamHeadSubtitleMethod == null) { + return null; + } + return enums.AudioItemIdStreamHeadSubtitleMethod.values.firstWhereOrNull( + (e) => e.value == audioItemIdStreamHeadSubtitleMethod) ?? + defaultValue; +} + +String audioItemIdStreamHeadSubtitleMethodExplodedListToJson( + List? + audioItemIdStreamHeadSubtitleMethod) { + return audioItemIdStreamHeadSubtitleMethod?.map((e) => e.value!).join(',') ?? + ''; +} + +List audioItemIdStreamHeadSubtitleMethodListToJson( + List? + audioItemIdStreamHeadSubtitleMethod) { + if (audioItemIdStreamHeadSubtitleMethod == null) { + return []; + } + + return audioItemIdStreamHeadSubtitleMethod.map((e) => e.value!).toList(); +} + +List + audioItemIdStreamHeadSubtitleMethodListFromJson( + List? audioItemIdStreamHeadSubtitleMethod, [ + List? defaultValue, +]) { + if (audioItemIdStreamHeadSubtitleMethod == null) { + return defaultValue ?? []; + } + + return audioItemIdStreamHeadSubtitleMethod + .map((e) => audioItemIdStreamHeadSubtitleMethodFromJson(e.toString())) + .toList(); +} + +List? + audioItemIdStreamHeadSubtitleMethodNullableListFromJson( + List? audioItemIdStreamHeadSubtitleMethod, [ + List? defaultValue, +]) { + if (audioItemIdStreamHeadSubtitleMethod == null) { + return defaultValue; + } + + return audioItemIdStreamHeadSubtitleMethod + .map((e) => audioItemIdStreamHeadSubtitleMethodFromJson(e.toString())) + .toList(); +} + +String? audioItemIdStreamHeadContextNullableToJson( + enums.AudioItemIdStreamHeadContext? audioItemIdStreamHeadContext) { + return audioItemIdStreamHeadContext?.value; +} + +String? audioItemIdStreamHeadContextToJson( + enums.AudioItemIdStreamHeadContext audioItemIdStreamHeadContext) { + return audioItemIdStreamHeadContext.value; +} + +enums.AudioItemIdStreamHeadContext audioItemIdStreamHeadContextFromJson( + Object? audioItemIdStreamHeadContext, [ + enums.AudioItemIdStreamHeadContext? defaultValue, +]) { + return enums.AudioItemIdStreamHeadContext.values + .firstWhereOrNull((e) => e.value == audioItemIdStreamHeadContext) ?? + defaultValue ?? + enums.AudioItemIdStreamHeadContext.swaggerGeneratedUnknown; +} + +enums.AudioItemIdStreamHeadContext? + audioItemIdStreamHeadContextNullableFromJson( + Object? audioItemIdStreamHeadContext, [ + enums.AudioItemIdStreamHeadContext? defaultValue, +]) { + if (audioItemIdStreamHeadContext == null) { + return null; + } + return enums.AudioItemIdStreamHeadContext.values + .firstWhereOrNull((e) => e.value == audioItemIdStreamHeadContext) ?? + defaultValue; +} + +String audioItemIdStreamHeadContextExplodedListToJson( + List? audioItemIdStreamHeadContext) { + return audioItemIdStreamHeadContext?.map((e) => e.value!).join(',') ?? ''; +} + +List audioItemIdStreamHeadContextListToJson( + List? audioItemIdStreamHeadContext) { + if (audioItemIdStreamHeadContext == null) { + return []; + } + + return audioItemIdStreamHeadContext.map((e) => e.value!).toList(); +} + +List + audioItemIdStreamHeadContextListFromJson( + List? audioItemIdStreamHeadContext, [ + List? defaultValue, +]) { + if (audioItemIdStreamHeadContext == null) { + return defaultValue ?? []; + } + + return audioItemIdStreamHeadContext + .map((e) => audioItemIdStreamHeadContextFromJson(e.toString())) + .toList(); +} + +List? + audioItemIdStreamHeadContextNullableListFromJson( + List? audioItemIdStreamHeadContext, [ + List? defaultValue, +]) { + if (audioItemIdStreamHeadContext == null) { + return defaultValue; + } + + return audioItemIdStreamHeadContext + .map((e) => audioItemIdStreamHeadContextFromJson(e.toString())) + .toList(); +} + +String? audioItemIdStreamContainerGetSubtitleMethodNullableToJson( + enums.AudioItemIdStreamContainerGetSubtitleMethod? + audioItemIdStreamContainerGetSubtitleMethod) { + return audioItemIdStreamContainerGetSubtitleMethod?.value; +} + +String? audioItemIdStreamContainerGetSubtitleMethodToJson( + enums.AudioItemIdStreamContainerGetSubtitleMethod + audioItemIdStreamContainerGetSubtitleMethod) { + return audioItemIdStreamContainerGetSubtitleMethod.value; +} + +enums.AudioItemIdStreamContainerGetSubtitleMethod + audioItemIdStreamContainerGetSubtitleMethodFromJson( + Object? audioItemIdStreamContainerGetSubtitleMethod, [ + enums.AudioItemIdStreamContainerGetSubtitleMethod? defaultValue, +]) { + return enums.AudioItemIdStreamContainerGetSubtitleMethod.values + .firstWhereOrNull( + (e) => e.value == audioItemIdStreamContainerGetSubtitleMethod) ?? + defaultValue ?? + enums.AudioItemIdStreamContainerGetSubtitleMethod.swaggerGeneratedUnknown; +} + +enums.AudioItemIdStreamContainerGetSubtitleMethod? + audioItemIdStreamContainerGetSubtitleMethodNullableFromJson( + Object? audioItemIdStreamContainerGetSubtitleMethod, [ + enums.AudioItemIdStreamContainerGetSubtitleMethod? defaultValue, +]) { + if (audioItemIdStreamContainerGetSubtitleMethod == null) { + return null; + } + return enums.AudioItemIdStreamContainerGetSubtitleMethod.values + .firstWhereOrNull( + (e) => e.value == audioItemIdStreamContainerGetSubtitleMethod) ?? + defaultValue; +} + +String audioItemIdStreamContainerGetSubtitleMethodExplodedListToJson( + List? + audioItemIdStreamContainerGetSubtitleMethod) { + return audioItemIdStreamContainerGetSubtitleMethod + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List audioItemIdStreamContainerGetSubtitleMethodListToJson( + List? + audioItemIdStreamContainerGetSubtitleMethod) { + if (audioItemIdStreamContainerGetSubtitleMethod == null) { + return []; + } + + return audioItemIdStreamContainerGetSubtitleMethod + .map((e) => e.value!) + .toList(); +} + +List + audioItemIdStreamContainerGetSubtitleMethodListFromJson( + List? audioItemIdStreamContainerGetSubtitleMethod, [ + List? defaultValue, +]) { + if (audioItemIdStreamContainerGetSubtitleMethod == null) { + return defaultValue ?? []; + } + + return audioItemIdStreamContainerGetSubtitleMethod + .map((e) => + audioItemIdStreamContainerGetSubtitleMethodFromJson(e.toString())) + .toList(); +} + +List? + audioItemIdStreamContainerGetSubtitleMethodNullableListFromJson( + List? audioItemIdStreamContainerGetSubtitleMethod, [ + List? defaultValue, +]) { + if (audioItemIdStreamContainerGetSubtitleMethod == null) { + return defaultValue; + } + + return audioItemIdStreamContainerGetSubtitleMethod + .map((e) => + audioItemIdStreamContainerGetSubtitleMethodFromJson(e.toString())) + .toList(); +} + +String? audioItemIdStreamContainerGetContextNullableToJson( + enums.AudioItemIdStreamContainerGetContext? + audioItemIdStreamContainerGetContext) { + return audioItemIdStreamContainerGetContext?.value; +} + +String? audioItemIdStreamContainerGetContextToJson( + enums.AudioItemIdStreamContainerGetContext + audioItemIdStreamContainerGetContext) { + return audioItemIdStreamContainerGetContext.value; +} + +enums.AudioItemIdStreamContainerGetContext + audioItemIdStreamContainerGetContextFromJson( + Object? audioItemIdStreamContainerGetContext, [ + enums.AudioItemIdStreamContainerGetContext? defaultValue, +]) { + return enums.AudioItemIdStreamContainerGetContext.values.firstWhereOrNull( + (e) => e.value == audioItemIdStreamContainerGetContext) ?? + defaultValue ?? + enums.AudioItemIdStreamContainerGetContext.swaggerGeneratedUnknown; +} + +enums.AudioItemIdStreamContainerGetContext? + audioItemIdStreamContainerGetContextNullableFromJson( + Object? audioItemIdStreamContainerGetContext, [ + enums.AudioItemIdStreamContainerGetContext? defaultValue, +]) { + if (audioItemIdStreamContainerGetContext == null) { + return null; + } + return enums.AudioItemIdStreamContainerGetContext.values.firstWhereOrNull( + (e) => e.value == audioItemIdStreamContainerGetContext) ?? + defaultValue; +} + +String audioItemIdStreamContainerGetContextExplodedListToJson( + List? + audioItemIdStreamContainerGetContext) { + return audioItemIdStreamContainerGetContext?.map((e) => e.value!).join(',') ?? + ''; +} + +List audioItemIdStreamContainerGetContextListToJson( + List? + audioItemIdStreamContainerGetContext) { + if (audioItemIdStreamContainerGetContext == null) { + return []; + } + + return audioItemIdStreamContainerGetContext.map((e) => e.value!).toList(); +} + +List + audioItemIdStreamContainerGetContextListFromJson( + List? audioItemIdStreamContainerGetContext, [ + List? defaultValue, +]) { + if (audioItemIdStreamContainerGetContext == null) { + return defaultValue ?? []; + } + + return audioItemIdStreamContainerGetContext + .map((e) => audioItemIdStreamContainerGetContextFromJson(e.toString())) + .toList(); +} + +List? + audioItemIdStreamContainerGetContextNullableListFromJson( + List? audioItemIdStreamContainerGetContext, [ + List? defaultValue, +]) { + if (audioItemIdStreamContainerGetContext == null) { + return defaultValue; + } + + return audioItemIdStreamContainerGetContext + .map((e) => audioItemIdStreamContainerGetContextFromJson(e.toString())) + .toList(); +} + +String? audioItemIdStreamContainerHeadSubtitleMethodNullableToJson( + enums.AudioItemIdStreamContainerHeadSubtitleMethod? + audioItemIdStreamContainerHeadSubtitleMethod) { + return audioItemIdStreamContainerHeadSubtitleMethod?.value; +} + +String? audioItemIdStreamContainerHeadSubtitleMethodToJson( + enums.AudioItemIdStreamContainerHeadSubtitleMethod + audioItemIdStreamContainerHeadSubtitleMethod) { + return audioItemIdStreamContainerHeadSubtitleMethod.value; +} + +enums.AudioItemIdStreamContainerHeadSubtitleMethod + audioItemIdStreamContainerHeadSubtitleMethodFromJson( + Object? audioItemIdStreamContainerHeadSubtitleMethod, [ + enums.AudioItemIdStreamContainerHeadSubtitleMethod? defaultValue, +]) { + return enums.AudioItemIdStreamContainerHeadSubtitleMethod.values + .firstWhereOrNull( + (e) => e.value == audioItemIdStreamContainerHeadSubtitleMethod) ?? + defaultValue ?? + enums + .AudioItemIdStreamContainerHeadSubtitleMethod.swaggerGeneratedUnknown; +} + +enums.AudioItemIdStreamContainerHeadSubtitleMethod? + audioItemIdStreamContainerHeadSubtitleMethodNullableFromJson( + Object? audioItemIdStreamContainerHeadSubtitleMethod, [ + enums.AudioItemIdStreamContainerHeadSubtitleMethod? defaultValue, +]) { + if (audioItemIdStreamContainerHeadSubtitleMethod == null) { + return null; + } + return enums.AudioItemIdStreamContainerHeadSubtitleMethod.values + .firstWhereOrNull( + (e) => e.value == audioItemIdStreamContainerHeadSubtitleMethod) ?? + defaultValue; +} + +String audioItemIdStreamContainerHeadSubtitleMethodExplodedListToJson( + List? + audioItemIdStreamContainerHeadSubtitleMethod) { + return audioItemIdStreamContainerHeadSubtitleMethod + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List audioItemIdStreamContainerHeadSubtitleMethodListToJson( + List? + audioItemIdStreamContainerHeadSubtitleMethod) { + if (audioItemIdStreamContainerHeadSubtitleMethod == null) { + return []; + } + + return audioItemIdStreamContainerHeadSubtitleMethod + .map((e) => e.value!) + .toList(); +} + +List + audioItemIdStreamContainerHeadSubtitleMethodListFromJson( + List? audioItemIdStreamContainerHeadSubtitleMethod, [ + List? defaultValue, +]) { + if (audioItemIdStreamContainerHeadSubtitleMethod == null) { + return defaultValue ?? []; + } + + return audioItemIdStreamContainerHeadSubtitleMethod + .map((e) => + audioItemIdStreamContainerHeadSubtitleMethodFromJson(e.toString())) + .toList(); +} + +List? + audioItemIdStreamContainerHeadSubtitleMethodNullableListFromJson( + List? audioItemIdStreamContainerHeadSubtitleMethod, [ + List? defaultValue, +]) { + if (audioItemIdStreamContainerHeadSubtitleMethod == null) { + return defaultValue; + } + + return audioItemIdStreamContainerHeadSubtitleMethod + .map((e) => + audioItemIdStreamContainerHeadSubtitleMethodFromJson(e.toString())) + .toList(); +} + +String? audioItemIdStreamContainerHeadContextNullableToJson( + enums.AudioItemIdStreamContainerHeadContext? + audioItemIdStreamContainerHeadContext) { + return audioItemIdStreamContainerHeadContext?.value; +} + +String? audioItemIdStreamContainerHeadContextToJson( + enums.AudioItemIdStreamContainerHeadContext + audioItemIdStreamContainerHeadContext) { + return audioItemIdStreamContainerHeadContext.value; +} + +enums.AudioItemIdStreamContainerHeadContext + audioItemIdStreamContainerHeadContextFromJson( + Object? audioItemIdStreamContainerHeadContext, [ + enums.AudioItemIdStreamContainerHeadContext? defaultValue, +]) { + return enums.AudioItemIdStreamContainerHeadContext.values.firstWhereOrNull( + (e) => e.value == audioItemIdStreamContainerHeadContext) ?? + defaultValue ?? + enums.AudioItemIdStreamContainerHeadContext.swaggerGeneratedUnknown; +} + +enums.AudioItemIdStreamContainerHeadContext? + audioItemIdStreamContainerHeadContextNullableFromJson( + Object? audioItemIdStreamContainerHeadContext, [ + enums.AudioItemIdStreamContainerHeadContext? defaultValue, +]) { + if (audioItemIdStreamContainerHeadContext == null) { + return null; + } + return enums.AudioItemIdStreamContainerHeadContext.values.firstWhereOrNull( + (e) => e.value == audioItemIdStreamContainerHeadContext) ?? + defaultValue; +} + +String audioItemIdStreamContainerHeadContextExplodedListToJson( + List? + audioItemIdStreamContainerHeadContext) { + return audioItemIdStreamContainerHeadContext + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List audioItemIdStreamContainerHeadContextListToJson( + List? + audioItemIdStreamContainerHeadContext) { + if (audioItemIdStreamContainerHeadContext == null) { + return []; + } + + return audioItemIdStreamContainerHeadContext.map((e) => e.value!).toList(); +} + +List + audioItemIdStreamContainerHeadContextListFromJson( + List? audioItemIdStreamContainerHeadContext, [ + List? defaultValue, +]) { + if (audioItemIdStreamContainerHeadContext == null) { + return defaultValue ?? []; + } + + return audioItemIdStreamContainerHeadContext + .map((e) => audioItemIdStreamContainerHeadContextFromJson(e.toString())) + .toList(); +} + +List? + audioItemIdStreamContainerHeadContextNullableListFromJson( + List? audioItemIdStreamContainerHeadContext, [ + List? defaultValue, +]) { + if (audioItemIdStreamContainerHeadContext == null) { + return defaultValue; + } + + return audioItemIdStreamContainerHeadContext + .map((e) => audioItemIdStreamContainerHeadContextFromJson(e.toString())) + .toList(); +} + +String? + audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethodNullableToJson( + enums.AudioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod? + audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod) { + return audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod?.value; +} + +String? audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethodToJson( + enums.AudioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod + audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod) { + return audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod.value; +} + +enums.AudioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod + audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethodFromJson( + Object? audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod, [ + enums.AudioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod? + defaultValue, +]) { + return enums + .AudioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod.values + .firstWhereOrNull((e) => + e.value == + audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod) ?? + defaultValue ?? + enums.AudioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod + .swaggerGeneratedUnknown; +} + +enums.AudioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod? + audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethodNullableFromJson( + Object? audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod, [ + enums.AudioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod? + defaultValue, +]) { + if (audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod == null) { + return null; + } + return enums + .AudioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod.values + .firstWhereOrNull((e) => + e.value == + audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod) ?? + defaultValue; +} + +String + audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethodExplodedListToJson( + List< + enums + .AudioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod>? + audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod) { + return audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List + audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethodListToJson( + List< + enums + .AudioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod>? + audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod) { + if (audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod == null) { + return []; + } + + return audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod + .map((e) => e.value!) + .toList(); +} + +List + audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethodListFromJson( + List? audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod, [ + List? + defaultValue, +]) { + if (audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod == null) { + return defaultValue ?? []; + } + + return audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod + .map((e) => + audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethodFromJson( + e.toString())) + .toList(); +} + +List? + audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethodNullableListFromJson( + List? audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod, [ + List? + defaultValue, +]) { + if (audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod == null) { + return defaultValue; + } + + return audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod + .map((e) => + audioItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethodFromJson( + e.toString())) + .toList(); +} + +String? audioItemIdHls1PlaylistIdSegmentIdContainerGetContextNullableToJson( + enums.AudioItemIdHls1PlaylistIdSegmentIdContainerGetContext? + audioItemIdHls1PlaylistIdSegmentIdContainerGetContext) { + return audioItemIdHls1PlaylistIdSegmentIdContainerGetContext?.value; +} + +String? audioItemIdHls1PlaylistIdSegmentIdContainerGetContextToJson( + enums.AudioItemIdHls1PlaylistIdSegmentIdContainerGetContext + audioItemIdHls1PlaylistIdSegmentIdContainerGetContext) { + return audioItemIdHls1PlaylistIdSegmentIdContainerGetContext.value; +} + +enums.AudioItemIdHls1PlaylistIdSegmentIdContainerGetContext + audioItemIdHls1PlaylistIdSegmentIdContainerGetContextFromJson( + Object? audioItemIdHls1PlaylistIdSegmentIdContainerGetContext, [ + enums.AudioItemIdHls1PlaylistIdSegmentIdContainerGetContext? defaultValue, +]) { + return enums.AudioItemIdHls1PlaylistIdSegmentIdContainerGetContext.values + .firstWhereOrNull((e) => + e.value == + audioItemIdHls1PlaylistIdSegmentIdContainerGetContext) ?? + defaultValue ?? + enums.AudioItemIdHls1PlaylistIdSegmentIdContainerGetContext + .swaggerGeneratedUnknown; +} + +enums.AudioItemIdHls1PlaylistIdSegmentIdContainerGetContext? + audioItemIdHls1PlaylistIdSegmentIdContainerGetContextNullableFromJson( + Object? audioItemIdHls1PlaylistIdSegmentIdContainerGetContext, [ + enums.AudioItemIdHls1PlaylistIdSegmentIdContainerGetContext? defaultValue, +]) { + if (audioItemIdHls1PlaylistIdSegmentIdContainerGetContext == null) { + return null; + } + return enums.AudioItemIdHls1PlaylistIdSegmentIdContainerGetContext.values + .firstWhereOrNull((e) => + e.value == + audioItemIdHls1PlaylistIdSegmentIdContainerGetContext) ?? + defaultValue; +} + +String audioItemIdHls1PlaylistIdSegmentIdContainerGetContextExplodedListToJson( + List? + audioItemIdHls1PlaylistIdSegmentIdContainerGetContext) { + return audioItemIdHls1PlaylistIdSegmentIdContainerGetContext + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List audioItemIdHls1PlaylistIdSegmentIdContainerGetContextListToJson( + List? + audioItemIdHls1PlaylistIdSegmentIdContainerGetContext) { + if (audioItemIdHls1PlaylistIdSegmentIdContainerGetContext == null) { + return []; + } + + return audioItemIdHls1PlaylistIdSegmentIdContainerGetContext + .map((e) => e.value!) + .toList(); +} + +List + audioItemIdHls1PlaylistIdSegmentIdContainerGetContextListFromJson( + List? audioItemIdHls1PlaylistIdSegmentIdContainerGetContext, [ + List? + defaultValue, +]) { + if (audioItemIdHls1PlaylistIdSegmentIdContainerGetContext == null) { + return defaultValue ?? []; + } + + return audioItemIdHls1PlaylistIdSegmentIdContainerGetContext + .map((e) => audioItemIdHls1PlaylistIdSegmentIdContainerGetContextFromJson( + e.toString())) + .toList(); +} + +List? + audioItemIdHls1PlaylistIdSegmentIdContainerGetContextNullableListFromJson( + List? audioItemIdHls1PlaylistIdSegmentIdContainerGetContext, [ + List? + defaultValue, +]) { + if (audioItemIdHls1PlaylistIdSegmentIdContainerGetContext == null) { + return defaultValue; + } + + return audioItemIdHls1PlaylistIdSegmentIdContainerGetContext + .map((e) => audioItemIdHls1PlaylistIdSegmentIdContainerGetContextFromJson( + e.toString())) + .toList(); +} + +String? audioItemIdMainM3u8GetSubtitleMethodNullableToJson( + enums.AudioItemIdMainM3u8GetSubtitleMethod? + audioItemIdMainM3u8GetSubtitleMethod) { + return audioItemIdMainM3u8GetSubtitleMethod?.value; +} + +String? audioItemIdMainM3u8GetSubtitleMethodToJson( + enums.AudioItemIdMainM3u8GetSubtitleMethod + audioItemIdMainM3u8GetSubtitleMethod) { + return audioItemIdMainM3u8GetSubtitleMethod.value; +} + +enums.AudioItemIdMainM3u8GetSubtitleMethod + audioItemIdMainM3u8GetSubtitleMethodFromJson( + Object? audioItemIdMainM3u8GetSubtitleMethod, [ + enums.AudioItemIdMainM3u8GetSubtitleMethod? defaultValue, +]) { + return enums.AudioItemIdMainM3u8GetSubtitleMethod.values.firstWhereOrNull( + (e) => e.value == audioItemIdMainM3u8GetSubtitleMethod) ?? + defaultValue ?? + enums.AudioItemIdMainM3u8GetSubtitleMethod.swaggerGeneratedUnknown; +} + +enums.AudioItemIdMainM3u8GetSubtitleMethod? + audioItemIdMainM3u8GetSubtitleMethodNullableFromJson( + Object? audioItemIdMainM3u8GetSubtitleMethod, [ + enums.AudioItemIdMainM3u8GetSubtitleMethod? defaultValue, +]) { + if (audioItemIdMainM3u8GetSubtitleMethod == null) { + return null; + } + return enums.AudioItemIdMainM3u8GetSubtitleMethod.values.firstWhereOrNull( + (e) => e.value == audioItemIdMainM3u8GetSubtitleMethod) ?? + defaultValue; +} + +String audioItemIdMainM3u8GetSubtitleMethodExplodedListToJson( + List? + audioItemIdMainM3u8GetSubtitleMethod) { + return audioItemIdMainM3u8GetSubtitleMethod?.map((e) => e.value!).join(',') ?? + ''; +} + +List audioItemIdMainM3u8GetSubtitleMethodListToJson( + List? + audioItemIdMainM3u8GetSubtitleMethod) { + if (audioItemIdMainM3u8GetSubtitleMethod == null) { + return []; + } + + return audioItemIdMainM3u8GetSubtitleMethod.map((e) => e.value!).toList(); +} + +List + audioItemIdMainM3u8GetSubtitleMethodListFromJson( + List? audioItemIdMainM3u8GetSubtitleMethod, [ + List? defaultValue, +]) { + if (audioItemIdMainM3u8GetSubtitleMethod == null) { + return defaultValue ?? []; + } + + return audioItemIdMainM3u8GetSubtitleMethod + .map((e) => audioItemIdMainM3u8GetSubtitleMethodFromJson(e.toString())) + .toList(); +} + +List? + audioItemIdMainM3u8GetSubtitleMethodNullableListFromJson( + List? audioItemIdMainM3u8GetSubtitleMethod, [ + List? defaultValue, +]) { + if (audioItemIdMainM3u8GetSubtitleMethod == null) { + return defaultValue; + } + + return audioItemIdMainM3u8GetSubtitleMethod + .map((e) => audioItemIdMainM3u8GetSubtitleMethodFromJson(e.toString())) + .toList(); +} + +String? audioItemIdMainM3u8GetContextNullableToJson( + enums.AudioItemIdMainM3u8GetContext? audioItemIdMainM3u8GetContext) { + return audioItemIdMainM3u8GetContext?.value; +} + +String? audioItemIdMainM3u8GetContextToJson( + enums.AudioItemIdMainM3u8GetContext audioItemIdMainM3u8GetContext) { + return audioItemIdMainM3u8GetContext.value; +} + +enums.AudioItemIdMainM3u8GetContext audioItemIdMainM3u8GetContextFromJson( + Object? audioItemIdMainM3u8GetContext, [ + enums.AudioItemIdMainM3u8GetContext? defaultValue, +]) { + return enums.AudioItemIdMainM3u8GetContext.values + .firstWhereOrNull((e) => e.value == audioItemIdMainM3u8GetContext) ?? + defaultValue ?? + enums.AudioItemIdMainM3u8GetContext.swaggerGeneratedUnknown; +} + +enums.AudioItemIdMainM3u8GetContext? + audioItemIdMainM3u8GetContextNullableFromJson( + Object? audioItemIdMainM3u8GetContext, [ + enums.AudioItemIdMainM3u8GetContext? defaultValue, +]) { + if (audioItemIdMainM3u8GetContext == null) { + return null; + } + return enums.AudioItemIdMainM3u8GetContext.values + .firstWhereOrNull((e) => e.value == audioItemIdMainM3u8GetContext) ?? + defaultValue; +} + +String audioItemIdMainM3u8GetContextExplodedListToJson( + List? audioItemIdMainM3u8GetContext) { + return audioItemIdMainM3u8GetContext?.map((e) => e.value!).join(',') ?? ''; +} + +List audioItemIdMainM3u8GetContextListToJson( + List? audioItemIdMainM3u8GetContext) { + if (audioItemIdMainM3u8GetContext == null) { + return []; + } + + return audioItemIdMainM3u8GetContext.map((e) => e.value!).toList(); +} + +List + audioItemIdMainM3u8GetContextListFromJson( + List? audioItemIdMainM3u8GetContext, [ + List? defaultValue, +]) { + if (audioItemIdMainM3u8GetContext == null) { + return defaultValue ?? []; + } + + return audioItemIdMainM3u8GetContext + .map((e) => audioItemIdMainM3u8GetContextFromJson(e.toString())) + .toList(); +} + +List? + audioItemIdMainM3u8GetContextNullableListFromJson( + List? audioItemIdMainM3u8GetContext, [ + List? defaultValue, +]) { + if (audioItemIdMainM3u8GetContext == null) { + return defaultValue; + } + + return audioItemIdMainM3u8GetContext + .map((e) => audioItemIdMainM3u8GetContextFromJson(e.toString())) + .toList(); +} + +String? audioItemIdMasterM3u8GetSubtitleMethodNullableToJson( + enums.AudioItemIdMasterM3u8GetSubtitleMethod? + audioItemIdMasterM3u8GetSubtitleMethod) { + return audioItemIdMasterM3u8GetSubtitleMethod?.value; +} + +String? audioItemIdMasterM3u8GetSubtitleMethodToJson( + enums.AudioItemIdMasterM3u8GetSubtitleMethod + audioItemIdMasterM3u8GetSubtitleMethod) { + return audioItemIdMasterM3u8GetSubtitleMethod.value; +} + +enums.AudioItemIdMasterM3u8GetSubtitleMethod + audioItemIdMasterM3u8GetSubtitleMethodFromJson( + Object? audioItemIdMasterM3u8GetSubtitleMethod, [ + enums.AudioItemIdMasterM3u8GetSubtitleMethod? defaultValue, +]) { + return enums.AudioItemIdMasterM3u8GetSubtitleMethod.values.firstWhereOrNull( + (e) => e.value == audioItemIdMasterM3u8GetSubtitleMethod) ?? + defaultValue ?? + enums.AudioItemIdMasterM3u8GetSubtitleMethod.swaggerGeneratedUnknown; +} + +enums.AudioItemIdMasterM3u8GetSubtitleMethod? + audioItemIdMasterM3u8GetSubtitleMethodNullableFromJson( + Object? audioItemIdMasterM3u8GetSubtitleMethod, [ + enums.AudioItemIdMasterM3u8GetSubtitleMethod? defaultValue, +]) { + if (audioItemIdMasterM3u8GetSubtitleMethod == null) { + return null; + } + return enums.AudioItemIdMasterM3u8GetSubtitleMethod.values.firstWhereOrNull( + (e) => e.value == audioItemIdMasterM3u8GetSubtitleMethod) ?? + defaultValue; +} + +String audioItemIdMasterM3u8GetSubtitleMethodExplodedListToJson( + List? + audioItemIdMasterM3u8GetSubtitleMethod) { + return audioItemIdMasterM3u8GetSubtitleMethod + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List audioItemIdMasterM3u8GetSubtitleMethodListToJson( + List? + audioItemIdMasterM3u8GetSubtitleMethod) { + if (audioItemIdMasterM3u8GetSubtitleMethod == null) { + return []; + } + + return audioItemIdMasterM3u8GetSubtitleMethod.map((e) => e.value!).toList(); +} + +List + audioItemIdMasterM3u8GetSubtitleMethodListFromJson( + List? audioItemIdMasterM3u8GetSubtitleMethod, [ + List? defaultValue, +]) { + if (audioItemIdMasterM3u8GetSubtitleMethod == null) { + return defaultValue ?? []; + } + + return audioItemIdMasterM3u8GetSubtitleMethod + .map((e) => audioItemIdMasterM3u8GetSubtitleMethodFromJson(e.toString())) + .toList(); +} + +List? + audioItemIdMasterM3u8GetSubtitleMethodNullableListFromJson( + List? audioItemIdMasterM3u8GetSubtitleMethod, [ + List? defaultValue, +]) { + if (audioItemIdMasterM3u8GetSubtitleMethod == null) { + return defaultValue; + } + + return audioItemIdMasterM3u8GetSubtitleMethod + .map((e) => audioItemIdMasterM3u8GetSubtitleMethodFromJson(e.toString())) + .toList(); +} + +String? audioItemIdMasterM3u8GetContextNullableToJson( + enums.AudioItemIdMasterM3u8GetContext? audioItemIdMasterM3u8GetContext) { + return audioItemIdMasterM3u8GetContext?.value; +} + +String? audioItemIdMasterM3u8GetContextToJson( + enums.AudioItemIdMasterM3u8GetContext audioItemIdMasterM3u8GetContext) { + return audioItemIdMasterM3u8GetContext.value; +} + +enums.AudioItemIdMasterM3u8GetContext audioItemIdMasterM3u8GetContextFromJson( + Object? audioItemIdMasterM3u8GetContext, [ + enums.AudioItemIdMasterM3u8GetContext? defaultValue, +]) { + return enums.AudioItemIdMasterM3u8GetContext.values.firstWhereOrNull( + (e) => e.value == audioItemIdMasterM3u8GetContext) ?? + defaultValue ?? + enums.AudioItemIdMasterM3u8GetContext.swaggerGeneratedUnknown; +} + +enums.AudioItemIdMasterM3u8GetContext? + audioItemIdMasterM3u8GetContextNullableFromJson( + Object? audioItemIdMasterM3u8GetContext, [ + enums.AudioItemIdMasterM3u8GetContext? defaultValue, +]) { + if (audioItemIdMasterM3u8GetContext == null) { + return null; + } + return enums.AudioItemIdMasterM3u8GetContext.values.firstWhereOrNull( + (e) => e.value == audioItemIdMasterM3u8GetContext) ?? + defaultValue; +} + +String audioItemIdMasterM3u8GetContextExplodedListToJson( + List? + audioItemIdMasterM3u8GetContext) { + return audioItemIdMasterM3u8GetContext?.map((e) => e.value!).join(',') ?? ''; +} + +List audioItemIdMasterM3u8GetContextListToJson( + List? + audioItemIdMasterM3u8GetContext) { + if (audioItemIdMasterM3u8GetContext == null) { + return []; + } + + return audioItemIdMasterM3u8GetContext.map((e) => e.value!).toList(); +} + +List + audioItemIdMasterM3u8GetContextListFromJson( + List? audioItemIdMasterM3u8GetContext, [ + List? defaultValue, +]) { + if (audioItemIdMasterM3u8GetContext == null) { + return defaultValue ?? []; + } + + return audioItemIdMasterM3u8GetContext + .map((e) => audioItemIdMasterM3u8GetContextFromJson(e.toString())) + .toList(); +} + +List? + audioItemIdMasterM3u8GetContextNullableListFromJson( + List? audioItemIdMasterM3u8GetContext, [ + List? defaultValue, +]) { + if (audioItemIdMasterM3u8GetContext == null) { + return defaultValue; + } + + return audioItemIdMasterM3u8GetContext + .map((e) => audioItemIdMasterM3u8GetContextFromJson(e.toString())) + .toList(); +} + +String? audioItemIdMasterM3u8HeadSubtitleMethodNullableToJson( + enums.AudioItemIdMasterM3u8HeadSubtitleMethod? + audioItemIdMasterM3u8HeadSubtitleMethod) { + return audioItemIdMasterM3u8HeadSubtitleMethod?.value; +} + +String? audioItemIdMasterM3u8HeadSubtitleMethodToJson( + enums.AudioItemIdMasterM3u8HeadSubtitleMethod + audioItemIdMasterM3u8HeadSubtitleMethod) { + return audioItemIdMasterM3u8HeadSubtitleMethod.value; +} + +enums.AudioItemIdMasterM3u8HeadSubtitleMethod + audioItemIdMasterM3u8HeadSubtitleMethodFromJson( + Object? audioItemIdMasterM3u8HeadSubtitleMethod, [ + enums.AudioItemIdMasterM3u8HeadSubtitleMethod? defaultValue, +]) { + return enums.AudioItemIdMasterM3u8HeadSubtitleMethod.values.firstWhereOrNull( + (e) => e.value == audioItemIdMasterM3u8HeadSubtitleMethod) ?? + defaultValue ?? + enums.AudioItemIdMasterM3u8HeadSubtitleMethod.swaggerGeneratedUnknown; +} + +enums.AudioItemIdMasterM3u8HeadSubtitleMethod? + audioItemIdMasterM3u8HeadSubtitleMethodNullableFromJson( + Object? audioItemIdMasterM3u8HeadSubtitleMethod, [ + enums.AudioItemIdMasterM3u8HeadSubtitleMethod? defaultValue, +]) { + if (audioItemIdMasterM3u8HeadSubtitleMethod == null) { + return null; + } + return enums.AudioItemIdMasterM3u8HeadSubtitleMethod.values.firstWhereOrNull( + (e) => e.value == audioItemIdMasterM3u8HeadSubtitleMethod) ?? + defaultValue; +} + +String audioItemIdMasterM3u8HeadSubtitleMethodExplodedListToJson( + List? + audioItemIdMasterM3u8HeadSubtitleMethod) { + return audioItemIdMasterM3u8HeadSubtitleMethod + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List audioItemIdMasterM3u8HeadSubtitleMethodListToJson( + List? + audioItemIdMasterM3u8HeadSubtitleMethod) { + if (audioItemIdMasterM3u8HeadSubtitleMethod == null) { + return []; + } + + return audioItemIdMasterM3u8HeadSubtitleMethod.map((e) => e.value!).toList(); +} + +List + audioItemIdMasterM3u8HeadSubtitleMethodListFromJson( + List? audioItemIdMasterM3u8HeadSubtitleMethod, [ + List? defaultValue, +]) { + if (audioItemIdMasterM3u8HeadSubtitleMethod == null) { + return defaultValue ?? []; + } + + return audioItemIdMasterM3u8HeadSubtitleMethod + .map((e) => audioItemIdMasterM3u8HeadSubtitleMethodFromJson(e.toString())) + .toList(); +} + +List? + audioItemIdMasterM3u8HeadSubtitleMethodNullableListFromJson( + List? audioItemIdMasterM3u8HeadSubtitleMethod, [ + List? defaultValue, +]) { + if (audioItemIdMasterM3u8HeadSubtitleMethod == null) { + return defaultValue; + } + + return audioItemIdMasterM3u8HeadSubtitleMethod + .map((e) => audioItemIdMasterM3u8HeadSubtitleMethodFromJson(e.toString())) + .toList(); +} + +String? audioItemIdMasterM3u8HeadContextNullableToJson( + enums.AudioItemIdMasterM3u8HeadContext? audioItemIdMasterM3u8HeadContext) { + return audioItemIdMasterM3u8HeadContext?.value; +} + +String? audioItemIdMasterM3u8HeadContextToJson( + enums.AudioItemIdMasterM3u8HeadContext audioItemIdMasterM3u8HeadContext) { + return audioItemIdMasterM3u8HeadContext.value; +} + +enums.AudioItemIdMasterM3u8HeadContext audioItemIdMasterM3u8HeadContextFromJson( + Object? audioItemIdMasterM3u8HeadContext, [ + enums.AudioItemIdMasterM3u8HeadContext? defaultValue, +]) { + return enums.AudioItemIdMasterM3u8HeadContext.values.firstWhereOrNull( + (e) => e.value == audioItemIdMasterM3u8HeadContext) ?? + defaultValue ?? + enums.AudioItemIdMasterM3u8HeadContext.swaggerGeneratedUnknown; +} + +enums.AudioItemIdMasterM3u8HeadContext? + audioItemIdMasterM3u8HeadContextNullableFromJson( + Object? audioItemIdMasterM3u8HeadContext, [ + enums.AudioItemIdMasterM3u8HeadContext? defaultValue, +]) { + if (audioItemIdMasterM3u8HeadContext == null) { + return null; + } + return enums.AudioItemIdMasterM3u8HeadContext.values.firstWhereOrNull( + (e) => e.value == audioItemIdMasterM3u8HeadContext) ?? + defaultValue; +} + +String audioItemIdMasterM3u8HeadContextExplodedListToJson( + List? + audioItemIdMasterM3u8HeadContext) { + return audioItemIdMasterM3u8HeadContext?.map((e) => e.value!).join(',') ?? ''; +} + +List audioItemIdMasterM3u8HeadContextListToJson( + List? + audioItemIdMasterM3u8HeadContext) { + if (audioItemIdMasterM3u8HeadContext == null) { + return []; + } + + return audioItemIdMasterM3u8HeadContext.map((e) => e.value!).toList(); +} + +List + audioItemIdMasterM3u8HeadContextListFromJson( + List? audioItemIdMasterM3u8HeadContext, [ + List? defaultValue, +]) { + if (audioItemIdMasterM3u8HeadContext == null) { + return defaultValue ?? []; + } + + return audioItemIdMasterM3u8HeadContext + .map((e) => audioItemIdMasterM3u8HeadContextFromJson(e.toString())) + .toList(); +} + +List? + audioItemIdMasterM3u8HeadContextNullableListFromJson( + List? audioItemIdMasterM3u8HeadContext, [ + List? defaultValue, +]) { + if (audioItemIdMasterM3u8HeadContext == null) { + return defaultValue; + } + + return audioItemIdMasterM3u8HeadContext + .map((e) => audioItemIdMasterM3u8HeadContextFromJson(e.toString())) + .toList(); +} + +String? + videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethodNullableToJson( + enums.VideosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod? + videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod) { + return videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod?.value; +} + +String? videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethodToJson( + enums.VideosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod + videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod) { + return videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod.value; +} + +enums.VideosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod + videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethodFromJson( + Object? videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod, [ + enums.VideosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod? + defaultValue, +]) { + return enums + .VideosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod.values + .firstWhereOrNull((e) => + e.value == + videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod) ?? + defaultValue ?? + enums.VideosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod + .swaggerGeneratedUnknown; +} + +enums.VideosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod? + videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethodNullableFromJson( + Object? videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod, [ + enums.VideosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod? + defaultValue, +]) { + if (videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod == null) { + return null; + } + return enums + .VideosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod.values + .firstWhereOrNull((e) => + e.value == + videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod) ?? + defaultValue; +} + +String + videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethodExplodedListToJson( + List< + enums + .VideosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod>? + videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod) { + return videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List + videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethodListToJson( + List< + enums + .VideosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod>? + videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod) { + if (videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod == null) { + return []; + } + + return videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod + .map((e) => e.value!) + .toList(); +} + +List + videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethodListFromJson( + List? videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod, [ + List? + defaultValue, +]) { + if (videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod == null) { + return defaultValue ?? []; + } + + return videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod + .map((e) => + videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethodFromJson( + e.toString())) + .toList(); +} + +List? + videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethodNullableListFromJson( + List? videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod, [ + List? + defaultValue, +]) { + if (videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod == null) { + return defaultValue; + } + + return videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethod + .map((e) => + videosItemIdHls1PlaylistIdSegmentIdContainerGetSubtitleMethodFromJson( + e.toString())) + .toList(); +} + +String? videosItemIdHls1PlaylistIdSegmentIdContainerGetContextNullableToJson( + enums.VideosItemIdHls1PlaylistIdSegmentIdContainerGetContext? + videosItemIdHls1PlaylistIdSegmentIdContainerGetContext) { + return videosItemIdHls1PlaylistIdSegmentIdContainerGetContext?.value; +} + +String? videosItemIdHls1PlaylistIdSegmentIdContainerGetContextToJson( + enums.VideosItemIdHls1PlaylistIdSegmentIdContainerGetContext + videosItemIdHls1PlaylistIdSegmentIdContainerGetContext) { + return videosItemIdHls1PlaylistIdSegmentIdContainerGetContext.value; +} + +enums.VideosItemIdHls1PlaylistIdSegmentIdContainerGetContext + videosItemIdHls1PlaylistIdSegmentIdContainerGetContextFromJson( + Object? videosItemIdHls1PlaylistIdSegmentIdContainerGetContext, [ + enums.VideosItemIdHls1PlaylistIdSegmentIdContainerGetContext? defaultValue, +]) { + return enums.VideosItemIdHls1PlaylistIdSegmentIdContainerGetContext.values + .firstWhereOrNull((e) => + e.value == + videosItemIdHls1PlaylistIdSegmentIdContainerGetContext) ?? + defaultValue ?? + enums.VideosItemIdHls1PlaylistIdSegmentIdContainerGetContext + .swaggerGeneratedUnknown; +} + +enums.VideosItemIdHls1PlaylistIdSegmentIdContainerGetContext? + videosItemIdHls1PlaylistIdSegmentIdContainerGetContextNullableFromJson( + Object? videosItemIdHls1PlaylistIdSegmentIdContainerGetContext, [ + enums.VideosItemIdHls1PlaylistIdSegmentIdContainerGetContext? defaultValue, +]) { + if (videosItemIdHls1PlaylistIdSegmentIdContainerGetContext == null) { + return null; + } + return enums.VideosItemIdHls1PlaylistIdSegmentIdContainerGetContext.values + .firstWhereOrNull((e) => + e.value == + videosItemIdHls1PlaylistIdSegmentIdContainerGetContext) ?? + defaultValue; +} + +String videosItemIdHls1PlaylistIdSegmentIdContainerGetContextExplodedListToJson( + List? + videosItemIdHls1PlaylistIdSegmentIdContainerGetContext) { + return videosItemIdHls1PlaylistIdSegmentIdContainerGetContext + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List videosItemIdHls1PlaylistIdSegmentIdContainerGetContextListToJson( + List? + videosItemIdHls1PlaylistIdSegmentIdContainerGetContext) { + if (videosItemIdHls1PlaylistIdSegmentIdContainerGetContext == null) { + return []; + } + + return videosItemIdHls1PlaylistIdSegmentIdContainerGetContext + .map((e) => e.value!) + .toList(); +} + +List + videosItemIdHls1PlaylistIdSegmentIdContainerGetContextListFromJson( + List? videosItemIdHls1PlaylistIdSegmentIdContainerGetContext, [ + List? + defaultValue, +]) { + if (videosItemIdHls1PlaylistIdSegmentIdContainerGetContext == null) { + return defaultValue ?? []; + } + + return videosItemIdHls1PlaylistIdSegmentIdContainerGetContext + .map((e) => + videosItemIdHls1PlaylistIdSegmentIdContainerGetContextFromJson( + e.toString())) + .toList(); +} + +List? + videosItemIdHls1PlaylistIdSegmentIdContainerGetContextNullableListFromJson( + List? videosItemIdHls1PlaylistIdSegmentIdContainerGetContext, [ + List? + defaultValue, +]) { + if (videosItemIdHls1PlaylistIdSegmentIdContainerGetContext == null) { + return defaultValue; + } + + return videosItemIdHls1PlaylistIdSegmentIdContainerGetContext + .map((e) => + videosItemIdHls1PlaylistIdSegmentIdContainerGetContextFromJson( + e.toString())) + .toList(); +} + +String? videosItemIdLiveM3u8GetSubtitleMethodNullableToJson( + enums.VideosItemIdLiveM3u8GetSubtitleMethod? + videosItemIdLiveM3u8GetSubtitleMethod) { + return videosItemIdLiveM3u8GetSubtitleMethod?.value; +} + +String? videosItemIdLiveM3u8GetSubtitleMethodToJson( + enums.VideosItemIdLiveM3u8GetSubtitleMethod + videosItemIdLiveM3u8GetSubtitleMethod) { + return videosItemIdLiveM3u8GetSubtitleMethod.value; +} + +enums.VideosItemIdLiveM3u8GetSubtitleMethod + videosItemIdLiveM3u8GetSubtitleMethodFromJson( + Object? videosItemIdLiveM3u8GetSubtitleMethod, [ + enums.VideosItemIdLiveM3u8GetSubtitleMethod? defaultValue, +]) { + return enums.VideosItemIdLiveM3u8GetSubtitleMethod.values.firstWhereOrNull( + (e) => e.value == videosItemIdLiveM3u8GetSubtitleMethod) ?? + defaultValue ?? + enums.VideosItemIdLiveM3u8GetSubtitleMethod.swaggerGeneratedUnknown; +} + +enums.VideosItemIdLiveM3u8GetSubtitleMethod? + videosItemIdLiveM3u8GetSubtitleMethodNullableFromJson( + Object? videosItemIdLiveM3u8GetSubtitleMethod, [ + enums.VideosItemIdLiveM3u8GetSubtitleMethod? defaultValue, +]) { + if (videosItemIdLiveM3u8GetSubtitleMethod == null) { + return null; + } + return enums.VideosItemIdLiveM3u8GetSubtitleMethod.values.firstWhereOrNull( + (e) => e.value == videosItemIdLiveM3u8GetSubtitleMethod) ?? + defaultValue; +} + +String videosItemIdLiveM3u8GetSubtitleMethodExplodedListToJson( + List? + videosItemIdLiveM3u8GetSubtitleMethod) { + return videosItemIdLiveM3u8GetSubtitleMethod + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List videosItemIdLiveM3u8GetSubtitleMethodListToJson( + List? + videosItemIdLiveM3u8GetSubtitleMethod) { + if (videosItemIdLiveM3u8GetSubtitleMethod == null) { + return []; + } + + return videosItemIdLiveM3u8GetSubtitleMethod.map((e) => e.value!).toList(); +} + +List + videosItemIdLiveM3u8GetSubtitleMethodListFromJson( + List? videosItemIdLiveM3u8GetSubtitleMethod, [ + List? defaultValue, +]) { + if (videosItemIdLiveM3u8GetSubtitleMethod == null) { + return defaultValue ?? []; + } + + return videosItemIdLiveM3u8GetSubtitleMethod + .map((e) => videosItemIdLiveM3u8GetSubtitleMethodFromJson(e.toString())) + .toList(); +} + +List? + videosItemIdLiveM3u8GetSubtitleMethodNullableListFromJson( + List? videosItemIdLiveM3u8GetSubtitleMethod, [ + List? defaultValue, +]) { + if (videosItemIdLiveM3u8GetSubtitleMethod == null) { + return defaultValue; + } + + return videosItemIdLiveM3u8GetSubtitleMethod + .map((e) => videosItemIdLiveM3u8GetSubtitleMethodFromJson(e.toString())) + .toList(); +} + +String? videosItemIdLiveM3u8GetContextNullableToJson( + enums.VideosItemIdLiveM3u8GetContext? videosItemIdLiveM3u8GetContext) { + return videosItemIdLiveM3u8GetContext?.value; +} + +String? videosItemIdLiveM3u8GetContextToJson( + enums.VideosItemIdLiveM3u8GetContext videosItemIdLiveM3u8GetContext) { + return videosItemIdLiveM3u8GetContext.value; +} + +enums.VideosItemIdLiveM3u8GetContext videosItemIdLiveM3u8GetContextFromJson( + Object? videosItemIdLiveM3u8GetContext, [ + enums.VideosItemIdLiveM3u8GetContext? defaultValue, +]) { + return enums.VideosItemIdLiveM3u8GetContext.values + .firstWhereOrNull((e) => e.value == videosItemIdLiveM3u8GetContext) ?? + defaultValue ?? + enums.VideosItemIdLiveM3u8GetContext.swaggerGeneratedUnknown; +} + +enums.VideosItemIdLiveM3u8GetContext? + videosItemIdLiveM3u8GetContextNullableFromJson( + Object? videosItemIdLiveM3u8GetContext, [ + enums.VideosItemIdLiveM3u8GetContext? defaultValue, +]) { + if (videosItemIdLiveM3u8GetContext == null) { + return null; + } + return enums.VideosItemIdLiveM3u8GetContext.values + .firstWhereOrNull((e) => e.value == videosItemIdLiveM3u8GetContext) ?? + defaultValue; +} + +String videosItemIdLiveM3u8GetContextExplodedListToJson( + List? + videosItemIdLiveM3u8GetContext) { + return videosItemIdLiveM3u8GetContext?.map((e) => e.value!).join(',') ?? ''; +} + +List videosItemIdLiveM3u8GetContextListToJson( + List? + videosItemIdLiveM3u8GetContext) { + if (videosItemIdLiveM3u8GetContext == null) { + return []; + } + + return videosItemIdLiveM3u8GetContext.map((e) => e.value!).toList(); +} + +List + videosItemIdLiveM3u8GetContextListFromJson( + List? videosItemIdLiveM3u8GetContext, [ + List? defaultValue, +]) { + if (videosItemIdLiveM3u8GetContext == null) { + return defaultValue ?? []; + } + + return videosItemIdLiveM3u8GetContext + .map((e) => videosItemIdLiveM3u8GetContextFromJson(e.toString())) + .toList(); +} + +List? + videosItemIdLiveM3u8GetContextNullableListFromJson( + List? videosItemIdLiveM3u8GetContext, [ + List? defaultValue, +]) { + if (videosItemIdLiveM3u8GetContext == null) { + return defaultValue; + } + + return videosItemIdLiveM3u8GetContext + .map((e) => videosItemIdLiveM3u8GetContextFromJson(e.toString())) + .toList(); +} + +String? videosItemIdMainM3u8GetSubtitleMethodNullableToJson( + enums.VideosItemIdMainM3u8GetSubtitleMethod? + videosItemIdMainM3u8GetSubtitleMethod) { + return videosItemIdMainM3u8GetSubtitleMethod?.value; +} + +String? videosItemIdMainM3u8GetSubtitleMethodToJson( + enums.VideosItemIdMainM3u8GetSubtitleMethod + videosItemIdMainM3u8GetSubtitleMethod) { + return videosItemIdMainM3u8GetSubtitleMethod.value; +} + +enums.VideosItemIdMainM3u8GetSubtitleMethod + videosItemIdMainM3u8GetSubtitleMethodFromJson( + Object? videosItemIdMainM3u8GetSubtitleMethod, [ + enums.VideosItemIdMainM3u8GetSubtitleMethod? defaultValue, +]) { + return enums.VideosItemIdMainM3u8GetSubtitleMethod.values.firstWhereOrNull( + (e) => e.value == videosItemIdMainM3u8GetSubtitleMethod) ?? + defaultValue ?? + enums.VideosItemIdMainM3u8GetSubtitleMethod.swaggerGeneratedUnknown; +} + +enums.VideosItemIdMainM3u8GetSubtitleMethod? + videosItemIdMainM3u8GetSubtitleMethodNullableFromJson( + Object? videosItemIdMainM3u8GetSubtitleMethod, [ + enums.VideosItemIdMainM3u8GetSubtitleMethod? defaultValue, +]) { + if (videosItemIdMainM3u8GetSubtitleMethod == null) { + return null; + } + return enums.VideosItemIdMainM3u8GetSubtitleMethod.values.firstWhereOrNull( + (e) => e.value == videosItemIdMainM3u8GetSubtitleMethod) ?? + defaultValue; +} + +String videosItemIdMainM3u8GetSubtitleMethodExplodedListToJson( + List? + videosItemIdMainM3u8GetSubtitleMethod) { + return videosItemIdMainM3u8GetSubtitleMethod + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List videosItemIdMainM3u8GetSubtitleMethodListToJson( + List? + videosItemIdMainM3u8GetSubtitleMethod) { + if (videosItemIdMainM3u8GetSubtitleMethod == null) { + return []; + } + + return videosItemIdMainM3u8GetSubtitleMethod.map((e) => e.value!).toList(); +} + +List + videosItemIdMainM3u8GetSubtitleMethodListFromJson( + List? videosItemIdMainM3u8GetSubtitleMethod, [ + List? defaultValue, +]) { + if (videosItemIdMainM3u8GetSubtitleMethod == null) { + return defaultValue ?? []; + } + + return videosItemIdMainM3u8GetSubtitleMethod + .map((e) => videosItemIdMainM3u8GetSubtitleMethodFromJson(e.toString())) + .toList(); +} + +List? + videosItemIdMainM3u8GetSubtitleMethodNullableListFromJson( + List? videosItemIdMainM3u8GetSubtitleMethod, [ + List? defaultValue, +]) { + if (videosItemIdMainM3u8GetSubtitleMethod == null) { + return defaultValue; + } + + return videosItemIdMainM3u8GetSubtitleMethod + .map((e) => videosItemIdMainM3u8GetSubtitleMethodFromJson(e.toString())) + .toList(); +} + +String? videosItemIdMainM3u8GetContextNullableToJson( + enums.VideosItemIdMainM3u8GetContext? videosItemIdMainM3u8GetContext) { + return videosItemIdMainM3u8GetContext?.value; +} + +String? videosItemIdMainM3u8GetContextToJson( + enums.VideosItemIdMainM3u8GetContext videosItemIdMainM3u8GetContext) { + return videosItemIdMainM3u8GetContext.value; +} + +enums.VideosItemIdMainM3u8GetContext videosItemIdMainM3u8GetContextFromJson( + Object? videosItemIdMainM3u8GetContext, [ + enums.VideosItemIdMainM3u8GetContext? defaultValue, +]) { + return enums.VideosItemIdMainM3u8GetContext.values + .firstWhereOrNull((e) => e.value == videosItemIdMainM3u8GetContext) ?? + defaultValue ?? + enums.VideosItemIdMainM3u8GetContext.swaggerGeneratedUnknown; +} + +enums.VideosItemIdMainM3u8GetContext? + videosItemIdMainM3u8GetContextNullableFromJson( + Object? videosItemIdMainM3u8GetContext, [ + enums.VideosItemIdMainM3u8GetContext? defaultValue, +]) { + if (videosItemIdMainM3u8GetContext == null) { + return null; + } + return enums.VideosItemIdMainM3u8GetContext.values + .firstWhereOrNull((e) => e.value == videosItemIdMainM3u8GetContext) ?? + defaultValue; +} + +String videosItemIdMainM3u8GetContextExplodedListToJson( + List? + videosItemIdMainM3u8GetContext) { + return videosItemIdMainM3u8GetContext?.map((e) => e.value!).join(',') ?? ''; +} + +List videosItemIdMainM3u8GetContextListToJson( + List? + videosItemIdMainM3u8GetContext) { + if (videosItemIdMainM3u8GetContext == null) { + return []; + } + + return videosItemIdMainM3u8GetContext.map((e) => e.value!).toList(); +} + +List + videosItemIdMainM3u8GetContextListFromJson( + List? videosItemIdMainM3u8GetContext, [ + List? defaultValue, +]) { + if (videosItemIdMainM3u8GetContext == null) { + return defaultValue ?? []; + } + + return videosItemIdMainM3u8GetContext + .map((e) => videosItemIdMainM3u8GetContextFromJson(e.toString())) + .toList(); +} + +List? + videosItemIdMainM3u8GetContextNullableListFromJson( + List? videosItemIdMainM3u8GetContext, [ + List? defaultValue, +]) { + if (videosItemIdMainM3u8GetContext == null) { + return defaultValue; + } + + return videosItemIdMainM3u8GetContext + .map((e) => videosItemIdMainM3u8GetContextFromJson(e.toString())) + .toList(); +} + +String? videosItemIdMasterM3u8GetSubtitleMethodNullableToJson( + enums.VideosItemIdMasterM3u8GetSubtitleMethod? + videosItemIdMasterM3u8GetSubtitleMethod) { + return videosItemIdMasterM3u8GetSubtitleMethod?.value; +} + +String? videosItemIdMasterM3u8GetSubtitleMethodToJson( + enums.VideosItemIdMasterM3u8GetSubtitleMethod + videosItemIdMasterM3u8GetSubtitleMethod) { + return videosItemIdMasterM3u8GetSubtitleMethod.value; +} + +enums.VideosItemIdMasterM3u8GetSubtitleMethod + videosItemIdMasterM3u8GetSubtitleMethodFromJson( + Object? videosItemIdMasterM3u8GetSubtitleMethod, [ + enums.VideosItemIdMasterM3u8GetSubtitleMethod? defaultValue, +]) { + return enums.VideosItemIdMasterM3u8GetSubtitleMethod.values.firstWhereOrNull( + (e) => e.value == videosItemIdMasterM3u8GetSubtitleMethod) ?? + defaultValue ?? + enums.VideosItemIdMasterM3u8GetSubtitleMethod.swaggerGeneratedUnknown; +} + +enums.VideosItemIdMasterM3u8GetSubtitleMethod? + videosItemIdMasterM3u8GetSubtitleMethodNullableFromJson( + Object? videosItemIdMasterM3u8GetSubtitleMethod, [ + enums.VideosItemIdMasterM3u8GetSubtitleMethod? defaultValue, +]) { + if (videosItemIdMasterM3u8GetSubtitleMethod == null) { + return null; + } + return enums.VideosItemIdMasterM3u8GetSubtitleMethod.values.firstWhereOrNull( + (e) => e.value == videosItemIdMasterM3u8GetSubtitleMethod) ?? + defaultValue; +} + +String videosItemIdMasterM3u8GetSubtitleMethodExplodedListToJson( + List? + videosItemIdMasterM3u8GetSubtitleMethod) { + return videosItemIdMasterM3u8GetSubtitleMethod + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List videosItemIdMasterM3u8GetSubtitleMethodListToJson( + List? + videosItemIdMasterM3u8GetSubtitleMethod) { + if (videosItemIdMasterM3u8GetSubtitleMethod == null) { + return []; + } + + return videosItemIdMasterM3u8GetSubtitleMethod.map((e) => e.value!).toList(); +} + +List + videosItemIdMasterM3u8GetSubtitleMethodListFromJson( + List? videosItemIdMasterM3u8GetSubtitleMethod, [ + List? defaultValue, +]) { + if (videosItemIdMasterM3u8GetSubtitleMethod == null) { + return defaultValue ?? []; + } + + return videosItemIdMasterM3u8GetSubtitleMethod + .map((e) => videosItemIdMasterM3u8GetSubtitleMethodFromJson(e.toString())) + .toList(); +} + +List? + videosItemIdMasterM3u8GetSubtitleMethodNullableListFromJson( + List? videosItemIdMasterM3u8GetSubtitleMethod, [ + List? defaultValue, +]) { + if (videosItemIdMasterM3u8GetSubtitleMethod == null) { + return defaultValue; + } + + return videosItemIdMasterM3u8GetSubtitleMethod + .map((e) => videosItemIdMasterM3u8GetSubtitleMethodFromJson(e.toString())) + .toList(); +} + +String? videosItemIdMasterM3u8GetContextNullableToJson( + enums.VideosItemIdMasterM3u8GetContext? videosItemIdMasterM3u8GetContext) { + return videosItemIdMasterM3u8GetContext?.value; +} + +String? videosItemIdMasterM3u8GetContextToJson( + enums.VideosItemIdMasterM3u8GetContext videosItemIdMasterM3u8GetContext) { + return videosItemIdMasterM3u8GetContext.value; +} + +enums.VideosItemIdMasterM3u8GetContext videosItemIdMasterM3u8GetContextFromJson( + Object? videosItemIdMasterM3u8GetContext, [ + enums.VideosItemIdMasterM3u8GetContext? defaultValue, +]) { + return enums.VideosItemIdMasterM3u8GetContext.values.firstWhereOrNull( + (e) => e.value == videosItemIdMasterM3u8GetContext) ?? + defaultValue ?? + enums.VideosItemIdMasterM3u8GetContext.swaggerGeneratedUnknown; +} + +enums.VideosItemIdMasterM3u8GetContext? + videosItemIdMasterM3u8GetContextNullableFromJson( + Object? videosItemIdMasterM3u8GetContext, [ + enums.VideosItemIdMasterM3u8GetContext? defaultValue, +]) { + if (videosItemIdMasterM3u8GetContext == null) { + return null; + } + return enums.VideosItemIdMasterM3u8GetContext.values.firstWhereOrNull( + (e) => e.value == videosItemIdMasterM3u8GetContext) ?? + defaultValue; +} + +String videosItemIdMasterM3u8GetContextExplodedListToJson( + List? + videosItemIdMasterM3u8GetContext) { + return videosItemIdMasterM3u8GetContext?.map((e) => e.value!).join(',') ?? ''; +} + +List videosItemIdMasterM3u8GetContextListToJson( + List? + videosItemIdMasterM3u8GetContext) { + if (videosItemIdMasterM3u8GetContext == null) { + return []; + } + + return videosItemIdMasterM3u8GetContext.map((e) => e.value!).toList(); +} + +List + videosItemIdMasterM3u8GetContextListFromJson( + List? videosItemIdMasterM3u8GetContext, [ + List? defaultValue, +]) { + if (videosItemIdMasterM3u8GetContext == null) { + return defaultValue ?? []; + } + + return videosItemIdMasterM3u8GetContext + .map((e) => videosItemIdMasterM3u8GetContextFromJson(e.toString())) + .toList(); +} + +List? + videosItemIdMasterM3u8GetContextNullableListFromJson( + List? videosItemIdMasterM3u8GetContext, [ + List? defaultValue, +]) { + if (videosItemIdMasterM3u8GetContext == null) { + return defaultValue; + } + + return videosItemIdMasterM3u8GetContext + .map((e) => videosItemIdMasterM3u8GetContextFromJson(e.toString())) + .toList(); +} + +String? videosItemIdMasterM3u8HeadSubtitleMethodNullableToJson( + enums.VideosItemIdMasterM3u8HeadSubtitleMethod? + videosItemIdMasterM3u8HeadSubtitleMethod) { + return videosItemIdMasterM3u8HeadSubtitleMethod?.value; +} + +String? videosItemIdMasterM3u8HeadSubtitleMethodToJson( + enums.VideosItemIdMasterM3u8HeadSubtitleMethod + videosItemIdMasterM3u8HeadSubtitleMethod) { + return videosItemIdMasterM3u8HeadSubtitleMethod.value; +} + +enums.VideosItemIdMasterM3u8HeadSubtitleMethod + videosItemIdMasterM3u8HeadSubtitleMethodFromJson( + Object? videosItemIdMasterM3u8HeadSubtitleMethod, [ + enums.VideosItemIdMasterM3u8HeadSubtitleMethod? defaultValue, +]) { + return enums.VideosItemIdMasterM3u8HeadSubtitleMethod.values.firstWhereOrNull( + (e) => e.value == videosItemIdMasterM3u8HeadSubtitleMethod) ?? + defaultValue ?? + enums.VideosItemIdMasterM3u8HeadSubtitleMethod.swaggerGeneratedUnknown; +} + +enums.VideosItemIdMasterM3u8HeadSubtitleMethod? + videosItemIdMasterM3u8HeadSubtitleMethodNullableFromJson( + Object? videosItemIdMasterM3u8HeadSubtitleMethod, [ + enums.VideosItemIdMasterM3u8HeadSubtitleMethod? defaultValue, +]) { + if (videosItemIdMasterM3u8HeadSubtitleMethod == null) { + return null; + } + return enums.VideosItemIdMasterM3u8HeadSubtitleMethod.values.firstWhereOrNull( + (e) => e.value == videosItemIdMasterM3u8HeadSubtitleMethod) ?? + defaultValue; +} + +String videosItemIdMasterM3u8HeadSubtitleMethodExplodedListToJson( + List? + videosItemIdMasterM3u8HeadSubtitleMethod) { + return videosItemIdMasterM3u8HeadSubtitleMethod + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List videosItemIdMasterM3u8HeadSubtitleMethodListToJson( + List? + videosItemIdMasterM3u8HeadSubtitleMethod) { + if (videosItemIdMasterM3u8HeadSubtitleMethod == null) { + return []; + } + + return videosItemIdMasterM3u8HeadSubtitleMethod.map((e) => e.value!).toList(); +} + +List + videosItemIdMasterM3u8HeadSubtitleMethodListFromJson( + List? videosItemIdMasterM3u8HeadSubtitleMethod, [ + List? defaultValue, +]) { + if (videosItemIdMasterM3u8HeadSubtitleMethod == null) { + return defaultValue ?? []; + } + + return videosItemIdMasterM3u8HeadSubtitleMethod + .map( + (e) => videosItemIdMasterM3u8HeadSubtitleMethodFromJson(e.toString())) + .toList(); +} + +List? + videosItemIdMasterM3u8HeadSubtitleMethodNullableListFromJson( + List? videosItemIdMasterM3u8HeadSubtitleMethod, [ + List? defaultValue, +]) { + if (videosItemIdMasterM3u8HeadSubtitleMethod == null) { + return defaultValue; + } + + return videosItemIdMasterM3u8HeadSubtitleMethod + .map( + (e) => videosItemIdMasterM3u8HeadSubtitleMethodFromJson(e.toString())) + .toList(); +} + +String? videosItemIdMasterM3u8HeadContextNullableToJson( + enums.VideosItemIdMasterM3u8HeadContext? + videosItemIdMasterM3u8HeadContext) { + return videosItemIdMasterM3u8HeadContext?.value; +} + +String? videosItemIdMasterM3u8HeadContextToJson( + enums.VideosItemIdMasterM3u8HeadContext videosItemIdMasterM3u8HeadContext) { + return videosItemIdMasterM3u8HeadContext.value; +} + +enums.VideosItemIdMasterM3u8HeadContext + videosItemIdMasterM3u8HeadContextFromJson( + Object? videosItemIdMasterM3u8HeadContext, [ + enums.VideosItemIdMasterM3u8HeadContext? defaultValue, +]) { + return enums.VideosItemIdMasterM3u8HeadContext.values.firstWhereOrNull( + (e) => e.value == videosItemIdMasterM3u8HeadContext) ?? + defaultValue ?? + enums.VideosItemIdMasterM3u8HeadContext.swaggerGeneratedUnknown; +} + +enums.VideosItemIdMasterM3u8HeadContext? + videosItemIdMasterM3u8HeadContextNullableFromJson( + Object? videosItemIdMasterM3u8HeadContext, [ + enums.VideosItemIdMasterM3u8HeadContext? defaultValue, +]) { + if (videosItemIdMasterM3u8HeadContext == null) { + return null; + } + return enums.VideosItemIdMasterM3u8HeadContext.values.firstWhereOrNull( + (e) => e.value == videosItemIdMasterM3u8HeadContext) ?? + defaultValue; +} + +String videosItemIdMasterM3u8HeadContextExplodedListToJson( + List? + videosItemIdMasterM3u8HeadContext) { + return videosItemIdMasterM3u8HeadContext?.map((e) => e.value!).join(',') ?? + ''; +} + +List videosItemIdMasterM3u8HeadContextListToJson( + List? + videosItemIdMasterM3u8HeadContext) { + if (videosItemIdMasterM3u8HeadContext == null) { + return []; + } + + return videosItemIdMasterM3u8HeadContext.map((e) => e.value!).toList(); +} + +List + videosItemIdMasterM3u8HeadContextListFromJson( + List? videosItemIdMasterM3u8HeadContext, [ + List? defaultValue, +]) { + if (videosItemIdMasterM3u8HeadContext == null) { + return defaultValue ?? []; + } + + return videosItemIdMasterM3u8HeadContext + .map((e) => videosItemIdMasterM3u8HeadContextFromJson(e.toString())) + .toList(); +} + +List? + videosItemIdMasterM3u8HeadContextNullableListFromJson( + List? videosItemIdMasterM3u8HeadContext, [ + List? defaultValue, +]) { + if (videosItemIdMasterM3u8HeadContext == null) { + return defaultValue; + } + + return videosItemIdMasterM3u8HeadContext + .map((e) => videosItemIdMasterM3u8HeadContextFromJson(e.toString())) + .toList(); +} + +String? artistsNameImagesImageTypeImageIndexGetImageTypeNullableToJson( + enums.ArtistsNameImagesImageTypeImageIndexGetImageType? + artistsNameImagesImageTypeImageIndexGetImageType) { + return artistsNameImagesImageTypeImageIndexGetImageType?.value; +} + +String? artistsNameImagesImageTypeImageIndexGetImageTypeToJson( + enums.ArtistsNameImagesImageTypeImageIndexGetImageType + artistsNameImagesImageTypeImageIndexGetImageType) { + return artistsNameImagesImageTypeImageIndexGetImageType.value; +} + +enums.ArtistsNameImagesImageTypeImageIndexGetImageType + artistsNameImagesImageTypeImageIndexGetImageTypeFromJson( + Object? artistsNameImagesImageTypeImageIndexGetImageType, [ + enums.ArtistsNameImagesImageTypeImageIndexGetImageType? defaultValue, +]) { + return enums.ArtistsNameImagesImageTypeImageIndexGetImageType.values + .firstWhereOrNull((e) => + e.value == artistsNameImagesImageTypeImageIndexGetImageType) ?? + defaultValue ?? + enums.ArtistsNameImagesImageTypeImageIndexGetImageType + .swaggerGeneratedUnknown; +} + +enums.ArtistsNameImagesImageTypeImageIndexGetImageType? + artistsNameImagesImageTypeImageIndexGetImageTypeNullableFromJson( + Object? artistsNameImagesImageTypeImageIndexGetImageType, [ + enums.ArtistsNameImagesImageTypeImageIndexGetImageType? defaultValue, +]) { + if (artistsNameImagesImageTypeImageIndexGetImageType == null) { + return null; + } + return enums.ArtistsNameImagesImageTypeImageIndexGetImageType.values + .firstWhereOrNull((e) => + e.value == artistsNameImagesImageTypeImageIndexGetImageType) ?? + defaultValue; +} + +String artistsNameImagesImageTypeImageIndexGetImageTypeExplodedListToJson( + List? + artistsNameImagesImageTypeImageIndexGetImageType) { + return artistsNameImagesImageTypeImageIndexGetImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List artistsNameImagesImageTypeImageIndexGetImageTypeListToJson( + List? + artistsNameImagesImageTypeImageIndexGetImageType) { + if (artistsNameImagesImageTypeImageIndexGetImageType == null) { + return []; + } + + return artistsNameImagesImageTypeImageIndexGetImageType + .map((e) => e.value!) + .toList(); +} + +List + artistsNameImagesImageTypeImageIndexGetImageTypeListFromJson( + List? artistsNameImagesImageTypeImageIndexGetImageType, [ + List? defaultValue, +]) { + if (artistsNameImagesImageTypeImageIndexGetImageType == null) { + return defaultValue ?? []; + } + + return artistsNameImagesImageTypeImageIndexGetImageType + .map((e) => artistsNameImagesImageTypeImageIndexGetImageTypeFromJson( + e.toString())) + .toList(); +} + +List? + artistsNameImagesImageTypeImageIndexGetImageTypeNullableListFromJson( + List? artistsNameImagesImageTypeImageIndexGetImageType, [ + List? defaultValue, +]) { + if (artistsNameImagesImageTypeImageIndexGetImageType == null) { + return defaultValue; + } + + return artistsNameImagesImageTypeImageIndexGetImageType + .map((e) => artistsNameImagesImageTypeImageIndexGetImageTypeFromJson( + e.toString())) + .toList(); +} + +String? artistsNameImagesImageTypeImageIndexGetFormatNullableToJson( + enums.ArtistsNameImagesImageTypeImageIndexGetFormat? + artistsNameImagesImageTypeImageIndexGetFormat) { + return artistsNameImagesImageTypeImageIndexGetFormat?.value; +} + +String? artistsNameImagesImageTypeImageIndexGetFormatToJson( + enums.ArtistsNameImagesImageTypeImageIndexGetFormat + artistsNameImagesImageTypeImageIndexGetFormat) { + return artistsNameImagesImageTypeImageIndexGetFormat.value; +} + +enums.ArtistsNameImagesImageTypeImageIndexGetFormat + artistsNameImagesImageTypeImageIndexGetFormatFromJson( + Object? artistsNameImagesImageTypeImageIndexGetFormat, [ + enums.ArtistsNameImagesImageTypeImageIndexGetFormat? defaultValue, +]) { + return enums.ArtistsNameImagesImageTypeImageIndexGetFormat.values + .firstWhereOrNull((e) => + e.value == artistsNameImagesImageTypeImageIndexGetFormat) ?? + defaultValue ?? + enums.ArtistsNameImagesImageTypeImageIndexGetFormat + .swaggerGeneratedUnknown; +} + +enums.ArtistsNameImagesImageTypeImageIndexGetFormat? + artistsNameImagesImageTypeImageIndexGetFormatNullableFromJson( + Object? artistsNameImagesImageTypeImageIndexGetFormat, [ + enums.ArtistsNameImagesImageTypeImageIndexGetFormat? defaultValue, +]) { + if (artistsNameImagesImageTypeImageIndexGetFormat == null) { + return null; + } + return enums.ArtistsNameImagesImageTypeImageIndexGetFormat.values + .firstWhereOrNull((e) => + e.value == artistsNameImagesImageTypeImageIndexGetFormat) ?? + defaultValue; +} + +String artistsNameImagesImageTypeImageIndexGetFormatExplodedListToJson( + List? + artistsNameImagesImageTypeImageIndexGetFormat) { + return artistsNameImagesImageTypeImageIndexGetFormat + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List artistsNameImagesImageTypeImageIndexGetFormatListToJson( + List? + artistsNameImagesImageTypeImageIndexGetFormat) { + if (artistsNameImagesImageTypeImageIndexGetFormat == null) { + return []; + } + + return artistsNameImagesImageTypeImageIndexGetFormat + .map((e) => e.value!) + .toList(); +} + +List + artistsNameImagesImageTypeImageIndexGetFormatListFromJson( + List? artistsNameImagesImageTypeImageIndexGetFormat, [ + List? defaultValue, +]) { + if (artistsNameImagesImageTypeImageIndexGetFormat == null) { + return defaultValue ?? []; + } + + return artistsNameImagesImageTypeImageIndexGetFormat + .map((e) => + artistsNameImagesImageTypeImageIndexGetFormatFromJson(e.toString())) + .toList(); +} + +List? + artistsNameImagesImageTypeImageIndexGetFormatNullableListFromJson( + List? artistsNameImagesImageTypeImageIndexGetFormat, [ + List? defaultValue, +]) { + if (artistsNameImagesImageTypeImageIndexGetFormat == null) { + return defaultValue; + } + + return artistsNameImagesImageTypeImageIndexGetFormat + .map((e) => + artistsNameImagesImageTypeImageIndexGetFormatFromJson(e.toString())) + .toList(); +} + +String? artistsNameImagesImageTypeImageIndexHeadImageTypeNullableToJson( + enums.ArtistsNameImagesImageTypeImageIndexHeadImageType? + artistsNameImagesImageTypeImageIndexHeadImageType) { + return artistsNameImagesImageTypeImageIndexHeadImageType?.value; +} + +String? artistsNameImagesImageTypeImageIndexHeadImageTypeToJson( + enums.ArtistsNameImagesImageTypeImageIndexHeadImageType + artistsNameImagesImageTypeImageIndexHeadImageType) { + return artistsNameImagesImageTypeImageIndexHeadImageType.value; +} + +enums.ArtistsNameImagesImageTypeImageIndexHeadImageType + artistsNameImagesImageTypeImageIndexHeadImageTypeFromJson( + Object? artistsNameImagesImageTypeImageIndexHeadImageType, [ + enums.ArtistsNameImagesImageTypeImageIndexHeadImageType? defaultValue, +]) { + return enums.ArtistsNameImagesImageTypeImageIndexHeadImageType.values + .firstWhereOrNull((e) => + e.value == artistsNameImagesImageTypeImageIndexHeadImageType) ?? + defaultValue ?? + enums.ArtistsNameImagesImageTypeImageIndexHeadImageType + .swaggerGeneratedUnknown; +} + +enums.ArtistsNameImagesImageTypeImageIndexHeadImageType? + artistsNameImagesImageTypeImageIndexHeadImageTypeNullableFromJson( + Object? artistsNameImagesImageTypeImageIndexHeadImageType, [ + enums.ArtistsNameImagesImageTypeImageIndexHeadImageType? defaultValue, +]) { + if (artistsNameImagesImageTypeImageIndexHeadImageType == null) { + return null; + } + return enums.ArtistsNameImagesImageTypeImageIndexHeadImageType.values + .firstWhereOrNull((e) => + e.value == artistsNameImagesImageTypeImageIndexHeadImageType) ?? + defaultValue; +} + +String artistsNameImagesImageTypeImageIndexHeadImageTypeExplodedListToJson( + List? + artistsNameImagesImageTypeImageIndexHeadImageType) { + return artistsNameImagesImageTypeImageIndexHeadImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List artistsNameImagesImageTypeImageIndexHeadImageTypeListToJson( + List? + artistsNameImagesImageTypeImageIndexHeadImageType) { + if (artistsNameImagesImageTypeImageIndexHeadImageType == null) { + return []; + } + + return artistsNameImagesImageTypeImageIndexHeadImageType + .map((e) => e.value!) + .toList(); +} + +List + artistsNameImagesImageTypeImageIndexHeadImageTypeListFromJson( + List? artistsNameImagesImageTypeImageIndexHeadImageType, [ + List? defaultValue, +]) { + if (artistsNameImagesImageTypeImageIndexHeadImageType == null) { + return defaultValue ?? []; + } + + return artistsNameImagesImageTypeImageIndexHeadImageType + .map((e) => artistsNameImagesImageTypeImageIndexHeadImageTypeFromJson( + e.toString())) + .toList(); +} + +List? + artistsNameImagesImageTypeImageIndexHeadImageTypeNullableListFromJson( + List? artistsNameImagesImageTypeImageIndexHeadImageType, [ + List? defaultValue, +]) { + if (artistsNameImagesImageTypeImageIndexHeadImageType == null) { + return defaultValue; + } + + return artistsNameImagesImageTypeImageIndexHeadImageType + .map((e) => artistsNameImagesImageTypeImageIndexHeadImageTypeFromJson( + e.toString())) + .toList(); +} + +String? artistsNameImagesImageTypeImageIndexHeadFormatNullableToJson( + enums.ArtistsNameImagesImageTypeImageIndexHeadFormat? + artistsNameImagesImageTypeImageIndexHeadFormat) { + return artistsNameImagesImageTypeImageIndexHeadFormat?.value; +} + +String? artistsNameImagesImageTypeImageIndexHeadFormatToJson( + enums.ArtistsNameImagesImageTypeImageIndexHeadFormat + artistsNameImagesImageTypeImageIndexHeadFormat) { + return artistsNameImagesImageTypeImageIndexHeadFormat.value; +} + +enums.ArtistsNameImagesImageTypeImageIndexHeadFormat + artistsNameImagesImageTypeImageIndexHeadFormatFromJson( + Object? artistsNameImagesImageTypeImageIndexHeadFormat, [ + enums.ArtistsNameImagesImageTypeImageIndexHeadFormat? defaultValue, +]) { + return enums.ArtistsNameImagesImageTypeImageIndexHeadFormat.values + .firstWhereOrNull((e) => + e.value == artistsNameImagesImageTypeImageIndexHeadFormat) ?? + defaultValue ?? + enums.ArtistsNameImagesImageTypeImageIndexHeadFormat + .swaggerGeneratedUnknown; +} + +enums.ArtistsNameImagesImageTypeImageIndexHeadFormat? + artistsNameImagesImageTypeImageIndexHeadFormatNullableFromJson( + Object? artistsNameImagesImageTypeImageIndexHeadFormat, [ + enums.ArtistsNameImagesImageTypeImageIndexHeadFormat? defaultValue, +]) { + if (artistsNameImagesImageTypeImageIndexHeadFormat == null) { + return null; + } + return enums.ArtistsNameImagesImageTypeImageIndexHeadFormat.values + .firstWhereOrNull((e) => + e.value == artistsNameImagesImageTypeImageIndexHeadFormat) ?? + defaultValue; +} + +String artistsNameImagesImageTypeImageIndexHeadFormatExplodedListToJson( + List? + artistsNameImagesImageTypeImageIndexHeadFormat) { + return artistsNameImagesImageTypeImageIndexHeadFormat + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List artistsNameImagesImageTypeImageIndexHeadFormatListToJson( + List? + artistsNameImagesImageTypeImageIndexHeadFormat) { + if (artistsNameImagesImageTypeImageIndexHeadFormat == null) { + return []; + } + + return artistsNameImagesImageTypeImageIndexHeadFormat + .map((e) => e.value!) + .toList(); +} + +List + artistsNameImagesImageTypeImageIndexHeadFormatListFromJson( + List? artistsNameImagesImageTypeImageIndexHeadFormat, [ + List? defaultValue, +]) { + if (artistsNameImagesImageTypeImageIndexHeadFormat == null) { + return defaultValue ?? []; + } + + return artistsNameImagesImageTypeImageIndexHeadFormat + .map((e) => + artistsNameImagesImageTypeImageIndexHeadFormatFromJson(e.toString())) + .toList(); +} + +List? + artistsNameImagesImageTypeImageIndexHeadFormatNullableListFromJson( + List? artistsNameImagesImageTypeImageIndexHeadFormat, [ + List? defaultValue, +]) { + if (artistsNameImagesImageTypeImageIndexHeadFormat == null) { + return defaultValue; + } + + return artistsNameImagesImageTypeImageIndexHeadFormat + .map((e) => + artistsNameImagesImageTypeImageIndexHeadFormatFromJson(e.toString())) + .toList(); +} + +String? brandingSplashscreenGetFormatNullableToJson( + enums.BrandingSplashscreenGetFormat? brandingSplashscreenGetFormat) { + return brandingSplashscreenGetFormat?.value; +} + +String? brandingSplashscreenGetFormatToJson( + enums.BrandingSplashscreenGetFormat brandingSplashscreenGetFormat) { + return brandingSplashscreenGetFormat.value; +} + +enums.BrandingSplashscreenGetFormat brandingSplashscreenGetFormatFromJson( + Object? brandingSplashscreenGetFormat, [ + enums.BrandingSplashscreenGetFormat? defaultValue, +]) { + return enums.BrandingSplashscreenGetFormat.values + .firstWhereOrNull((e) => e.value == brandingSplashscreenGetFormat) ?? + defaultValue ?? + enums.BrandingSplashscreenGetFormat.swaggerGeneratedUnknown; +} + +enums.BrandingSplashscreenGetFormat? + brandingSplashscreenGetFormatNullableFromJson( + Object? brandingSplashscreenGetFormat, [ + enums.BrandingSplashscreenGetFormat? defaultValue, +]) { + if (brandingSplashscreenGetFormat == null) { + return null; + } + return enums.BrandingSplashscreenGetFormat.values + .firstWhereOrNull((e) => e.value == brandingSplashscreenGetFormat) ?? + defaultValue; +} + +String brandingSplashscreenGetFormatExplodedListToJson( + List? brandingSplashscreenGetFormat) { + return brandingSplashscreenGetFormat?.map((e) => e.value!).join(',') ?? ''; +} + +List brandingSplashscreenGetFormatListToJson( + List? brandingSplashscreenGetFormat) { + if (brandingSplashscreenGetFormat == null) { + return []; + } + + return brandingSplashscreenGetFormat.map((e) => e.value!).toList(); +} + +List + brandingSplashscreenGetFormatListFromJson( + List? brandingSplashscreenGetFormat, [ + List? defaultValue, +]) { + if (brandingSplashscreenGetFormat == null) { + return defaultValue ?? []; + } + + return brandingSplashscreenGetFormat + .map((e) => brandingSplashscreenGetFormatFromJson(e.toString())) + .toList(); +} + +List? + brandingSplashscreenGetFormatNullableListFromJson( + List? brandingSplashscreenGetFormat, [ + List? defaultValue, +]) { + if (brandingSplashscreenGetFormat == null) { + return defaultValue; + } + + return brandingSplashscreenGetFormat + .map((e) => brandingSplashscreenGetFormatFromJson(e.toString())) + .toList(); +} + +String? genresNameImagesImageTypeGetImageTypeNullableToJson( + enums.GenresNameImagesImageTypeGetImageType? + genresNameImagesImageTypeGetImageType) { + return genresNameImagesImageTypeGetImageType?.value; +} + +String? genresNameImagesImageTypeGetImageTypeToJson( + enums.GenresNameImagesImageTypeGetImageType + genresNameImagesImageTypeGetImageType) { + return genresNameImagesImageTypeGetImageType.value; +} + +enums.GenresNameImagesImageTypeGetImageType + genresNameImagesImageTypeGetImageTypeFromJson( + Object? genresNameImagesImageTypeGetImageType, [ + enums.GenresNameImagesImageTypeGetImageType? defaultValue, +]) { + return enums.GenresNameImagesImageTypeGetImageType.values.firstWhereOrNull( + (e) => e.value == genresNameImagesImageTypeGetImageType) ?? + defaultValue ?? + enums.GenresNameImagesImageTypeGetImageType.swaggerGeneratedUnknown; +} + +enums.GenresNameImagesImageTypeGetImageType? + genresNameImagesImageTypeGetImageTypeNullableFromJson( + Object? genresNameImagesImageTypeGetImageType, [ + enums.GenresNameImagesImageTypeGetImageType? defaultValue, +]) { + if (genresNameImagesImageTypeGetImageType == null) { + return null; + } + return enums.GenresNameImagesImageTypeGetImageType.values.firstWhereOrNull( + (e) => e.value == genresNameImagesImageTypeGetImageType) ?? + defaultValue; +} + +String genresNameImagesImageTypeGetImageTypeExplodedListToJson( + List? + genresNameImagesImageTypeGetImageType) { + return genresNameImagesImageTypeGetImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List genresNameImagesImageTypeGetImageTypeListToJson( + List? + genresNameImagesImageTypeGetImageType) { + if (genresNameImagesImageTypeGetImageType == null) { + return []; + } + + return genresNameImagesImageTypeGetImageType.map((e) => e.value!).toList(); +} + +List + genresNameImagesImageTypeGetImageTypeListFromJson( + List? genresNameImagesImageTypeGetImageType, [ + List? defaultValue, +]) { + if (genresNameImagesImageTypeGetImageType == null) { + return defaultValue ?? []; + } + + return genresNameImagesImageTypeGetImageType + .map((e) => genresNameImagesImageTypeGetImageTypeFromJson(e.toString())) + .toList(); +} + +List? + genresNameImagesImageTypeGetImageTypeNullableListFromJson( + List? genresNameImagesImageTypeGetImageType, [ + List? defaultValue, +]) { + if (genresNameImagesImageTypeGetImageType == null) { + return defaultValue; + } + + return genresNameImagesImageTypeGetImageType + .map((e) => genresNameImagesImageTypeGetImageTypeFromJson(e.toString())) + .toList(); +} + +String? genresNameImagesImageTypeGetFormatNullableToJson( + enums.GenresNameImagesImageTypeGetFormat? + genresNameImagesImageTypeGetFormat) { + return genresNameImagesImageTypeGetFormat?.value; +} + +String? genresNameImagesImageTypeGetFormatToJson( + enums.GenresNameImagesImageTypeGetFormat + genresNameImagesImageTypeGetFormat) { + return genresNameImagesImageTypeGetFormat.value; +} + +enums.GenresNameImagesImageTypeGetFormat + genresNameImagesImageTypeGetFormatFromJson( + Object? genresNameImagesImageTypeGetFormat, [ + enums.GenresNameImagesImageTypeGetFormat? defaultValue, +]) { + return enums.GenresNameImagesImageTypeGetFormat.values.firstWhereOrNull( + (e) => e.value == genresNameImagesImageTypeGetFormat) ?? + defaultValue ?? + enums.GenresNameImagesImageTypeGetFormat.swaggerGeneratedUnknown; +} + +enums.GenresNameImagesImageTypeGetFormat? + genresNameImagesImageTypeGetFormatNullableFromJson( + Object? genresNameImagesImageTypeGetFormat, [ + enums.GenresNameImagesImageTypeGetFormat? defaultValue, +]) { + if (genresNameImagesImageTypeGetFormat == null) { + return null; + } + return enums.GenresNameImagesImageTypeGetFormat.values.firstWhereOrNull( + (e) => e.value == genresNameImagesImageTypeGetFormat) ?? + defaultValue; +} + +String genresNameImagesImageTypeGetFormatExplodedListToJson( + List? + genresNameImagesImageTypeGetFormat) { + return genresNameImagesImageTypeGetFormat?.map((e) => e.value!).join(',') ?? + ''; +} + +List genresNameImagesImageTypeGetFormatListToJson( + List? + genresNameImagesImageTypeGetFormat) { + if (genresNameImagesImageTypeGetFormat == null) { + return []; + } + + return genresNameImagesImageTypeGetFormat.map((e) => e.value!).toList(); +} + +List + genresNameImagesImageTypeGetFormatListFromJson( + List? genresNameImagesImageTypeGetFormat, [ + List? defaultValue, +]) { + if (genresNameImagesImageTypeGetFormat == null) { + return defaultValue ?? []; + } + + return genresNameImagesImageTypeGetFormat + .map((e) => genresNameImagesImageTypeGetFormatFromJson(e.toString())) + .toList(); +} + +List? + genresNameImagesImageTypeGetFormatNullableListFromJson( + List? genresNameImagesImageTypeGetFormat, [ + List? defaultValue, +]) { + if (genresNameImagesImageTypeGetFormat == null) { + return defaultValue; + } + + return genresNameImagesImageTypeGetFormat + .map((e) => genresNameImagesImageTypeGetFormatFromJson(e.toString())) + .toList(); +} + +String? genresNameImagesImageTypeHeadImageTypeNullableToJson( + enums.GenresNameImagesImageTypeHeadImageType? + genresNameImagesImageTypeHeadImageType) { + return genresNameImagesImageTypeHeadImageType?.value; +} + +String? genresNameImagesImageTypeHeadImageTypeToJson( + enums.GenresNameImagesImageTypeHeadImageType + genresNameImagesImageTypeHeadImageType) { + return genresNameImagesImageTypeHeadImageType.value; +} + +enums.GenresNameImagesImageTypeHeadImageType + genresNameImagesImageTypeHeadImageTypeFromJson( + Object? genresNameImagesImageTypeHeadImageType, [ + enums.GenresNameImagesImageTypeHeadImageType? defaultValue, +]) { + return enums.GenresNameImagesImageTypeHeadImageType.values.firstWhereOrNull( + (e) => e.value == genresNameImagesImageTypeHeadImageType) ?? + defaultValue ?? + enums.GenresNameImagesImageTypeHeadImageType.swaggerGeneratedUnknown; +} + +enums.GenresNameImagesImageTypeHeadImageType? + genresNameImagesImageTypeHeadImageTypeNullableFromJson( + Object? genresNameImagesImageTypeHeadImageType, [ + enums.GenresNameImagesImageTypeHeadImageType? defaultValue, +]) { + if (genresNameImagesImageTypeHeadImageType == null) { + return null; + } + return enums.GenresNameImagesImageTypeHeadImageType.values.firstWhereOrNull( + (e) => e.value == genresNameImagesImageTypeHeadImageType) ?? + defaultValue; +} + +String genresNameImagesImageTypeHeadImageTypeExplodedListToJson( + List? + genresNameImagesImageTypeHeadImageType) { + return genresNameImagesImageTypeHeadImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List genresNameImagesImageTypeHeadImageTypeListToJson( + List? + genresNameImagesImageTypeHeadImageType) { + if (genresNameImagesImageTypeHeadImageType == null) { + return []; + } + + return genresNameImagesImageTypeHeadImageType.map((e) => e.value!).toList(); +} + +List + genresNameImagesImageTypeHeadImageTypeListFromJson( + List? genresNameImagesImageTypeHeadImageType, [ + List? defaultValue, +]) { + if (genresNameImagesImageTypeHeadImageType == null) { + return defaultValue ?? []; + } + + return genresNameImagesImageTypeHeadImageType + .map((e) => genresNameImagesImageTypeHeadImageTypeFromJson(e.toString())) + .toList(); +} + +List? + genresNameImagesImageTypeHeadImageTypeNullableListFromJson( + List? genresNameImagesImageTypeHeadImageType, [ + List? defaultValue, +]) { + if (genresNameImagesImageTypeHeadImageType == null) { + return defaultValue; + } + + return genresNameImagesImageTypeHeadImageType + .map((e) => genresNameImagesImageTypeHeadImageTypeFromJson(e.toString())) + .toList(); +} + +String? genresNameImagesImageTypeHeadFormatNullableToJson( + enums.GenresNameImagesImageTypeHeadFormat? + genresNameImagesImageTypeHeadFormat) { + return genresNameImagesImageTypeHeadFormat?.value; +} + +String? genresNameImagesImageTypeHeadFormatToJson( + enums.GenresNameImagesImageTypeHeadFormat + genresNameImagesImageTypeHeadFormat) { + return genresNameImagesImageTypeHeadFormat.value; +} + +enums.GenresNameImagesImageTypeHeadFormat + genresNameImagesImageTypeHeadFormatFromJson( + Object? genresNameImagesImageTypeHeadFormat, [ + enums.GenresNameImagesImageTypeHeadFormat? defaultValue, +]) { + return enums.GenresNameImagesImageTypeHeadFormat.values.firstWhereOrNull( + (e) => e.value == genresNameImagesImageTypeHeadFormat) ?? + defaultValue ?? + enums.GenresNameImagesImageTypeHeadFormat.swaggerGeneratedUnknown; +} + +enums.GenresNameImagesImageTypeHeadFormat? + genresNameImagesImageTypeHeadFormatNullableFromJson( + Object? genresNameImagesImageTypeHeadFormat, [ + enums.GenresNameImagesImageTypeHeadFormat? defaultValue, +]) { + if (genresNameImagesImageTypeHeadFormat == null) { + return null; + } + return enums.GenresNameImagesImageTypeHeadFormat.values.firstWhereOrNull( + (e) => e.value == genresNameImagesImageTypeHeadFormat) ?? + defaultValue; +} + +String genresNameImagesImageTypeHeadFormatExplodedListToJson( + List? + genresNameImagesImageTypeHeadFormat) { + return genresNameImagesImageTypeHeadFormat?.map((e) => e.value!).join(',') ?? + ''; +} + +List genresNameImagesImageTypeHeadFormatListToJson( + List? + genresNameImagesImageTypeHeadFormat) { + if (genresNameImagesImageTypeHeadFormat == null) { + return []; + } + + return genresNameImagesImageTypeHeadFormat.map((e) => e.value!).toList(); +} + +List + genresNameImagesImageTypeHeadFormatListFromJson( + List? genresNameImagesImageTypeHeadFormat, [ + List? defaultValue, +]) { + if (genresNameImagesImageTypeHeadFormat == null) { + return defaultValue ?? []; + } + + return genresNameImagesImageTypeHeadFormat + .map((e) => genresNameImagesImageTypeHeadFormatFromJson(e.toString())) + .toList(); +} + +List? + genresNameImagesImageTypeHeadFormatNullableListFromJson( + List? genresNameImagesImageTypeHeadFormat, [ + List? defaultValue, +]) { + if (genresNameImagesImageTypeHeadFormat == null) { + return defaultValue; + } + + return genresNameImagesImageTypeHeadFormat + .map((e) => genresNameImagesImageTypeHeadFormatFromJson(e.toString())) + .toList(); +} + +String? genresNameImagesImageTypeImageIndexGetImageTypeNullableToJson( + enums.GenresNameImagesImageTypeImageIndexGetImageType? + genresNameImagesImageTypeImageIndexGetImageType) { + return genresNameImagesImageTypeImageIndexGetImageType?.value; +} + +String? genresNameImagesImageTypeImageIndexGetImageTypeToJson( + enums.GenresNameImagesImageTypeImageIndexGetImageType + genresNameImagesImageTypeImageIndexGetImageType) { + return genresNameImagesImageTypeImageIndexGetImageType.value; +} + +enums.GenresNameImagesImageTypeImageIndexGetImageType + genresNameImagesImageTypeImageIndexGetImageTypeFromJson( + Object? genresNameImagesImageTypeImageIndexGetImageType, [ + enums.GenresNameImagesImageTypeImageIndexGetImageType? defaultValue, +]) { + return enums.GenresNameImagesImageTypeImageIndexGetImageType.values + .firstWhereOrNull((e) => + e.value == genresNameImagesImageTypeImageIndexGetImageType) ?? + defaultValue ?? + enums.GenresNameImagesImageTypeImageIndexGetImageType + .swaggerGeneratedUnknown; +} + +enums.GenresNameImagesImageTypeImageIndexGetImageType? + genresNameImagesImageTypeImageIndexGetImageTypeNullableFromJson( + Object? genresNameImagesImageTypeImageIndexGetImageType, [ + enums.GenresNameImagesImageTypeImageIndexGetImageType? defaultValue, +]) { + if (genresNameImagesImageTypeImageIndexGetImageType == null) { + return null; + } + return enums.GenresNameImagesImageTypeImageIndexGetImageType.values + .firstWhereOrNull((e) => + e.value == genresNameImagesImageTypeImageIndexGetImageType) ?? + defaultValue; +} + +String genresNameImagesImageTypeImageIndexGetImageTypeExplodedListToJson( + List? + genresNameImagesImageTypeImageIndexGetImageType) { + return genresNameImagesImageTypeImageIndexGetImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List genresNameImagesImageTypeImageIndexGetImageTypeListToJson( + List? + genresNameImagesImageTypeImageIndexGetImageType) { + if (genresNameImagesImageTypeImageIndexGetImageType == null) { + return []; + } + + return genresNameImagesImageTypeImageIndexGetImageType + .map((e) => e.value!) + .toList(); +} + +List + genresNameImagesImageTypeImageIndexGetImageTypeListFromJson( + List? genresNameImagesImageTypeImageIndexGetImageType, [ + List? defaultValue, +]) { + if (genresNameImagesImageTypeImageIndexGetImageType == null) { + return defaultValue ?? []; + } + + return genresNameImagesImageTypeImageIndexGetImageType + .map((e) => + genresNameImagesImageTypeImageIndexGetImageTypeFromJson(e.toString())) + .toList(); +} + +List? + genresNameImagesImageTypeImageIndexGetImageTypeNullableListFromJson( + List? genresNameImagesImageTypeImageIndexGetImageType, [ + List? defaultValue, +]) { + if (genresNameImagesImageTypeImageIndexGetImageType == null) { + return defaultValue; + } + + return genresNameImagesImageTypeImageIndexGetImageType + .map((e) => + genresNameImagesImageTypeImageIndexGetImageTypeFromJson(e.toString())) + .toList(); +} + +String? genresNameImagesImageTypeImageIndexGetFormatNullableToJson( + enums.GenresNameImagesImageTypeImageIndexGetFormat? + genresNameImagesImageTypeImageIndexGetFormat) { + return genresNameImagesImageTypeImageIndexGetFormat?.value; +} + +String? genresNameImagesImageTypeImageIndexGetFormatToJson( + enums.GenresNameImagesImageTypeImageIndexGetFormat + genresNameImagesImageTypeImageIndexGetFormat) { + return genresNameImagesImageTypeImageIndexGetFormat.value; +} + +enums.GenresNameImagesImageTypeImageIndexGetFormat + genresNameImagesImageTypeImageIndexGetFormatFromJson( + Object? genresNameImagesImageTypeImageIndexGetFormat, [ + enums.GenresNameImagesImageTypeImageIndexGetFormat? defaultValue, +]) { + return enums.GenresNameImagesImageTypeImageIndexGetFormat.values + .firstWhereOrNull( + (e) => e.value == genresNameImagesImageTypeImageIndexGetFormat) ?? + defaultValue ?? + enums + .GenresNameImagesImageTypeImageIndexGetFormat.swaggerGeneratedUnknown; +} + +enums.GenresNameImagesImageTypeImageIndexGetFormat? + genresNameImagesImageTypeImageIndexGetFormatNullableFromJson( + Object? genresNameImagesImageTypeImageIndexGetFormat, [ + enums.GenresNameImagesImageTypeImageIndexGetFormat? defaultValue, +]) { + if (genresNameImagesImageTypeImageIndexGetFormat == null) { + return null; + } + return enums.GenresNameImagesImageTypeImageIndexGetFormat.values + .firstWhereOrNull( + (e) => e.value == genresNameImagesImageTypeImageIndexGetFormat) ?? + defaultValue; +} + +String genresNameImagesImageTypeImageIndexGetFormatExplodedListToJson( + List? + genresNameImagesImageTypeImageIndexGetFormat) { + return genresNameImagesImageTypeImageIndexGetFormat + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List genresNameImagesImageTypeImageIndexGetFormatListToJson( + List? + genresNameImagesImageTypeImageIndexGetFormat) { + if (genresNameImagesImageTypeImageIndexGetFormat == null) { + return []; + } + + return genresNameImagesImageTypeImageIndexGetFormat + .map((e) => e.value!) + .toList(); +} + +List + genresNameImagesImageTypeImageIndexGetFormatListFromJson( + List? genresNameImagesImageTypeImageIndexGetFormat, [ + List? defaultValue, +]) { + if (genresNameImagesImageTypeImageIndexGetFormat == null) { + return defaultValue ?? []; + } + + return genresNameImagesImageTypeImageIndexGetFormat + .map((e) => + genresNameImagesImageTypeImageIndexGetFormatFromJson(e.toString())) + .toList(); +} + +List? + genresNameImagesImageTypeImageIndexGetFormatNullableListFromJson( + List? genresNameImagesImageTypeImageIndexGetFormat, [ + List? defaultValue, +]) { + if (genresNameImagesImageTypeImageIndexGetFormat == null) { + return defaultValue; + } + + return genresNameImagesImageTypeImageIndexGetFormat + .map((e) => + genresNameImagesImageTypeImageIndexGetFormatFromJson(e.toString())) + .toList(); +} + +String? genresNameImagesImageTypeImageIndexHeadImageTypeNullableToJson( + enums.GenresNameImagesImageTypeImageIndexHeadImageType? + genresNameImagesImageTypeImageIndexHeadImageType) { + return genresNameImagesImageTypeImageIndexHeadImageType?.value; +} + +String? genresNameImagesImageTypeImageIndexHeadImageTypeToJson( + enums.GenresNameImagesImageTypeImageIndexHeadImageType + genresNameImagesImageTypeImageIndexHeadImageType) { + return genresNameImagesImageTypeImageIndexHeadImageType.value; +} + +enums.GenresNameImagesImageTypeImageIndexHeadImageType + genresNameImagesImageTypeImageIndexHeadImageTypeFromJson( + Object? genresNameImagesImageTypeImageIndexHeadImageType, [ + enums.GenresNameImagesImageTypeImageIndexHeadImageType? defaultValue, +]) { + return enums.GenresNameImagesImageTypeImageIndexHeadImageType.values + .firstWhereOrNull((e) => + e.value == genresNameImagesImageTypeImageIndexHeadImageType) ?? + defaultValue ?? + enums.GenresNameImagesImageTypeImageIndexHeadImageType + .swaggerGeneratedUnknown; +} + +enums.GenresNameImagesImageTypeImageIndexHeadImageType? + genresNameImagesImageTypeImageIndexHeadImageTypeNullableFromJson( + Object? genresNameImagesImageTypeImageIndexHeadImageType, [ + enums.GenresNameImagesImageTypeImageIndexHeadImageType? defaultValue, +]) { + if (genresNameImagesImageTypeImageIndexHeadImageType == null) { + return null; + } + return enums.GenresNameImagesImageTypeImageIndexHeadImageType.values + .firstWhereOrNull((e) => + e.value == genresNameImagesImageTypeImageIndexHeadImageType) ?? + defaultValue; +} + +String genresNameImagesImageTypeImageIndexHeadImageTypeExplodedListToJson( + List? + genresNameImagesImageTypeImageIndexHeadImageType) { + return genresNameImagesImageTypeImageIndexHeadImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List genresNameImagesImageTypeImageIndexHeadImageTypeListToJson( + List? + genresNameImagesImageTypeImageIndexHeadImageType) { + if (genresNameImagesImageTypeImageIndexHeadImageType == null) { + return []; + } + + return genresNameImagesImageTypeImageIndexHeadImageType + .map((e) => e.value!) + .toList(); +} + +List + genresNameImagesImageTypeImageIndexHeadImageTypeListFromJson( + List? genresNameImagesImageTypeImageIndexHeadImageType, [ + List? defaultValue, +]) { + if (genresNameImagesImageTypeImageIndexHeadImageType == null) { + return defaultValue ?? []; + } + + return genresNameImagesImageTypeImageIndexHeadImageType + .map((e) => genresNameImagesImageTypeImageIndexHeadImageTypeFromJson( + e.toString())) + .toList(); +} + +List? + genresNameImagesImageTypeImageIndexHeadImageTypeNullableListFromJson( + List? genresNameImagesImageTypeImageIndexHeadImageType, [ + List? defaultValue, +]) { + if (genresNameImagesImageTypeImageIndexHeadImageType == null) { + return defaultValue; + } + + return genresNameImagesImageTypeImageIndexHeadImageType + .map((e) => genresNameImagesImageTypeImageIndexHeadImageTypeFromJson( + e.toString())) + .toList(); +} + +String? genresNameImagesImageTypeImageIndexHeadFormatNullableToJson( + enums.GenresNameImagesImageTypeImageIndexHeadFormat? + genresNameImagesImageTypeImageIndexHeadFormat) { + return genresNameImagesImageTypeImageIndexHeadFormat?.value; +} + +String? genresNameImagesImageTypeImageIndexHeadFormatToJson( + enums.GenresNameImagesImageTypeImageIndexHeadFormat + genresNameImagesImageTypeImageIndexHeadFormat) { + return genresNameImagesImageTypeImageIndexHeadFormat.value; +} + +enums.GenresNameImagesImageTypeImageIndexHeadFormat + genresNameImagesImageTypeImageIndexHeadFormatFromJson( + Object? genresNameImagesImageTypeImageIndexHeadFormat, [ + enums.GenresNameImagesImageTypeImageIndexHeadFormat? defaultValue, +]) { + return enums.GenresNameImagesImageTypeImageIndexHeadFormat.values + .firstWhereOrNull((e) => + e.value == genresNameImagesImageTypeImageIndexHeadFormat) ?? + defaultValue ?? + enums.GenresNameImagesImageTypeImageIndexHeadFormat + .swaggerGeneratedUnknown; +} + +enums.GenresNameImagesImageTypeImageIndexHeadFormat? + genresNameImagesImageTypeImageIndexHeadFormatNullableFromJson( + Object? genresNameImagesImageTypeImageIndexHeadFormat, [ + enums.GenresNameImagesImageTypeImageIndexHeadFormat? defaultValue, +]) { + if (genresNameImagesImageTypeImageIndexHeadFormat == null) { + return null; + } + return enums.GenresNameImagesImageTypeImageIndexHeadFormat.values + .firstWhereOrNull((e) => + e.value == genresNameImagesImageTypeImageIndexHeadFormat) ?? + defaultValue; +} + +String genresNameImagesImageTypeImageIndexHeadFormatExplodedListToJson( + List? + genresNameImagesImageTypeImageIndexHeadFormat) { + return genresNameImagesImageTypeImageIndexHeadFormat + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List genresNameImagesImageTypeImageIndexHeadFormatListToJson( + List? + genresNameImagesImageTypeImageIndexHeadFormat) { + if (genresNameImagesImageTypeImageIndexHeadFormat == null) { + return []; + } + + return genresNameImagesImageTypeImageIndexHeadFormat + .map((e) => e.value!) + .toList(); +} + +List + genresNameImagesImageTypeImageIndexHeadFormatListFromJson( + List? genresNameImagesImageTypeImageIndexHeadFormat, [ + List? defaultValue, +]) { + if (genresNameImagesImageTypeImageIndexHeadFormat == null) { + return defaultValue ?? []; + } + + return genresNameImagesImageTypeImageIndexHeadFormat + .map((e) => + genresNameImagesImageTypeImageIndexHeadFormatFromJson(e.toString())) + .toList(); +} + +List? + genresNameImagesImageTypeImageIndexHeadFormatNullableListFromJson( + List? genresNameImagesImageTypeImageIndexHeadFormat, [ + List? defaultValue, +]) { + if (genresNameImagesImageTypeImageIndexHeadFormat == null) { + return defaultValue; + } + + return genresNameImagesImageTypeImageIndexHeadFormat + .map((e) => + genresNameImagesImageTypeImageIndexHeadFormatFromJson(e.toString())) + .toList(); +} + +String? itemsItemIdImagesImageTypeDeleteImageTypeNullableToJson( + enums.ItemsItemIdImagesImageTypeDeleteImageType? + itemsItemIdImagesImageTypeDeleteImageType) { + return itemsItemIdImagesImageTypeDeleteImageType?.value; +} + +String? itemsItemIdImagesImageTypeDeleteImageTypeToJson( + enums.ItemsItemIdImagesImageTypeDeleteImageType + itemsItemIdImagesImageTypeDeleteImageType) { + return itemsItemIdImagesImageTypeDeleteImageType.value; +} + +enums.ItemsItemIdImagesImageTypeDeleteImageType + itemsItemIdImagesImageTypeDeleteImageTypeFromJson( + Object? itemsItemIdImagesImageTypeDeleteImageType, [ + enums.ItemsItemIdImagesImageTypeDeleteImageType? defaultValue, +]) { + return enums.ItemsItemIdImagesImageTypeDeleteImageType.values + .firstWhereOrNull( + (e) => e.value == itemsItemIdImagesImageTypeDeleteImageType) ?? + defaultValue ?? + enums.ItemsItemIdImagesImageTypeDeleteImageType.swaggerGeneratedUnknown; +} + +enums.ItemsItemIdImagesImageTypeDeleteImageType? + itemsItemIdImagesImageTypeDeleteImageTypeNullableFromJson( + Object? itemsItemIdImagesImageTypeDeleteImageType, [ + enums.ItemsItemIdImagesImageTypeDeleteImageType? defaultValue, +]) { + if (itemsItemIdImagesImageTypeDeleteImageType == null) { + return null; + } + return enums.ItemsItemIdImagesImageTypeDeleteImageType.values + .firstWhereOrNull( + (e) => e.value == itemsItemIdImagesImageTypeDeleteImageType) ?? + defaultValue; +} + +String itemsItemIdImagesImageTypeDeleteImageTypeExplodedListToJson( + List? + itemsItemIdImagesImageTypeDeleteImageType) { + return itemsItemIdImagesImageTypeDeleteImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List itemsItemIdImagesImageTypeDeleteImageTypeListToJson( + List? + itemsItemIdImagesImageTypeDeleteImageType) { + if (itemsItemIdImagesImageTypeDeleteImageType == null) { + return []; + } + + return itemsItemIdImagesImageTypeDeleteImageType + .map((e) => e.value!) + .toList(); +} + +List + itemsItemIdImagesImageTypeDeleteImageTypeListFromJson( + List? itemsItemIdImagesImageTypeDeleteImageType, [ + List? defaultValue, +]) { + if (itemsItemIdImagesImageTypeDeleteImageType == null) { + return defaultValue ?? []; + } + + return itemsItemIdImagesImageTypeDeleteImageType + .map((e) => + itemsItemIdImagesImageTypeDeleteImageTypeFromJson(e.toString())) + .toList(); +} + +List? + itemsItemIdImagesImageTypeDeleteImageTypeNullableListFromJson( + List? itemsItemIdImagesImageTypeDeleteImageType, [ + List? defaultValue, +]) { + if (itemsItemIdImagesImageTypeDeleteImageType == null) { + return defaultValue; + } + + return itemsItemIdImagesImageTypeDeleteImageType + .map((e) => + itemsItemIdImagesImageTypeDeleteImageTypeFromJson(e.toString())) + .toList(); +} + +String? itemsItemIdImagesImageTypePostImageTypeNullableToJson( + enums.ItemsItemIdImagesImageTypePostImageType? + itemsItemIdImagesImageTypePostImageType) { + return itemsItemIdImagesImageTypePostImageType?.value; +} + +String? itemsItemIdImagesImageTypePostImageTypeToJson( + enums.ItemsItemIdImagesImageTypePostImageType + itemsItemIdImagesImageTypePostImageType) { + return itemsItemIdImagesImageTypePostImageType.value; +} + +enums.ItemsItemIdImagesImageTypePostImageType + itemsItemIdImagesImageTypePostImageTypeFromJson( + Object? itemsItemIdImagesImageTypePostImageType, [ + enums.ItemsItemIdImagesImageTypePostImageType? defaultValue, +]) { + return enums.ItemsItemIdImagesImageTypePostImageType.values.firstWhereOrNull( + (e) => e.value == itemsItemIdImagesImageTypePostImageType) ?? + defaultValue ?? + enums.ItemsItemIdImagesImageTypePostImageType.swaggerGeneratedUnknown; +} + +enums.ItemsItemIdImagesImageTypePostImageType? + itemsItemIdImagesImageTypePostImageTypeNullableFromJson( + Object? itemsItemIdImagesImageTypePostImageType, [ + enums.ItemsItemIdImagesImageTypePostImageType? defaultValue, +]) { + if (itemsItemIdImagesImageTypePostImageType == null) { + return null; + } + return enums.ItemsItemIdImagesImageTypePostImageType.values.firstWhereOrNull( + (e) => e.value == itemsItemIdImagesImageTypePostImageType) ?? + defaultValue; +} + +String itemsItemIdImagesImageTypePostImageTypeExplodedListToJson( + List? + itemsItemIdImagesImageTypePostImageType) { + return itemsItemIdImagesImageTypePostImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List itemsItemIdImagesImageTypePostImageTypeListToJson( + List? + itemsItemIdImagesImageTypePostImageType) { + if (itemsItemIdImagesImageTypePostImageType == null) { + return []; + } + + return itemsItemIdImagesImageTypePostImageType.map((e) => e.value!).toList(); +} + +List + itemsItemIdImagesImageTypePostImageTypeListFromJson( + List? itemsItemIdImagesImageTypePostImageType, [ + List? defaultValue, +]) { + if (itemsItemIdImagesImageTypePostImageType == null) { + return defaultValue ?? []; + } + + return itemsItemIdImagesImageTypePostImageType + .map((e) => itemsItemIdImagesImageTypePostImageTypeFromJson(e.toString())) + .toList(); +} + +List? + itemsItemIdImagesImageTypePostImageTypeNullableListFromJson( + List? itemsItemIdImagesImageTypePostImageType, [ + List? defaultValue, +]) { + if (itemsItemIdImagesImageTypePostImageType == null) { + return defaultValue; + } + + return itemsItemIdImagesImageTypePostImageType + .map((e) => itemsItemIdImagesImageTypePostImageTypeFromJson(e.toString())) + .toList(); +} + +String? itemsItemIdImagesImageTypeGetImageTypeNullableToJson( + enums.ItemsItemIdImagesImageTypeGetImageType? + itemsItemIdImagesImageTypeGetImageType) { + return itemsItemIdImagesImageTypeGetImageType?.value; +} + +String? itemsItemIdImagesImageTypeGetImageTypeToJson( + enums.ItemsItemIdImagesImageTypeGetImageType + itemsItemIdImagesImageTypeGetImageType) { + return itemsItemIdImagesImageTypeGetImageType.value; +} + +enums.ItemsItemIdImagesImageTypeGetImageType + itemsItemIdImagesImageTypeGetImageTypeFromJson( + Object? itemsItemIdImagesImageTypeGetImageType, [ + enums.ItemsItemIdImagesImageTypeGetImageType? defaultValue, +]) { + return enums.ItemsItemIdImagesImageTypeGetImageType.values.firstWhereOrNull( + (e) => e.value == itemsItemIdImagesImageTypeGetImageType) ?? + defaultValue ?? + enums.ItemsItemIdImagesImageTypeGetImageType.swaggerGeneratedUnknown; +} + +enums.ItemsItemIdImagesImageTypeGetImageType? + itemsItemIdImagesImageTypeGetImageTypeNullableFromJson( + Object? itemsItemIdImagesImageTypeGetImageType, [ + enums.ItemsItemIdImagesImageTypeGetImageType? defaultValue, +]) { + if (itemsItemIdImagesImageTypeGetImageType == null) { + return null; + } + return enums.ItemsItemIdImagesImageTypeGetImageType.values.firstWhereOrNull( + (e) => e.value == itemsItemIdImagesImageTypeGetImageType) ?? + defaultValue; +} + +String itemsItemIdImagesImageTypeGetImageTypeExplodedListToJson( + List? + itemsItemIdImagesImageTypeGetImageType) { + return itemsItemIdImagesImageTypeGetImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List itemsItemIdImagesImageTypeGetImageTypeListToJson( + List? + itemsItemIdImagesImageTypeGetImageType) { + if (itemsItemIdImagesImageTypeGetImageType == null) { + return []; + } + + return itemsItemIdImagesImageTypeGetImageType.map((e) => e.value!).toList(); +} + +List + itemsItemIdImagesImageTypeGetImageTypeListFromJson( + List? itemsItemIdImagesImageTypeGetImageType, [ + List? defaultValue, +]) { + if (itemsItemIdImagesImageTypeGetImageType == null) { + return defaultValue ?? []; + } + + return itemsItemIdImagesImageTypeGetImageType + .map((e) => itemsItemIdImagesImageTypeGetImageTypeFromJson(e.toString())) + .toList(); +} + +List? + itemsItemIdImagesImageTypeGetImageTypeNullableListFromJson( + List? itemsItemIdImagesImageTypeGetImageType, [ + List? defaultValue, +]) { + if (itemsItemIdImagesImageTypeGetImageType == null) { + return defaultValue; + } + + return itemsItemIdImagesImageTypeGetImageType + .map((e) => itemsItemIdImagesImageTypeGetImageTypeFromJson(e.toString())) + .toList(); +} + +String? itemsItemIdImagesImageTypeGetFormatNullableToJson( + enums.ItemsItemIdImagesImageTypeGetFormat? + itemsItemIdImagesImageTypeGetFormat) { + return itemsItemIdImagesImageTypeGetFormat?.value; +} + +String? itemsItemIdImagesImageTypeGetFormatToJson( + enums.ItemsItemIdImagesImageTypeGetFormat + itemsItemIdImagesImageTypeGetFormat) { + return itemsItemIdImagesImageTypeGetFormat.value; +} + +enums.ItemsItemIdImagesImageTypeGetFormat + itemsItemIdImagesImageTypeGetFormatFromJson( + Object? itemsItemIdImagesImageTypeGetFormat, [ + enums.ItemsItemIdImagesImageTypeGetFormat? defaultValue, +]) { + return enums.ItemsItemIdImagesImageTypeGetFormat.values.firstWhereOrNull( + (e) => e.value == itemsItemIdImagesImageTypeGetFormat) ?? + defaultValue ?? + enums.ItemsItemIdImagesImageTypeGetFormat.swaggerGeneratedUnknown; +} + +enums.ItemsItemIdImagesImageTypeGetFormat? + itemsItemIdImagesImageTypeGetFormatNullableFromJson( + Object? itemsItemIdImagesImageTypeGetFormat, [ + enums.ItemsItemIdImagesImageTypeGetFormat? defaultValue, +]) { + if (itemsItemIdImagesImageTypeGetFormat == null) { + return null; + } + return enums.ItemsItemIdImagesImageTypeGetFormat.values.firstWhereOrNull( + (e) => e.value == itemsItemIdImagesImageTypeGetFormat) ?? + defaultValue; +} + +String itemsItemIdImagesImageTypeGetFormatExplodedListToJson( + List? + itemsItemIdImagesImageTypeGetFormat) { + return itemsItemIdImagesImageTypeGetFormat?.map((e) => e.value!).join(',') ?? + ''; +} + +List itemsItemIdImagesImageTypeGetFormatListToJson( + List? + itemsItemIdImagesImageTypeGetFormat) { + if (itemsItemIdImagesImageTypeGetFormat == null) { + return []; + } + + return itemsItemIdImagesImageTypeGetFormat.map((e) => e.value!).toList(); +} + +List + itemsItemIdImagesImageTypeGetFormatListFromJson( + List? itemsItemIdImagesImageTypeGetFormat, [ + List? defaultValue, +]) { + if (itemsItemIdImagesImageTypeGetFormat == null) { + return defaultValue ?? []; + } + + return itemsItemIdImagesImageTypeGetFormat + .map((e) => itemsItemIdImagesImageTypeGetFormatFromJson(e.toString())) + .toList(); +} + +List? + itemsItemIdImagesImageTypeGetFormatNullableListFromJson( + List? itemsItemIdImagesImageTypeGetFormat, [ + List? defaultValue, +]) { + if (itemsItemIdImagesImageTypeGetFormat == null) { + return defaultValue; + } + + return itemsItemIdImagesImageTypeGetFormat + .map((e) => itemsItemIdImagesImageTypeGetFormatFromJson(e.toString())) + .toList(); +} + +String? itemsItemIdImagesImageTypeHeadImageTypeNullableToJson( + enums.ItemsItemIdImagesImageTypeHeadImageType? + itemsItemIdImagesImageTypeHeadImageType) { + return itemsItemIdImagesImageTypeHeadImageType?.value; +} + +String? itemsItemIdImagesImageTypeHeadImageTypeToJson( + enums.ItemsItemIdImagesImageTypeHeadImageType + itemsItemIdImagesImageTypeHeadImageType) { + return itemsItemIdImagesImageTypeHeadImageType.value; +} + +enums.ItemsItemIdImagesImageTypeHeadImageType + itemsItemIdImagesImageTypeHeadImageTypeFromJson( + Object? itemsItemIdImagesImageTypeHeadImageType, [ + enums.ItemsItemIdImagesImageTypeHeadImageType? defaultValue, +]) { + return enums.ItemsItemIdImagesImageTypeHeadImageType.values.firstWhereOrNull( + (e) => e.value == itemsItemIdImagesImageTypeHeadImageType) ?? + defaultValue ?? + enums.ItemsItemIdImagesImageTypeHeadImageType.swaggerGeneratedUnknown; +} + +enums.ItemsItemIdImagesImageTypeHeadImageType? + itemsItemIdImagesImageTypeHeadImageTypeNullableFromJson( + Object? itemsItemIdImagesImageTypeHeadImageType, [ + enums.ItemsItemIdImagesImageTypeHeadImageType? defaultValue, +]) { + if (itemsItemIdImagesImageTypeHeadImageType == null) { + return null; + } + return enums.ItemsItemIdImagesImageTypeHeadImageType.values.firstWhereOrNull( + (e) => e.value == itemsItemIdImagesImageTypeHeadImageType) ?? + defaultValue; +} + +String itemsItemIdImagesImageTypeHeadImageTypeExplodedListToJson( + List? + itemsItemIdImagesImageTypeHeadImageType) { + return itemsItemIdImagesImageTypeHeadImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List itemsItemIdImagesImageTypeHeadImageTypeListToJson( + List? + itemsItemIdImagesImageTypeHeadImageType) { + if (itemsItemIdImagesImageTypeHeadImageType == null) { + return []; + } + + return itemsItemIdImagesImageTypeHeadImageType.map((e) => e.value!).toList(); +} + +List + itemsItemIdImagesImageTypeHeadImageTypeListFromJson( + List? itemsItemIdImagesImageTypeHeadImageType, [ + List? defaultValue, +]) { + if (itemsItemIdImagesImageTypeHeadImageType == null) { + return defaultValue ?? []; + } + + return itemsItemIdImagesImageTypeHeadImageType + .map((e) => itemsItemIdImagesImageTypeHeadImageTypeFromJson(e.toString())) + .toList(); +} + +List? + itemsItemIdImagesImageTypeHeadImageTypeNullableListFromJson( + List? itemsItemIdImagesImageTypeHeadImageType, [ + List? defaultValue, +]) { + if (itemsItemIdImagesImageTypeHeadImageType == null) { + return defaultValue; + } + + return itemsItemIdImagesImageTypeHeadImageType + .map((e) => itemsItemIdImagesImageTypeHeadImageTypeFromJson(e.toString())) + .toList(); +} + +String? itemsItemIdImagesImageTypeHeadFormatNullableToJson( + enums.ItemsItemIdImagesImageTypeHeadFormat? + itemsItemIdImagesImageTypeHeadFormat) { + return itemsItemIdImagesImageTypeHeadFormat?.value; +} + +String? itemsItemIdImagesImageTypeHeadFormatToJson( + enums.ItemsItemIdImagesImageTypeHeadFormat + itemsItemIdImagesImageTypeHeadFormat) { + return itemsItemIdImagesImageTypeHeadFormat.value; +} + +enums.ItemsItemIdImagesImageTypeHeadFormat + itemsItemIdImagesImageTypeHeadFormatFromJson( + Object? itemsItemIdImagesImageTypeHeadFormat, [ + enums.ItemsItemIdImagesImageTypeHeadFormat? defaultValue, +]) { + return enums.ItemsItemIdImagesImageTypeHeadFormat.values.firstWhereOrNull( + (e) => e.value == itemsItemIdImagesImageTypeHeadFormat) ?? + defaultValue ?? + enums.ItemsItemIdImagesImageTypeHeadFormat.swaggerGeneratedUnknown; +} + +enums.ItemsItemIdImagesImageTypeHeadFormat? + itemsItemIdImagesImageTypeHeadFormatNullableFromJson( + Object? itemsItemIdImagesImageTypeHeadFormat, [ + enums.ItemsItemIdImagesImageTypeHeadFormat? defaultValue, +]) { + if (itemsItemIdImagesImageTypeHeadFormat == null) { + return null; + } + return enums.ItemsItemIdImagesImageTypeHeadFormat.values.firstWhereOrNull( + (e) => e.value == itemsItemIdImagesImageTypeHeadFormat) ?? + defaultValue; +} + +String itemsItemIdImagesImageTypeHeadFormatExplodedListToJson( + List? + itemsItemIdImagesImageTypeHeadFormat) { + return itemsItemIdImagesImageTypeHeadFormat?.map((e) => e.value!).join(',') ?? + ''; +} + +List itemsItemIdImagesImageTypeHeadFormatListToJson( + List? + itemsItemIdImagesImageTypeHeadFormat) { + if (itemsItemIdImagesImageTypeHeadFormat == null) { + return []; + } + + return itemsItemIdImagesImageTypeHeadFormat.map((e) => e.value!).toList(); +} + +List + itemsItemIdImagesImageTypeHeadFormatListFromJson( + List? itemsItemIdImagesImageTypeHeadFormat, [ + List? defaultValue, +]) { + if (itemsItemIdImagesImageTypeHeadFormat == null) { + return defaultValue ?? []; + } + + return itemsItemIdImagesImageTypeHeadFormat + .map((e) => itemsItemIdImagesImageTypeHeadFormatFromJson(e.toString())) + .toList(); +} + +List? + itemsItemIdImagesImageTypeHeadFormatNullableListFromJson( + List? itemsItemIdImagesImageTypeHeadFormat, [ + List? defaultValue, +]) { + if (itemsItemIdImagesImageTypeHeadFormat == null) { + return defaultValue; + } + + return itemsItemIdImagesImageTypeHeadFormat + .map((e) => itemsItemIdImagesImageTypeHeadFormatFromJson(e.toString())) + .toList(); +} + +String? itemsItemIdImagesImageTypeImageIndexDeleteImageTypeNullableToJson( + enums.ItemsItemIdImagesImageTypeImageIndexDeleteImageType? + itemsItemIdImagesImageTypeImageIndexDeleteImageType) { + return itemsItemIdImagesImageTypeImageIndexDeleteImageType?.value; +} + +String? itemsItemIdImagesImageTypeImageIndexDeleteImageTypeToJson( + enums.ItemsItemIdImagesImageTypeImageIndexDeleteImageType + itemsItemIdImagesImageTypeImageIndexDeleteImageType) { + return itemsItemIdImagesImageTypeImageIndexDeleteImageType.value; +} + +enums.ItemsItemIdImagesImageTypeImageIndexDeleteImageType + itemsItemIdImagesImageTypeImageIndexDeleteImageTypeFromJson( + Object? itemsItemIdImagesImageTypeImageIndexDeleteImageType, [ + enums.ItemsItemIdImagesImageTypeImageIndexDeleteImageType? defaultValue, +]) { + return enums.ItemsItemIdImagesImageTypeImageIndexDeleteImageType.values + .firstWhereOrNull((e) => + e.value == itemsItemIdImagesImageTypeImageIndexDeleteImageType) ?? + defaultValue ?? + enums.ItemsItemIdImagesImageTypeImageIndexDeleteImageType + .swaggerGeneratedUnknown; +} + +enums.ItemsItemIdImagesImageTypeImageIndexDeleteImageType? + itemsItemIdImagesImageTypeImageIndexDeleteImageTypeNullableFromJson( + Object? itemsItemIdImagesImageTypeImageIndexDeleteImageType, [ + enums.ItemsItemIdImagesImageTypeImageIndexDeleteImageType? defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexDeleteImageType == null) { + return null; + } + return enums.ItemsItemIdImagesImageTypeImageIndexDeleteImageType.values + .firstWhereOrNull((e) => + e.value == itemsItemIdImagesImageTypeImageIndexDeleteImageType) ?? + defaultValue; +} + +String itemsItemIdImagesImageTypeImageIndexDeleteImageTypeExplodedListToJson( + List? + itemsItemIdImagesImageTypeImageIndexDeleteImageType) { + return itemsItemIdImagesImageTypeImageIndexDeleteImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List itemsItemIdImagesImageTypeImageIndexDeleteImageTypeListToJson( + List? + itemsItemIdImagesImageTypeImageIndexDeleteImageType) { + if (itemsItemIdImagesImageTypeImageIndexDeleteImageType == null) { + return []; + } + + return itemsItemIdImagesImageTypeImageIndexDeleteImageType + .map((e) => e.value!) + .toList(); +} + +List + itemsItemIdImagesImageTypeImageIndexDeleteImageTypeListFromJson( + List? itemsItemIdImagesImageTypeImageIndexDeleteImageType, [ + List? defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexDeleteImageType == null) { + return defaultValue ?? []; + } + + return itemsItemIdImagesImageTypeImageIndexDeleteImageType + .map((e) => itemsItemIdImagesImageTypeImageIndexDeleteImageTypeFromJson( + e.toString())) + .toList(); +} + +List? + itemsItemIdImagesImageTypeImageIndexDeleteImageTypeNullableListFromJson( + List? itemsItemIdImagesImageTypeImageIndexDeleteImageType, [ + List? defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexDeleteImageType == null) { + return defaultValue; + } + + return itemsItemIdImagesImageTypeImageIndexDeleteImageType + .map((e) => itemsItemIdImagesImageTypeImageIndexDeleteImageTypeFromJson( + e.toString())) + .toList(); +} + +String? itemsItemIdImagesImageTypeImageIndexPostImageTypeNullableToJson( + enums.ItemsItemIdImagesImageTypeImageIndexPostImageType? + itemsItemIdImagesImageTypeImageIndexPostImageType) { + return itemsItemIdImagesImageTypeImageIndexPostImageType?.value; +} + +String? itemsItemIdImagesImageTypeImageIndexPostImageTypeToJson( + enums.ItemsItemIdImagesImageTypeImageIndexPostImageType + itemsItemIdImagesImageTypeImageIndexPostImageType) { + return itemsItemIdImagesImageTypeImageIndexPostImageType.value; +} + +enums.ItemsItemIdImagesImageTypeImageIndexPostImageType + itemsItemIdImagesImageTypeImageIndexPostImageTypeFromJson( + Object? itemsItemIdImagesImageTypeImageIndexPostImageType, [ + enums.ItemsItemIdImagesImageTypeImageIndexPostImageType? defaultValue, +]) { + return enums.ItemsItemIdImagesImageTypeImageIndexPostImageType.values + .firstWhereOrNull((e) => + e.value == itemsItemIdImagesImageTypeImageIndexPostImageType) ?? + defaultValue ?? + enums.ItemsItemIdImagesImageTypeImageIndexPostImageType + .swaggerGeneratedUnknown; +} + +enums.ItemsItemIdImagesImageTypeImageIndexPostImageType? + itemsItemIdImagesImageTypeImageIndexPostImageTypeNullableFromJson( + Object? itemsItemIdImagesImageTypeImageIndexPostImageType, [ + enums.ItemsItemIdImagesImageTypeImageIndexPostImageType? defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexPostImageType == null) { + return null; + } + return enums.ItemsItemIdImagesImageTypeImageIndexPostImageType.values + .firstWhereOrNull((e) => + e.value == itemsItemIdImagesImageTypeImageIndexPostImageType) ?? + defaultValue; +} + +String itemsItemIdImagesImageTypeImageIndexPostImageTypeExplodedListToJson( + List? + itemsItemIdImagesImageTypeImageIndexPostImageType) { + return itemsItemIdImagesImageTypeImageIndexPostImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List itemsItemIdImagesImageTypeImageIndexPostImageTypeListToJson( + List? + itemsItemIdImagesImageTypeImageIndexPostImageType) { + if (itemsItemIdImagesImageTypeImageIndexPostImageType == null) { + return []; + } + + return itemsItemIdImagesImageTypeImageIndexPostImageType + .map((e) => e.value!) + .toList(); +} + +List + itemsItemIdImagesImageTypeImageIndexPostImageTypeListFromJson( + List? itemsItemIdImagesImageTypeImageIndexPostImageType, [ + List? defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexPostImageType == null) { + return defaultValue ?? []; + } + + return itemsItemIdImagesImageTypeImageIndexPostImageType + .map((e) => itemsItemIdImagesImageTypeImageIndexPostImageTypeFromJson( + e.toString())) + .toList(); +} + +List? + itemsItemIdImagesImageTypeImageIndexPostImageTypeNullableListFromJson( + List? itemsItemIdImagesImageTypeImageIndexPostImageType, [ + List? defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexPostImageType == null) { + return defaultValue; + } + + return itemsItemIdImagesImageTypeImageIndexPostImageType + .map((e) => itemsItemIdImagesImageTypeImageIndexPostImageTypeFromJson( + e.toString())) + .toList(); +} + +String? itemsItemIdImagesImageTypeImageIndexGetImageTypeNullableToJson( + enums.ItemsItemIdImagesImageTypeImageIndexGetImageType? + itemsItemIdImagesImageTypeImageIndexGetImageType) { + return itemsItemIdImagesImageTypeImageIndexGetImageType?.value; +} + +String? itemsItemIdImagesImageTypeImageIndexGetImageTypeToJson( + enums.ItemsItemIdImagesImageTypeImageIndexGetImageType + itemsItemIdImagesImageTypeImageIndexGetImageType) { + return itemsItemIdImagesImageTypeImageIndexGetImageType.value; +} + +enums.ItemsItemIdImagesImageTypeImageIndexGetImageType + itemsItemIdImagesImageTypeImageIndexGetImageTypeFromJson( + Object? itemsItemIdImagesImageTypeImageIndexGetImageType, [ + enums.ItemsItemIdImagesImageTypeImageIndexGetImageType? defaultValue, +]) { + return enums.ItemsItemIdImagesImageTypeImageIndexGetImageType.values + .firstWhereOrNull((e) => + e.value == itemsItemIdImagesImageTypeImageIndexGetImageType) ?? + defaultValue ?? + enums.ItemsItemIdImagesImageTypeImageIndexGetImageType + .swaggerGeneratedUnknown; +} + +enums.ItemsItemIdImagesImageTypeImageIndexGetImageType? + itemsItemIdImagesImageTypeImageIndexGetImageTypeNullableFromJson( + Object? itemsItemIdImagesImageTypeImageIndexGetImageType, [ + enums.ItemsItemIdImagesImageTypeImageIndexGetImageType? defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexGetImageType == null) { + return null; + } + return enums.ItemsItemIdImagesImageTypeImageIndexGetImageType.values + .firstWhereOrNull((e) => + e.value == itemsItemIdImagesImageTypeImageIndexGetImageType) ?? + defaultValue; +} + +String itemsItemIdImagesImageTypeImageIndexGetImageTypeExplodedListToJson( + List? + itemsItemIdImagesImageTypeImageIndexGetImageType) { + return itemsItemIdImagesImageTypeImageIndexGetImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List itemsItemIdImagesImageTypeImageIndexGetImageTypeListToJson( + List? + itemsItemIdImagesImageTypeImageIndexGetImageType) { + if (itemsItemIdImagesImageTypeImageIndexGetImageType == null) { + return []; + } + + return itemsItemIdImagesImageTypeImageIndexGetImageType + .map((e) => e.value!) + .toList(); +} + +List + itemsItemIdImagesImageTypeImageIndexGetImageTypeListFromJson( + List? itemsItemIdImagesImageTypeImageIndexGetImageType, [ + List? defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexGetImageType == null) { + return defaultValue ?? []; + } + + return itemsItemIdImagesImageTypeImageIndexGetImageType + .map((e) => itemsItemIdImagesImageTypeImageIndexGetImageTypeFromJson( + e.toString())) + .toList(); +} + +List? + itemsItemIdImagesImageTypeImageIndexGetImageTypeNullableListFromJson( + List? itemsItemIdImagesImageTypeImageIndexGetImageType, [ + List? defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexGetImageType == null) { + return defaultValue; + } + + return itemsItemIdImagesImageTypeImageIndexGetImageType + .map((e) => itemsItemIdImagesImageTypeImageIndexGetImageTypeFromJson( + e.toString())) + .toList(); +} + +String? itemsItemIdImagesImageTypeImageIndexGetFormatNullableToJson( + enums.ItemsItemIdImagesImageTypeImageIndexGetFormat? + itemsItemIdImagesImageTypeImageIndexGetFormat) { + return itemsItemIdImagesImageTypeImageIndexGetFormat?.value; +} + +String? itemsItemIdImagesImageTypeImageIndexGetFormatToJson( + enums.ItemsItemIdImagesImageTypeImageIndexGetFormat + itemsItemIdImagesImageTypeImageIndexGetFormat) { + return itemsItemIdImagesImageTypeImageIndexGetFormat.value; +} + +enums.ItemsItemIdImagesImageTypeImageIndexGetFormat + itemsItemIdImagesImageTypeImageIndexGetFormatFromJson( + Object? itemsItemIdImagesImageTypeImageIndexGetFormat, [ + enums.ItemsItemIdImagesImageTypeImageIndexGetFormat? defaultValue, +]) { + return enums.ItemsItemIdImagesImageTypeImageIndexGetFormat.values + .firstWhereOrNull((e) => + e.value == itemsItemIdImagesImageTypeImageIndexGetFormat) ?? + defaultValue ?? + enums.ItemsItemIdImagesImageTypeImageIndexGetFormat + .swaggerGeneratedUnknown; +} + +enums.ItemsItemIdImagesImageTypeImageIndexGetFormat? + itemsItemIdImagesImageTypeImageIndexGetFormatNullableFromJson( + Object? itemsItemIdImagesImageTypeImageIndexGetFormat, [ + enums.ItemsItemIdImagesImageTypeImageIndexGetFormat? defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexGetFormat == null) { + return null; + } + return enums.ItemsItemIdImagesImageTypeImageIndexGetFormat.values + .firstWhereOrNull((e) => + e.value == itemsItemIdImagesImageTypeImageIndexGetFormat) ?? + defaultValue; +} + +String itemsItemIdImagesImageTypeImageIndexGetFormatExplodedListToJson( + List? + itemsItemIdImagesImageTypeImageIndexGetFormat) { + return itemsItemIdImagesImageTypeImageIndexGetFormat + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List itemsItemIdImagesImageTypeImageIndexGetFormatListToJson( + List? + itemsItemIdImagesImageTypeImageIndexGetFormat) { + if (itemsItemIdImagesImageTypeImageIndexGetFormat == null) { + return []; + } + + return itemsItemIdImagesImageTypeImageIndexGetFormat + .map((e) => e.value!) + .toList(); +} + +List + itemsItemIdImagesImageTypeImageIndexGetFormatListFromJson( + List? itemsItemIdImagesImageTypeImageIndexGetFormat, [ + List? defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexGetFormat == null) { + return defaultValue ?? []; + } + + return itemsItemIdImagesImageTypeImageIndexGetFormat + .map((e) => + itemsItemIdImagesImageTypeImageIndexGetFormatFromJson(e.toString())) + .toList(); +} + +List? + itemsItemIdImagesImageTypeImageIndexGetFormatNullableListFromJson( + List? itemsItemIdImagesImageTypeImageIndexGetFormat, [ + List? defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexGetFormat == null) { + return defaultValue; + } + + return itemsItemIdImagesImageTypeImageIndexGetFormat + .map((e) => + itemsItemIdImagesImageTypeImageIndexGetFormatFromJson(e.toString())) + .toList(); +} + +String? itemsItemIdImagesImageTypeImageIndexHeadImageTypeNullableToJson( + enums.ItemsItemIdImagesImageTypeImageIndexHeadImageType? + itemsItemIdImagesImageTypeImageIndexHeadImageType) { + return itemsItemIdImagesImageTypeImageIndexHeadImageType?.value; +} + +String? itemsItemIdImagesImageTypeImageIndexHeadImageTypeToJson( + enums.ItemsItemIdImagesImageTypeImageIndexHeadImageType + itemsItemIdImagesImageTypeImageIndexHeadImageType) { + return itemsItemIdImagesImageTypeImageIndexHeadImageType.value; +} + +enums.ItemsItemIdImagesImageTypeImageIndexHeadImageType + itemsItemIdImagesImageTypeImageIndexHeadImageTypeFromJson( + Object? itemsItemIdImagesImageTypeImageIndexHeadImageType, [ + enums.ItemsItemIdImagesImageTypeImageIndexHeadImageType? defaultValue, +]) { + return enums.ItemsItemIdImagesImageTypeImageIndexHeadImageType.values + .firstWhereOrNull((e) => + e.value == itemsItemIdImagesImageTypeImageIndexHeadImageType) ?? + defaultValue ?? + enums.ItemsItemIdImagesImageTypeImageIndexHeadImageType + .swaggerGeneratedUnknown; +} + +enums.ItemsItemIdImagesImageTypeImageIndexHeadImageType? + itemsItemIdImagesImageTypeImageIndexHeadImageTypeNullableFromJson( + Object? itemsItemIdImagesImageTypeImageIndexHeadImageType, [ + enums.ItemsItemIdImagesImageTypeImageIndexHeadImageType? defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexHeadImageType == null) { + return null; + } + return enums.ItemsItemIdImagesImageTypeImageIndexHeadImageType.values + .firstWhereOrNull((e) => + e.value == itemsItemIdImagesImageTypeImageIndexHeadImageType) ?? + defaultValue; +} + +String itemsItemIdImagesImageTypeImageIndexHeadImageTypeExplodedListToJson( + List? + itemsItemIdImagesImageTypeImageIndexHeadImageType) { + return itemsItemIdImagesImageTypeImageIndexHeadImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List itemsItemIdImagesImageTypeImageIndexHeadImageTypeListToJson( + List? + itemsItemIdImagesImageTypeImageIndexHeadImageType) { + if (itemsItemIdImagesImageTypeImageIndexHeadImageType == null) { + return []; + } + + return itemsItemIdImagesImageTypeImageIndexHeadImageType + .map((e) => e.value!) + .toList(); +} + +List + itemsItemIdImagesImageTypeImageIndexHeadImageTypeListFromJson( + List? itemsItemIdImagesImageTypeImageIndexHeadImageType, [ + List? defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexHeadImageType == null) { + return defaultValue ?? []; + } + + return itemsItemIdImagesImageTypeImageIndexHeadImageType + .map((e) => itemsItemIdImagesImageTypeImageIndexHeadImageTypeFromJson( + e.toString())) + .toList(); +} + +List? + itemsItemIdImagesImageTypeImageIndexHeadImageTypeNullableListFromJson( + List? itemsItemIdImagesImageTypeImageIndexHeadImageType, [ + List? defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexHeadImageType == null) { + return defaultValue; + } + + return itemsItemIdImagesImageTypeImageIndexHeadImageType + .map((e) => itemsItemIdImagesImageTypeImageIndexHeadImageTypeFromJson( + e.toString())) + .toList(); +} + +String? itemsItemIdImagesImageTypeImageIndexHeadFormatNullableToJson( + enums.ItemsItemIdImagesImageTypeImageIndexHeadFormat? + itemsItemIdImagesImageTypeImageIndexHeadFormat) { + return itemsItemIdImagesImageTypeImageIndexHeadFormat?.value; +} + +String? itemsItemIdImagesImageTypeImageIndexHeadFormatToJson( + enums.ItemsItemIdImagesImageTypeImageIndexHeadFormat + itemsItemIdImagesImageTypeImageIndexHeadFormat) { + return itemsItemIdImagesImageTypeImageIndexHeadFormat.value; +} + +enums.ItemsItemIdImagesImageTypeImageIndexHeadFormat + itemsItemIdImagesImageTypeImageIndexHeadFormatFromJson( + Object? itemsItemIdImagesImageTypeImageIndexHeadFormat, [ + enums.ItemsItemIdImagesImageTypeImageIndexHeadFormat? defaultValue, +]) { + return enums.ItemsItemIdImagesImageTypeImageIndexHeadFormat.values + .firstWhereOrNull((e) => + e.value == itemsItemIdImagesImageTypeImageIndexHeadFormat) ?? + defaultValue ?? + enums.ItemsItemIdImagesImageTypeImageIndexHeadFormat + .swaggerGeneratedUnknown; +} + +enums.ItemsItemIdImagesImageTypeImageIndexHeadFormat? + itemsItemIdImagesImageTypeImageIndexHeadFormatNullableFromJson( + Object? itemsItemIdImagesImageTypeImageIndexHeadFormat, [ + enums.ItemsItemIdImagesImageTypeImageIndexHeadFormat? defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexHeadFormat == null) { + return null; + } + return enums.ItemsItemIdImagesImageTypeImageIndexHeadFormat.values + .firstWhereOrNull((e) => + e.value == itemsItemIdImagesImageTypeImageIndexHeadFormat) ?? + defaultValue; +} + +String itemsItemIdImagesImageTypeImageIndexHeadFormatExplodedListToJson( + List? + itemsItemIdImagesImageTypeImageIndexHeadFormat) { + return itemsItemIdImagesImageTypeImageIndexHeadFormat + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List itemsItemIdImagesImageTypeImageIndexHeadFormatListToJson( + List? + itemsItemIdImagesImageTypeImageIndexHeadFormat) { + if (itemsItemIdImagesImageTypeImageIndexHeadFormat == null) { + return []; + } + + return itemsItemIdImagesImageTypeImageIndexHeadFormat + .map((e) => e.value!) + .toList(); +} + +List + itemsItemIdImagesImageTypeImageIndexHeadFormatListFromJson( + List? itemsItemIdImagesImageTypeImageIndexHeadFormat, [ + List? defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexHeadFormat == null) { + return defaultValue ?? []; + } + + return itemsItemIdImagesImageTypeImageIndexHeadFormat + .map((e) => + itemsItemIdImagesImageTypeImageIndexHeadFormatFromJson(e.toString())) + .toList(); +} + +List? + itemsItemIdImagesImageTypeImageIndexHeadFormatNullableListFromJson( + List? itemsItemIdImagesImageTypeImageIndexHeadFormat, [ + List? defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexHeadFormat == null) { + return defaultValue; + } + + return itemsItemIdImagesImageTypeImageIndexHeadFormat + .map((e) => + itemsItemIdImagesImageTypeImageIndexHeadFormatFromJson(e.toString())) + .toList(); +} + +String? itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageTypeNullableToJson( + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType) { + return itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType + ?.value; +} + +String? itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageTypeToJson( + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType) { + return itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType + .value; +} + +enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageTypeFromJson( + Object? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType, [ + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType? + defaultValue, +]) { + return enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType + .values + .firstWhereOrNull((e) => + e.value == + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType) ?? + defaultValue ?? + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType + .swaggerGeneratedUnknown; +} + +enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageTypeNullableFromJson( + Object? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType, [ + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType? + defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType == + null) { + return null; + } + return enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType + .values + .firstWhereOrNull((e) => + e.value == + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType) ?? + defaultValue; +} + +String itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageTypeExplodedListToJson( + List< + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType>? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType) { + return itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageTypeListToJson( + List< + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType>? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType) { + if (itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType == + null) { + return []; + } + + return itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType + .map((e) => e.value!) + .toList(); +} + +List< + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType> + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageTypeListFromJson( + List? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType, [ + List< + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType>? + defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType == + null) { + return defaultValue ?? []; + } + + return itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType + .map((e) => + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageTypeFromJson( + e.toString())) + .toList(); +} + +List< + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType>? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageTypeNullableListFromJson( + List? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType, [ + List< + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType>? + defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType == + null) { + return defaultValue; + } + + return itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageType + .map((e) => + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetImageTypeFromJson( + e.toString())) + .toList(); +} + +String? itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormatNullableToJson( + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat) { + return itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat + ?.value; +} + +String? itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormatToJson( + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat) { + return itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat + .value; +} + +enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormatFromJson( + Object? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat, [ + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat? + defaultValue, +]) { + return enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat + .values + .firstWhereOrNull((e) => + e.value == + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat) ?? + defaultValue ?? + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat + .swaggerGeneratedUnknown; +} + +enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormatNullableFromJson( + Object? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat, [ + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat? + defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat == + null) { + return null; + } + return enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat + .values + .firstWhereOrNull((e) => + e.value == + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat) ?? + defaultValue; +} + +String itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormatExplodedListToJson( + List< + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat>? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat) { + return itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormatListToJson( + List< + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat>? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat) { + if (itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat == + null) { + return []; + } + + return itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat + .map((e) => e.value!) + .toList(); +} + +List< + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat> + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormatListFromJson( + List? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat, [ + List< + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat>? + defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat == + null) { + return defaultValue ?? []; + } + + return itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat + .map((e) => + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormatFromJson( + e.toString())) + .toList(); +} + +List< + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat>? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormatNullableListFromJson( + List? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat, [ + List< + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat>? + defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat == + null) { + return defaultValue; + } + + return itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormat + .map((e) => + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountGetFormatFromJson( + e.toString())) + .toList(); +} + +String? itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageTypeNullableToJson( + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType) { + return itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType + ?.value; +} + +String? itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageTypeToJson( + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType) { + return itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType + .value; +} + +enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageTypeFromJson( + Object? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType, [ + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType? + defaultValue, +]) { + return enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType + .values + .firstWhereOrNull((e) => + e.value == + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType) ?? + defaultValue ?? + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType + .swaggerGeneratedUnknown; +} + +enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageTypeNullableFromJson( + Object? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType, [ + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType? + defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType == + null) { + return null; + } + return enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType + .values + .firstWhereOrNull((e) => + e.value == + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType) ?? + defaultValue; +} + +String itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageTypeExplodedListToJson( + List< + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType>? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType) { + return itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageTypeListToJson( + List< + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType>? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType) { + if (itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType == + null) { + return []; + } + + return itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType + .map((e) => e.value!) + .toList(); +} + +List< + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType> + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageTypeListFromJson( + List? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType, [ + List< + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType>? + defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType == + null) { + return defaultValue ?? []; + } + + return itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType + .map((e) => + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageTypeFromJson( + e.toString())) + .toList(); +} + +List< + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType>? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageTypeNullableListFromJson( + List? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType, [ + List< + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType>? + defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType == + null) { + return defaultValue; + } + + return itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageType + .map((e) => + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadImageTypeFromJson( + e.toString())) + .toList(); +} + +String? itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormatNullableToJson( + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat) { + return itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat + ?.value; +} + +String? itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormatToJson( + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat) { + return itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat + .value; +} + +enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormatFromJson( + Object? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat, [ + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat? + defaultValue, +]) { + return enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat + .values + .firstWhereOrNull((e) => + e.value == + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat) ?? + defaultValue ?? + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat + .swaggerGeneratedUnknown; +} + +enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormatNullableFromJson( + Object? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat, [ + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat? + defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat == + null) { + return null; + } + return enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat + .values + .firstWhereOrNull((e) => + e.value == + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat) ?? + defaultValue; +} + +String itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormatExplodedListToJson( + List< + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat>? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat) { + return itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormatListToJson( + List< + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat>? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat) { + if (itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat == + null) { + return []; + } + + return itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat + .map((e) => e.value!) + .toList(); +} + +List< + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat> + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormatListFromJson( + List? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat, [ + List< + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat>? + defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat == + null) { + return defaultValue ?? []; + } + + return itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat + .map((e) => + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormatFromJson( + e.toString())) + .toList(); +} + +List< + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat>? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormatNullableListFromJson( + List? + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat, [ + List< + enums + .ItemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat>? + defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat == + null) { + return defaultValue; + } + + return itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormat + .map((e) => + itemsItemIdImagesImageTypeImageIndexTagFormatMaxWidthMaxHeightPercentPlayedUnplayedCountHeadFormatFromJson( + e.toString())) + .toList(); +} + +String? itemsItemIdImagesImageTypeImageIndexIndexPostImageTypeNullableToJson( + enums.ItemsItemIdImagesImageTypeImageIndexIndexPostImageType? + itemsItemIdImagesImageTypeImageIndexIndexPostImageType) { + return itemsItemIdImagesImageTypeImageIndexIndexPostImageType?.value; +} + +String? itemsItemIdImagesImageTypeImageIndexIndexPostImageTypeToJson( + enums.ItemsItemIdImagesImageTypeImageIndexIndexPostImageType + itemsItemIdImagesImageTypeImageIndexIndexPostImageType) { + return itemsItemIdImagesImageTypeImageIndexIndexPostImageType.value; +} + +enums.ItemsItemIdImagesImageTypeImageIndexIndexPostImageType + itemsItemIdImagesImageTypeImageIndexIndexPostImageTypeFromJson( + Object? itemsItemIdImagesImageTypeImageIndexIndexPostImageType, [ + enums.ItemsItemIdImagesImageTypeImageIndexIndexPostImageType? defaultValue, +]) { + return enums.ItemsItemIdImagesImageTypeImageIndexIndexPostImageType.values + .firstWhereOrNull((e) => + e.value == + itemsItemIdImagesImageTypeImageIndexIndexPostImageType) ?? + defaultValue ?? + enums.ItemsItemIdImagesImageTypeImageIndexIndexPostImageType + .swaggerGeneratedUnknown; +} + +enums.ItemsItemIdImagesImageTypeImageIndexIndexPostImageType? + itemsItemIdImagesImageTypeImageIndexIndexPostImageTypeNullableFromJson( + Object? itemsItemIdImagesImageTypeImageIndexIndexPostImageType, [ + enums.ItemsItemIdImagesImageTypeImageIndexIndexPostImageType? defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexIndexPostImageType == null) { + return null; + } + return enums.ItemsItemIdImagesImageTypeImageIndexIndexPostImageType.values + .firstWhereOrNull((e) => + e.value == + itemsItemIdImagesImageTypeImageIndexIndexPostImageType) ?? + defaultValue; +} + +String itemsItemIdImagesImageTypeImageIndexIndexPostImageTypeExplodedListToJson( + List? + itemsItemIdImagesImageTypeImageIndexIndexPostImageType) { + return itemsItemIdImagesImageTypeImageIndexIndexPostImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List itemsItemIdImagesImageTypeImageIndexIndexPostImageTypeListToJson( + List? + itemsItemIdImagesImageTypeImageIndexIndexPostImageType) { + if (itemsItemIdImagesImageTypeImageIndexIndexPostImageType == null) { + return []; + } + + return itemsItemIdImagesImageTypeImageIndexIndexPostImageType + .map((e) => e.value!) + .toList(); +} + +List + itemsItemIdImagesImageTypeImageIndexIndexPostImageTypeListFromJson( + List? itemsItemIdImagesImageTypeImageIndexIndexPostImageType, [ + List? + defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexIndexPostImageType == null) { + return defaultValue ?? []; + } + + return itemsItemIdImagesImageTypeImageIndexIndexPostImageType + .map((e) => + itemsItemIdImagesImageTypeImageIndexIndexPostImageTypeFromJson( + e.toString())) + .toList(); +} + +List? + itemsItemIdImagesImageTypeImageIndexIndexPostImageTypeNullableListFromJson( + List? itemsItemIdImagesImageTypeImageIndexIndexPostImageType, [ + List? + defaultValue, +]) { + if (itemsItemIdImagesImageTypeImageIndexIndexPostImageType == null) { + return defaultValue; + } + + return itemsItemIdImagesImageTypeImageIndexIndexPostImageType + .map((e) => + itemsItemIdImagesImageTypeImageIndexIndexPostImageTypeFromJson( + e.toString())) + .toList(); +} + +String? musicGenresNameImagesImageTypeGetImageTypeNullableToJson( + enums.MusicGenresNameImagesImageTypeGetImageType? + musicGenresNameImagesImageTypeGetImageType) { + return musicGenresNameImagesImageTypeGetImageType?.value; +} + +String? musicGenresNameImagesImageTypeGetImageTypeToJson( + enums.MusicGenresNameImagesImageTypeGetImageType + musicGenresNameImagesImageTypeGetImageType) { + return musicGenresNameImagesImageTypeGetImageType.value; +} + +enums.MusicGenresNameImagesImageTypeGetImageType + musicGenresNameImagesImageTypeGetImageTypeFromJson( + Object? musicGenresNameImagesImageTypeGetImageType, [ + enums.MusicGenresNameImagesImageTypeGetImageType? defaultValue, +]) { + return enums.MusicGenresNameImagesImageTypeGetImageType.values + .firstWhereOrNull( + (e) => e.value == musicGenresNameImagesImageTypeGetImageType) ?? + defaultValue ?? + enums.MusicGenresNameImagesImageTypeGetImageType.swaggerGeneratedUnknown; +} + +enums.MusicGenresNameImagesImageTypeGetImageType? + musicGenresNameImagesImageTypeGetImageTypeNullableFromJson( + Object? musicGenresNameImagesImageTypeGetImageType, [ + enums.MusicGenresNameImagesImageTypeGetImageType? defaultValue, +]) { + if (musicGenresNameImagesImageTypeGetImageType == null) { + return null; + } + return enums.MusicGenresNameImagesImageTypeGetImageType.values + .firstWhereOrNull( + (e) => e.value == musicGenresNameImagesImageTypeGetImageType) ?? + defaultValue; +} + +String musicGenresNameImagesImageTypeGetImageTypeExplodedListToJson( + List? + musicGenresNameImagesImageTypeGetImageType) { + return musicGenresNameImagesImageTypeGetImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List musicGenresNameImagesImageTypeGetImageTypeListToJson( + List? + musicGenresNameImagesImageTypeGetImageType) { + if (musicGenresNameImagesImageTypeGetImageType == null) { + return []; + } + + return musicGenresNameImagesImageTypeGetImageType + .map((e) => e.value!) + .toList(); +} + +List + musicGenresNameImagesImageTypeGetImageTypeListFromJson( + List? musicGenresNameImagesImageTypeGetImageType, [ + List? defaultValue, +]) { + if (musicGenresNameImagesImageTypeGetImageType == null) { + return defaultValue ?? []; + } + + return musicGenresNameImagesImageTypeGetImageType + .map((e) => + musicGenresNameImagesImageTypeGetImageTypeFromJson(e.toString())) + .toList(); +} + +List? + musicGenresNameImagesImageTypeGetImageTypeNullableListFromJson( + List? musicGenresNameImagesImageTypeGetImageType, [ + List? defaultValue, +]) { + if (musicGenresNameImagesImageTypeGetImageType == null) { + return defaultValue; + } + + return musicGenresNameImagesImageTypeGetImageType + .map((e) => + musicGenresNameImagesImageTypeGetImageTypeFromJson(e.toString())) + .toList(); +} + +String? musicGenresNameImagesImageTypeGetFormatNullableToJson( + enums.MusicGenresNameImagesImageTypeGetFormat? + musicGenresNameImagesImageTypeGetFormat) { + return musicGenresNameImagesImageTypeGetFormat?.value; +} + +String? musicGenresNameImagesImageTypeGetFormatToJson( + enums.MusicGenresNameImagesImageTypeGetFormat + musicGenresNameImagesImageTypeGetFormat) { + return musicGenresNameImagesImageTypeGetFormat.value; +} + +enums.MusicGenresNameImagesImageTypeGetFormat + musicGenresNameImagesImageTypeGetFormatFromJson( + Object? musicGenresNameImagesImageTypeGetFormat, [ + enums.MusicGenresNameImagesImageTypeGetFormat? defaultValue, +]) { + return enums.MusicGenresNameImagesImageTypeGetFormat.values.firstWhereOrNull( + (e) => e.value == musicGenresNameImagesImageTypeGetFormat) ?? + defaultValue ?? + enums.MusicGenresNameImagesImageTypeGetFormat.swaggerGeneratedUnknown; +} + +enums.MusicGenresNameImagesImageTypeGetFormat? + musicGenresNameImagesImageTypeGetFormatNullableFromJson( + Object? musicGenresNameImagesImageTypeGetFormat, [ + enums.MusicGenresNameImagesImageTypeGetFormat? defaultValue, +]) { + if (musicGenresNameImagesImageTypeGetFormat == null) { + return null; + } + return enums.MusicGenresNameImagesImageTypeGetFormat.values.firstWhereOrNull( + (e) => e.value == musicGenresNameImagesImageTypeGetFormat) ?? + defaultValue; +} + +String musicGenresNameImagesImageTypeGetFormatExplodedListToJson( + List? + musicGenresNameImagesImageTypeGetFormat) { + return musicGenresNameImagesImageTypeGetFormat + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List musicGenresNameImagesImageTypeGetFormatListToJson( + List? + musicGenresNameImagesImageTypeGetFormat) { + if (musicGenresNameImagesImageTypeGetFormat == null) { + return []; + } + + return musicGenresNameImagesImageTypeGetFormat.map((e) => e.value!).toList(); +} + +List + musicGenresNameImagesImageTypeGetFormatListFromJson( + List? musicGenresNameImagesImageTypeGetFormat, [ + List? defaultValue, +]) { + if (musicGenresNameImagesImageTypeGetFormat == null) { + return defaultValue ?? []; + } + + return musicGenresNameImagesImageTypeGetFormat + .map((e) => musicGenresNameImagesImageTypeGetFormatFromJson(e.toString())) + .toList(); +} + +List? + musicGenresNameImagesImageTypeGetFormatNullableListFromJson( + List? musicGenresNameImagesImageTypeGetFormat, [ + List? defaultValue, +]) { + if (musicGenresNameImagesImageTypeGetFormat == null) { + return defaultValue; + } + + return musicGenresNameImagesImageTypeGetFormat + .map((e) => musicGenresNameImagesImageTypeGetFormatFromJson(e.toString())) + .toList(); +} + +String? musicGenresNameImagesImageTypeHeadImageTypeNullableToJson( + enums.MusicGenresNameImagesImageTypeHeadImageType? + musicGenresNameImagesImageTypeHeadImageType) { + return musicGenresNameImagesImageTypeHeadImageType?.value; +} + +String? musicGenresNameImagesImageTypeHeadImageTypeToJson( + enums.MusicGenresNameImagesImageTypeHeadImageType + musicGenresNameImagesImageTypeHeadImageType) { + return musicGenresNameImagesImageTypeHeadImageType.value; +} + +enums.MusicGenresNameImagesImageTypeHeadImageType + musicGenresNameImagesImageTypeHeadImageTypeFromJson( + Object? musicGenresNameImagesImageTypeHeadImageType, [ + enums.MusicGenresNameImagesImageTypeHeadImageType? defaultValue, +]) { + return enums.MusicGenresNameImagesImageTypeHeadImageType.values + .firstWhereOrNull( + (e) => e.value == musicGenresNameImagesImageTypeHeadImageType) ?? + defaultValue ?? + enums.MusicGenresNameImagesImageTypeHeadImageType.swaggerGeneratedUnknown; +} + +enums.MusicGenresNameImagesImageTypeHeadImageType? + musicGenresNameImagesImageTypeHeadImageTypeNullableFromJson( + Object? musicGenresNameImagesImageTypeHeadImageType, [ + enums.MusicGenresNameImagesImageTypeHeadImageType? defaultValue, +]) { + if (musicGenresNameImagesImageTypeHeadImageType == null) { + return null; + } + return enums.MusicGenresNameImagesImageTypeHeadImageType.values + .firstWhereOrNull( + (e) => e.value == musicGenresNameImagesImageTypeHeadImageType) ?? + defaultValue; +} + +String musicGenresNameImagesImageTypeHeadImageTypeExplodedListToJson( + List? + musicGenresNameImagesImageTypeHeadImageType) { + return musicGenresNameImagesImageTypeHeadImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List musicGenresNameImagesImageTypeHeadImageTypeListToJson( + List? + musicGenresNameImagesImageTypeHeadImageType) { + if (musicGenresNameImagesImageTypeHeadImageType == null) { + return []; + } + + return musicGenresNameImagesImageTypeHeadImageType + .map((e) => e.value!) + .toList(); +} + +List + musicGenresNameImagesImageTypeHeadImageTypeListFromJson( + List? musicGenresNameImagesImageTypeHeadImageType, [ + List? defaultValue, +]) { + if (musicGenresNameImagesImageTypeHeadImageType == null) { + return defaultValue ?? []; + } + + return musicGenresNameImagesImageTypeHeadImageType + .map((e) => + musicGenresNameImagesImageTypeHeadImageTypeFromJson(e.toString())) + .toList(); +} + +List? + musicGenresNameImagesImageTypeHeadImageTypeNullableListFromJson( + List? musicGenresNameImagesImageTypeHeadImageType, [ + List? defaultValue, +]) { + if (musicGenresNameImagesImageTypeHeadImageType == null) { + return defaultValue; + } + + return musicGenresNameImagesImageTypeHeadImageType + .map((e) => + musicGenresNameImagesImageTypeHeadImageTypeFromJson(e.toString())) + .toList(); +} + +String? musicGenresNameImagesImageTypeHeadFormatNullableToJson( + enums.MusicGenresNameImagesImageTypeHeadFormat? + musicGenresNameImagesImageTypeHeadFormat) { + return musicGenresNameImagesImageTypeHeadFormat?.value; +} + +String? musicGenresNameImagesImageTypeHeadFormatToJson( + enums.MusicGenresNameImagesImageTypeHeadFormat + musicGenresNameImagesImageTypeHeadFormat) { + return musicGenresNameImagesImageTypeHeadFormat.value; +} + +enums.MusicGenresNameImagesImageTypeHeadFormat + musicGenresNameImagesImageTypeHeadFormatFromJson( + Object? musicGenresNameImagesImageTypeHeadFormat, [ + enums.MusicGenresNameImagesImageTypeHeadFormat? defaultValue, +]) { + return enums.MusicGenresNameImagesImageTypeHeadFormat.values.firstWhereOrNull( + (e) => e.value == musicGenresNameImagesImageTypeHeadFormat) ?? + defaultValue ?? + enums.MusicGenresNameImagesImageTypeHeadFormat.swaggerGeneratedUnknown; +} + +enums.MusicGenresNameImagesImageTypeHeadFormat? + musicGenresNameImagesImageTypeHeadFormatNullableFromJson( + Object? musicGenresNameImagesImageTypeHeadFormat, [ + enums.MusicGenresNameImagesImageTypeHeadFormat? defaultValue, +]) { + if (musicGenresNameImagesImageTypeHeadFormat == null) { + return null; + } + return enums.MusicGenresNameImagesImageTypeHeadFormat.values.firstWhereOrNull( + (e) => e.value == musicGenresNameImagesImageTypeHeadFormat) ?? + defaultValue; +} + +String musicGenresNameImagesImageTypeHeadFormatExplodedListToJson( + List? + musicGenresNameImagesImageTypeHeadFormat) { + return musicGenresNameImagesImageTypeHeadFormat + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List musicGenresNameImagesImageTypeHeadFormatListToJson( + List? + musicGenresNameImagesImageTypeHeadFormat) { + if (musicGenresNameImagesImageTypeHeadFormat == null) { + return []; + } + + return musicGenresNameImagesImageTypeHeadFormat.map((e) => e.value!).toList(); +} + +List + musicGenresNameImagesImageTypeHeadFormatListFromJson( + List? musicGenresNameImagesImageTypeHeadFormat, [ + List? defaultValue, +]) { + if (musicGenresNameImagesImageTypeHeadFormat == null) { + return defaultValue ?? []; + } + + return musicGenresNameImagesImageTypeHeadFormat + .map( + (e) => musicGenresNameImagesImageTypeHeadFormatFromJson(e.toString())) + .toList(); +} + +List? + musicGenresNameImagesImageTypeHeadFormatNullableListFromJson( + List? musicGenresNameImagesImageTypeHeadFormat, [ + List? defaultValue, +]) { + if (musicGenresNameImagesImageTypeHeadFormat == null) { + return defaultValue; + } + + return musicGenresNameImagesImageTypeHeadFormat + .map( + (e) => musicGenresNameImagesImageTypeHeadFormatFromJson(e.toString())) + .toList(); +} + +String? musicGenresNameImagesImageTypeImageIndexGetImageTypeNullableToJson( + enums.MusicGenresNameImagesImageTypeImageIndexGetImageType? + musicGenresNameImagesImageTypeImageIndexGetImageType) { + return musicGenresNameImagesImageTypeImageIndexGetImageType?.value; +} + +String? musicGenresNameImagesImageTypeImageIndexGetImageTypeToJson( + enums.MusicGenresNameImagesImageTypeImageIndexGetImageType + musicGenresNameImagesImageTypeImageIndexGetImageType) { + return musicGenresNameImagesImageTypeImageIndexGetImageType.value; +} + +enums.MusicGenresNameImagesImageTypeImageIndexGetImageType + musicGenresNameImagesImageTypeImageIndexGetImageTypeFromJson( + Object? musicGenresNameImagesImageTypeImageIndexGetImageType, [ + enums.MusicGenresNameImagesImageTypeImageIndexGetImageType? defaultValue, +]) { + return enums.MusicGenresNameImagesImageTypeImageIndexGetImageType.values + .firstWhereOrNull((e) => + e.value == + musicGenresNameImagesImageTypeImageIndexGetImageType) ?? + defaultValue ?? + enums.MusicGenresNameImagesImageTypeImageIndexGetImageType + .swaggerGeneratedUnknown; +} + +enums.MusicGenresNameImagesImageTypeImageIndexGetImageType? + musicGenresNameImagesImageTypeImageIndexGetImageTypeNullableFromJson( + Object? musicGenresNameImagesImageTypeImageIndexGetImageType, [ + enums.MusicGenresNameImagesImageTypeImageIndexGetImageType? defaultValue, +]) { + if (musicGenresNameImagesImageTypeImageIndexGetImageType == null) { + return null; + } + return enums.MusicGenresNameImagesImageTypeImageIndexGetImageType.values + .firstWhereOrNull((e) => + e.value == + musicGenresNameImagesImageTypeImageIndexGetImageType) ?? + defaultValue; +} + +String musicGenresNameImagesImageTypeImageIndexGetImageTypeExplodedListToJson( + List? + musicGenresNameImagesImageTypeImageIndexGetImageType) { + return musicGenresNameImagesImageTypeImageIndexGetImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List musicGenresNameImagesImageTypeImageIndexGetImageTypeListToJson( + List? + musicGenresNameImagesImageTypeImageIndexGetImageType) { + if (musicGenresNameImagesImageTypeImageIndexGetImageType == null) { + return []; + } + + return musicGenresNameImagesImageTypeImageIndexGetImageType + .map((e) => e.value!) + .toList(); +} + +List + musicGenresNameImagesImageTypeImageIndexGetImageTypeListFromJson( + List? musicGenresNameImagesImageTypeImageIndexGetImageType, [ + List? + defaultValue, +]) { + if (musicGenresNameImagesImageTypeImageIndexGetImageType == null) { + return defaultValue ?? []; + } + + return musicGenresNameImagesImageTypeImageIndexGetImageType + .map((e) => musicGenresNameImagesImageTypeImageIndexGetImageTypeFromJson( + e.toString())) + .toList(); +} + +List? + musicGenresNameImagesImageTypeImageIndexGetImageTypeNullableListFromJson( + List? musicGenresNameImagesImageTypeImageIndexGetImageType, [ + List? + defaultValue, +]) { + if (musicGenresNameImagesImageTypeImageIndexGetImageType == null) { + return defaultValue; + } + + return musicGenresNameImagesImageTypeImageIndexGetImageType + .map((e) => musicGenresNameImagesImageTypeImageIndexGetImageTypeFromJson( + e.toString())) + .toList(); +} + +String? musicGenresNameImagesImageTypeImageIndexGetFormatNullableToJson( + enums.MusicGenresNameImagesImageTypeImageIndexGetFormat? + musicGenresNameImagesImageTypeImageIndexGetFormat) { + return musicGenresNameImagesImageTypeImageIndexGetFormat?.value; +} + +String? musicGenresNameImagesImageTypeImageIndexGetFormatToJson( + enums.MusicGenresNameImagesImageTypeImageIndexGetFormat + musicGenresNameImagesImageTypeImageIndexGetFormat) { + return musicGenresNameImagesImageTypeImageIndexGetFormat.value; +} + +enums.MusicGenresNameImagesImageTypeImageIndexGetFormat + musicGenresNameImagesImageTypeImageIndexGetFormatFromJson( + Object? musicGenresNameImagesImageTypeImageIndexGetFormat, [ + enums.MusicGenresNameImagesImageTypeImageIndexGetFormat? defaultValue, +]) { + return enums.MusicGenresNameImagesImageTypeImageIndexGetFormat.values + .firstWhereOrNull((e) => + e.value == musicGenresNameImagesImageTypeImageIndexGetFormat) ?? + defaultValue ?? + enums.MusicGenresNameImagesImageTypeImageIndexGetFormat + .swaggerGeneratedUnknown; +} + +enums.MusicGenresNameImagesImageTypeImageIndexGetFormat? + musicGenresNameImagesImageTypeImageIndexGetFormatNullableFromJson( + Object? musicGenresNameImagesImageTypeImageIndexGetFormat, [ + enums.MusicGenresNameImagesImageTypeImageIndexGetFormat? defaultValue, +]) { + if (musicGenresNameImagesImageTypeImageIndexGetFormat == null) { + return null; + } + return enums.MusicGenresNameImagesImageTypeImageIndexGetFormat.values + .firstWhereOrNull((e) => + e.value == musicGenresNameImagesImageTypeImageIndexGetFormat) ?? + defaultValue; +} + +String musicGenresNameImagesImageTypeImageIndexGetFormatExplodedListToJson( + List? + musicGenresNameImagesImageTypeImageIndexGetFormat) { + return musicGenresNameImagesImageTypeImageIndexGetFormat + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List musicGenresNameImagesImageTypeImageIndexGetFormatListToJson( + List? + musicGenresNameImagesImageTypeImageIndexGetFormat) { + if (musicGenresNameImagesImageTypeImageIndexGetFormat == null) { + return []; + } + + return musicGenresNameImagesImageTypeImageIndexGetFormat + .map((e) => e.value!) + .toList(); +} + +List + musicGenresNameImagesImageTypeImageIndexGetFormatListFromJson( + List? musicGenresNameImagesImageTypeImageIndexGetFormat, [ + List? defaultValue, +]) { + if (musicGenresNameImagesImageTypeImageIndexGetFormat == null) { + return defaultValue ?? []; + } + + return musicGenresNameImagesImageTypeImageIndexGetFormat + .map((e) => musicGenresNameImagesImageTypeImageIndexGetFormatFromJson( + e.toString())) + .toList(); +} + +List? + musicGenresNameImagesImageTypeImageIndexGetFormatNullableListFromJson( + List? musicGenresNameImagesImageTypeImageIndexGetFormat, [ + List? defaultValue, +]) { + if (musicGenresNameImagesImageTypeImageIndexGetFormat == null) { + return defaultValue; + } + + return musicGenresNameImagesImageTypeImageIndexGetFormat + .map((e) => musicGenresNameImagesImageTypeImageIndexGetFormatFromJson( + e.toString())) + .toList(); +} + +String? musicGenresNameImagesImageTypeImageIndexHeadImageTypeNullableToJson( + enums.MusicGenresNameImagesImageTypeImageIndexHeadImageType? + musicGenresNameImagesImageTypeImageIndexHeadImageType) { + return musicGenresNameImagesImageTypeImageIndexHeadImageType?.value; +} + +String? musicGenresNameImagesImageTypeImageIndexHeadImageTypeToJson( + enums.MusicGenresNameImagesImageTypeImageIndexHeadImageType + musicGenresNameImagesImageTypeImageIndexHeadImageType) { + return musicGenresNameImagesImageTypeImageIndexHeadImageType.value; +} + +enums.MusicGenresNameImagesImageTypeImageIndexHeadImageType + musicGenresNameImagesImageTypeImageIndexHeadImageTypeFromJson( + Object? musicGenresNameImagesImageTypeImageIndexHeadImageType, [ + enums.MusicGenresNameImagesImageTypeImageIndexHeadImageType? defaultValue, +]) { + return enums.MusicGenresNameImagesImageTypeImageIndexHeadImageType.values + .firstWhereOrNull((e) => + e.value == + musicGenresNameImagesImageTypeImageIndexHeadImageType) ?? + defaultValue ?? + enums.MusicGenresNameImagesImageTypeImageIndexHeadImageType + .swaggerGeneratedUnknown; +} + +enums.MusicGenresNameImagesImageTypeImageIndexHeadImageType? + musicGenresNameImagesImageTypeImageIndexHeadImageTypeNullableFromJson( + Object? musicGenresNameImagesImageTypeImageIndexHeadImageType, [ + enums.MusicGenresNameImagesImageTypeImageIndexHeadImageType? defaultValue, +]) { + if (musicGenresNameImagesImageTypeImageIndexHeadImageType == null) { + return null; + } + return enums.MusicGenresNameImagesImageTypeImageIndexHeadImageType.values + .firstWhereOrNull((e) => + e.value == + musicGenresNameImagesImageTypeImageIndexHeadImageType) ?? + defaultValue; +} + +String musicGenresNameImagesImageTypeImageIndexHeadImageTypeExplodedListToJson( + List? + musicGenresNameImagesImageTypeImageIndexHeadImageType) { + return musicGenresNameImagesImageTypeImageIndexHeadImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List musicGenresNameImagesImageTypeImageIndexHeadImageTypeListToJson( + List? + musicGenresNameImagesImageTypeImageIndexHeadImageType) { + if (musicGenresNameImagesImageTypeImageIndexHeadImageType == null) { + return []; + } + + return musicGenresNameImagesImageTypeImageIndexHeadImageType + .map((e) => e.value!) + .toList(); +} + +List + musicGenresNameImagesImageTypeImageIndexHeadImageTypeListFromJson( + List? musicGenresNameImagesImageTypeImageIndexHeadImageType, [ + List? + defaultValue, +]) { + if (musicGenresNameImagesImageTypeImageIndexHeadImageType == null) { + return defaultValue ?? []; + } + + return musicGenresNameImagesImageTypeImageIndexHeadImageType + .map((e) => musicGenresNameImagesImageTypeImageIndexHeadImageTypeFromJson( + e.toString())) + .toList(); +} + +List? + musicGenresNameImagesImageTypeImageIndexHeadImageTypeNullableListFromJson( + List? musicGenresNameImagesImageTypeImageIndexHeadImageType, [ + List? + defaultValue, +]) { + if (musicGenresNameImagesImageTypeImageIndexHeadImageType == null) { + return defaultValue; + } + + return musicGenresNameImagesImageTypeImageIndexHeadImageType + .map((e) => musicGenresNameImagesImageTypeImageIndexHeadImageTypeFromJson( + e.toString())) + .toList(); +} + +String? musicGenresNameImagesImageTypeImageIndexHeadFormatNullableToJson( + enums.MusicGenresNameImagesImageTypeImageIndexHeadFormat? + musicGenresNameImagesImageTypeImageIndexHeadFormat) { + return musicGenresNameImagesImageTypeImageIndexHeadFormat?.value; +} + +String? musicGenresNameImagesImageTypeImageIndexHeadFormatToJson( + enums.MusicGenresNameImagesImageTypeImageIndexHeadFormat + musicGenresNameImagesImageTypeImageIndexHeadFormat) { + return musicGenresNameImagesImageTypeImageIndexHeadFormat.value; +} + +enums.MusicGenresNameImagesImageTypeImageIndexHeadFormat + musicGenresNameImagesImageTypeImageIndexHeadFormatFromJson( + Object? musicGenresNameImagesImageTypeImageIndexHeadFormat, [ + enums.MusicGenresNameImagesImageTypeImageIndexHeadFormat? defaultValue, +]) { + return enums.MusicGenresNameImagesImageTypeImageIndexHeadFormat.values + .firstWhereOrNull((e) => + e.value == musicGenresNameImagesImageTypeImageIndexHeadFormat) ?? + defaultValue ?? + enums.MusicGenresNameImagesImageTypeImageIndexHeadFormat + .swaggerGeneratedUnknown; +} + +enums.MusicGenresNameImagesImageTypeImageIndexHeadFormat? + musicGenresNameImagesImageTypeImageIndexHeadFormatNullableFromJson( + Object? musicGenresNameImagesImageTypeImageIndexHeadFormat, [ + enums.MusicGenresNameImagesImageTypeImageIndexHeadFormat? defaultValue, +]) { + if (musicGenresNameImagesImageTypeImageIndexHeadFormat == null) { + return null; + } + return enums.MusicGenresNameImagesImageTypeImageIndexHeadFormat.values + .firstWhereOrNull((e) => + e.value == musicGenresNameImagesImageTypeImageIndexHeadFormat) ?? + defaultValue; +} + +String musicGenresNameImagesImageTypeImageIndexHeadFormatExplodedListToJson( + List? + musicGenresNameImagesImageTypeImageIndexHeadFormat) { + return musicGenresNameImagesImageTypeImageIndexHeadFormat + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List musicGenresNameImagesImageTypeImageIndexHeadFormatListToJson( + List? + musicGenresNameImagesImageTypeImageIndexHeadFormat) { + if (musicGenresNameImagesImageTypeImageIndexHeadFormat == null) { + return []; + } + + return musicGenresNameImagesImageTypeImageIndexHeadFormat + .map((e) => e.value!) + .toList(); +} + +List + musicGenresNameImagesImageTypeImageIndexHeadFormatListFromJson( + List? musicGenresNameImagesImageTypeImageIndexHeadFormat, [ + List? defaultValue, +]) { + if (musicGenresNameImagesImageTypeImageIndexHeadFormat == null) { + return defaultValue ?? []; + } + + return musicGenresNameImagesImageTypeImageIndexHeadFormat + .map((e) => musicGenresNameImagesImageTypeImageIndexHeadFormatFromJson( + e.toString())) + .toList(); +} + +List? + musicGenresNameImagesImageTypeImageIndexHeadFormatNullableListFromJson( + List? musicGenresNameImagesImageTypeImageIndexHeadFormat, [ + List? defaultValue, +]) { + if (musicGenresNameImagesImageTypeImageIndexHeadFormat == null) { + return defaultValue; + } + + return musicGenresNameImagesImageTypeImageIndexHeadFormat + .map((e) => musicGenresNameImagesImageTypeImageIndexHeadFormatFromJson( + e.toString())) + .toList(); +} + +String? personsNameImagesImageTypeGetImageTypeNullableToJson( + enums.PersonsNameImagesImageTypeGetImageType? + personsNameImagesImageTypeGetImageType) { + return personsNameImagesImageTypeGetImageType?.value; +} + +String? personsNameImagesImageTypeGetImageTypeToJson( + enums.PersonsNameImagesImageTypeGetImageType + personsNameImagesImageTypeGetImageType) { + return personsNameImagesImageTypeGetImageType.value; +} + +enums.PersonsNameImagesImageTypeGetImageType + personsNameImagesImageTypeGetImageTypeFromJson( + Object? personsNameImagesImageTypeGetImageType, [ + enums.PersonsNameImagesImageTypeGetImageType? defaultValue, +]) { + return enums.PersonsNameImagesImageTypeGetImageType.values.firstWhereOrNull( + (e) => e.value == personsNameImagesImageTypeGetImageType) ?? + defaultValue ?? + enums.PersonsNameImagesImageTypeGetImageType.swaggerGeneratedUnknown; +} + +enums.PersonsNameImagesImageTypeGetImageType? + personsNameImagesImageTypeGetImageTypeNullableFromJson( + Object? personsNameImagesImageTypeGetImageType, [ + enums.PersonsNameImagesImageTypeGetImageType? defaultValue, +]) { + if (personsNameImagesImageTypeGetImageType == null) { + return null; + } + return enums.PersonsNameImagesImageTypeGetImageType.values.firstWhereOrNull( + (e) => e.value == personsNameImagesImageTypeGetImageType) ?? + defaultValue; +} + +String personsNameImagesImageTypeGetImageTypeExplodedListToJson( + List? + personsNameImagesImageTypeGetImageType) { + return personsNameImagesImageTypeGetImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List personsNameImagesImageTypeGetImageTypeListToJson( + List? + personsNameImagesImageTypeGetImageType) { + if (personsNameImagesImageTypeGetImageType == null) { + return []; + } + + return personsNameImagesImageTypeGetImageType.map((e) => e.value!).toList(); +} + +List + personsNameImagesImageTypeGetImageTypeListFromJson( + List? personsNameImagesImageTypeGetImageType, [ + List? defaultValue, +]) { + if (personsNameImagesImageTypeGetImageType == null) { + return defaultValue ?? []; + } + + return personsNameImagesImageTypeGetImageType + .map((e) => personsNameImagesImageTypeGetImageTypeFromJson(e.toString())) + .toList(); +} + +List? + personsNameImagesImageTypeGetImageTypeNullableListFromJson( + List? personsNameImagesImageTypeGetImageType, [ + List? defaultValue, +]) { + if (personsNameImagesImageTypeGetImageType == null) { + return defaultValue; + } + + return personsNameImagesImageTypeGetImageType + .map((e) => personsNameImagesImageTypeGetImageTypeFromJson(e.toString())) + .toList(); +} + +String? personsNameImagesImageTypeGetFormatNullableToJson( + enums.PersonsNameImagesImageTypeGetFormat? + personsNameImagesImageTypeGetFormat) { + return personsNameImagesImageTypeGetFormat?.value; +} + +String? personsNameImagesImageTypeGetFormatToJson( + enums.PersonsNameImagesImageTypeGetFormat + personsNameImagesImageTypeGetFormat) { + return personsNameImagesImageTypeGetFormat.value; +} + +enums.PersonsNameImagesImageTypeGetFormat + personsNameImagesImageTypeGetFormatFromJson( + Object? personsNameImagesImageTypeGetFormat, [ + enums.PersonsNameImagesImageTypeGetFormat? defaultValue, +]) { + return enums.PersonsNameImagesImageTypeGetFormat.values.firstWhereOrNull( + (e) => e.value == personsNameImagesImageTypeGetFormat) ?? + defaultValue ?? + enums.PersonsNameImagesImageTypeGetFormat.swaggerGeneratedUnknown; +} + +enums.PersonsNameImagesImageTypeGetFormat? + personsNameImagesImageTypeGetFormatNullableFromJson( + Object? personsNameImagesImageTypeGetFormat, [ + enums.PersonsNameImagesImageTypeGetFormat? defaultValue, +]) { + if (personsNameImagesImageTypeGetFormat == null) { + return null; + } + return enums.PersonsNameImagesImageTypeGetFormat.values.firstWhereOrNull( + (e) => e.value == personsNameImagesImageTypeGetFormat) ?? + defaultValue; +} + +String personsNameImagesImageTypeGetFormatExplodedListToJson( + List? + personsNameImagesImageTypeGetFormat) { + return personsNameImagesImageTypeGetFormat?.map((e) => e.value!).join(',') ?? + ''; +} + +List personsNameImagesImageTypeGetFormatListToJson( + List? + personsNameImagesImageTypeGetFormat) { + if (personsNameImagesImageTypeGetFormat == null) { + return []; + } + + return personsNameImagesImageTypeGetFormat.map((e) => e.value!).toList(); +} + +List + personsNameImagesImageTypeGetFormatListFromJson( + List? personsNameImagesImageTypeGetFormat, [ + List? defaultValue, +]) { + if (personsNameImagesImageTypeGetFormat == null) { + return defaultValue ?? []; + } + + return personsNameImagesImageTypeGetFormat + .map((e) => personsNameImagesImageTypeGetFormatFromJson(e.toString())) + .toList(); +} + +List? + personsNameImagesImageTypeGetFormatNullableListFromJson( + List? personsNameImagesImageTypeGetFormat, [ + List? defaultValue, +]) { + if (personsNameImagesImageTypeGetFormat == null) { + return defaultValue; + } + + return personsNameImagesImageTypeGetFormat + .map((e) => personsNameImagesImageTypeGetFormatFromJson(e.toString())) + .toList(); +} + +String? personsNameImagesImageTypeHeadImageTypeNullableToJson( + enums.PersonsNameImagesImageTypeHeadImageType? + personsNameImagesImageTypeHeadImageType) { + return personsNameImagesImageTypeHeadImageType?.value; +} + +String? personsNameImagesImageTypeHeadImageTypeToJson( + enums.PersonsNameImagesImageTypeHeadImageType + personsNameImagesImageTypeHeadImageType) { + return personsNameImagesImageTypeHeadImageType.value; +} + +enums.PersonsNameImagesImageTypeHeadImageType + personsNameImagesImageTypeHeadImageTypeFromJson( + Object? personsNameImagesImageTypeHeadImageType, [ + enums.PersonsNameImagesImageTypeHeadImageType? defaultValue, +]) { + return enums.PersonsNameImagesImageTypeHeadImageType.values.firstWhereOrNull( + (e) => e.value == personsNameImagesImageTypeHeadImageType) ?? + defaultValue ?? + enums.PersonsNameImagesImageTypeHeadImageType.swaggerGeneratedUnknown; +} + +enums.PersonsNameImagesImageTypeHeadImageType? + personsNameImagesImageTypeHeadImageTypeNullableFromJson( + Object? personsNameImagesImageTypeHeadImageType, [ + enums.PersonsNameImagesImageTypeHeadImageType? defaultValue, +]) { + if (personsNameImagesImageTypeHeadImageType == null) { + return null; + } + return enums.PersonsNameImagesImageTypeHeadImageType.values.firstWhereOrNull( + (e) => e.value == personsNameImagesImageTypeHeadImageType) ?? + defaultValue; +} + +String personsNameImagesImageTypeHeadImageTypeExplodedListToJson( + List? + personsNameImagesImageTypeHeadImageType) { + return personsNameImagesImageTypeHeadImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List personsNameImagesImageTypeHeadImageTypeListToJson( + List? + personsNameImagesImageTypeHeadImageType) { + if (personsNameImagesImageTypeHeadImageType == null) { + return []; + } + + return personsNameImagesImageTypeHeadImageType.map((e) => e.value!).toList(); +} + +List + personsNameImagesImageTypeHeadImageTypeListFromJson( + List? personsNameImagesImageTypeHeadImageType, [ + List? defaultValue, +]) { + if (personsNameImagesImageTypeHeadImageType == null) { + return defaultValue ?? []; + } + + return personsNameImagesImageTypeHeadImageType + .map((e) => personsNameImagesImageTypeHeadImageTypeFromJson(e.toString())) + .toList(); +} + +List? + personsNameImagesImageTypeHeadImageTypeNullableListFromJson( + List? personsNameImagesImageTypeHeadImageType, [ + List? defaultValue, +]) { + if (personsNameImagesImageTypeHeadImageType == null) { + return defaultValue; + } + + return personsNameImagesImageTypeHeadImageType + .map((e) => personsNameImagesImageTypeHeadImageTypeFromJson(e.toString())) + .toList(); +} + +String? personsNameImagesImageTypeHeadFormatNullableToJson( + enums.PersonsNameImagesImageTypeHeadFormat? + personsNameImagesImageTypeHeadFormat) { + return personsNameImagesImageTypeHeadFormat?.value; +} + +String? personsNameImagesImageTypeHeadFormatToJson( + enums.PersonsNameImagesImageTypeHeadFormat + personsNameImagesImageTypeHeadFormat) { + return personsNameImagesImageTypeHeadFormat.value; +} + +enums.PersonsNameImagesImageTypeHeadFormat + personsNameImagesImageTypeHeadFormatFromJson( + Object? personsNameImagesImageTypeHeadFormat, [ + enums.PersonsNameImagesImageTypeHeadFormat? defaultValue, +]) { + return enums.PersonsNameImagesImageTypeHeadFormat.values.firstWhereOrNull( + (e) => e.value == personsNameImagesImageTypeHeadFormat) ?? + defaultValue ?? + enums.PersonsNameImagesImageTypeHeadFormat.swaggerGeneratedUnknown; +} + +enums.PersonsNameImagesImageTypeHeadFormat? + personsNameImagesImageTypeHeadFormatNullableFromJson( + Object? personsNameImagesImageTypeHeadFormat, [ + enums.PersonsNameImagesImageTypeHeadFormat? defaultValue, +]) { + if (personsNameImagesImageTypeHeadFormat == null) { + return null; + } + return enums.PersonsNameImagesImageTypeHeadFormat.values.firstWhereOrNull( + (e) => e.value == personsNameImagesImageTypeHeadFormat) ?? + defaultValue; +} + +String personsNameImagesImageTypeHeadFormatExplodedListToJson( + List? + personsNameImagesImageTypeHeadFormat) { + return personsNameImagesImageTypeHeadFormat?.map((e) => e.value!).join(',') ?? + ''; +} + +List personsNameImagesImageTypeHeadFormatListToJson( + List? + personsNameImagesImageTypeHeadFormat) { + if (personsNameImagesImageTypeHeadFormat == null) { + return []; + } + + return personsNameImagesImageTypeHeadFormat.map((e) => e.value!).toList(); +} + +List + personsNameImagesImageTypeHeadFormatListFromJson( + List? personsNameImagesImageTypeHeadFormat, [ + List? defaultValue, +]) { + if (personsNameImagesImageTypeHeadFormat == null) { + return defaultValue ?? []; + } + + return personsNameImagesImageTypeHeadFormat + .map((e) => personsNameImagesImageTypeHeadFormatFromJson(e.toString())) + .toList(); +} + +List? + personsNameImagesImageTypeHeadFormatNullableListFromJson( + List? personsNameImagesImageTypeHeadFormat, [ + List? defaultValue, +]) { + if (personsNameImagesImageTypeHeadFormat == null) { + return defaultValue; + } + + return personsNameImagesImageTypeHeadFormat + .map((e) => personsNameImagesImageTypeHeadFormatFromJson(e.toString())) + .toList(); +} + +String? personsNameImagesImageTypeImageIndexGetImageTypeNullableToJson( + enums.PersonsNameImagesImageTypeImageIndexGetImageType? + personsNameImagesImageTypeImageIndexGetImageType) { + return personsNameImagesImageTypeImageIndexGetImageType?.value; +} + +String? personsNameImagesImageTypeImageIndexGetImageTypeToJson( + enums.PersonsNameImagesImageTypeImageIndexGetImageType + personsNameImagesImageTypeImageIndexGetImageType) { + return personsNameImagesImageTypeImageIndexGetImageType.value; +} + +enums.PersonsNameImagesImageTypeImageIndexGetImageType + personsNameImagesImageTypeImageIndexGetImageTypeFromJson( + Object? personsNameImagesImageTypeImageIndexGetImageType, [ + enums.PersonsNameImagesImageTypeImageIndexGetImageType? defaultValue, +]) { + return enums.PersonsNameImagesImageTypeImageIndexGetImageType.values + .firstWhereOrNull((e) => + e.value == personsNameImagesImageTypeImageIndexGetImageType) ?? + defaultValue ?? + enums.PersonsNameImagesImageTypeImageIndexGetImageType + .swaggerGeneratedUnknown; +} + +enums.PersonsNameImagesImageTypeImageIndexGetImageType? + personsNameImagesImageTypeImageIndexGetImageTypeNullableFromJson( + Object? personsNameImagesImageTypeImageIndexGetImageType, [ + enums.PersonsNameImagesImageTypeImageIndexGetImageType? defaultValue, +]) { + if (personsNameImagesImageTypeImageIndexGetImageType == null) { + return null; + } + return enums.PersonsNameImagesImageTypeImageIndexGetImageType.values + .firstWhereOrNull((e) => + e.value == personsNameImagesImageTypeImageIndexGetImageType) ?? + defaultValue; +} + +String personsNameImagesImageTypeImageIndexGetImageTypeExplodedListToJson( + List? + personsNameImagesImageTypeImageIndexGetImageType) { + return personsNameImagesImageTypeImageIndexGetImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List personsNameImagesImageTypeImageIndexGetImageTypeListToJson( + List? + personsNameImagesImageTypeImageIndexGetImageType) { + if (personsNameImagesImageTypeImageIndexGetImageType == null) { + return []; + } + + return personsNameImagesImageTypeImageIndexGetImageType + .map((e) => e.value!) + .toList(); +} + +List + personsNameImagesImageTypeImageIndexGetImageTypeListFromJson( + List? personsNameImagesImageTypeImageIndexGetImageType, [ + List? defaultValue, +]) { + if (personsNameImagesImageTypeImageIndexGetImageType == null) { + return defaultValue ?? []; + } + + return personsNameImagesImageTypeImageIndexGetImageType + .map((e) => personsNameImagesImageTypeImageIndexGetImageTypeFromJson( + e.toString())) + .toList(); +} + +List? + personsNameImagesImageTypeImageIndexGetImageTypeNullableListFromJson( + List? personsNameImagesImageTypeImageIndexGetImageType, [ + List? defaultValue, +]) { + if (personsNameImagesImageTypeImageIndexGetImageType == null) { + return defaultValue; + } + + return personsNameImagesImageTypeImageIndexGetImageType + .map((e) => personsNameImagesImageTypeImageIndexGetImageTypeFromJson( + e.toString())) + .toList(); +} + +String? personsNameImagesImageTypeImageIndexGetFormatNullableToJson( + enums.PersonsNameImagesImageTypeImageIndexGetFormat? + personsNameImagesImageTypeImageIndexGetFormat) { + return personsNameImagesImageTypeImageIndexGetFormat?.value; +} + +String? personsNameImagesImageTypeImageIndexGetFormatToJson( + enums.PersonsNameImagesImageTypeImageIndexGetFormat + personsNameImagesImageTypeImageIndexGetFormat) { + return personsNameImagesImageTypeImageIndexGetFormat.value; +} + +enums.PersonsNameImagesImageTypeImageIndexGetFormat + personsNameImagesImageTypeImageIndexGetFormatFromJson( + Object? personsNameImagesImageTypeImageIndexGetFormat, [ + enums.PersonsNameImagesImageTypeImageIndexGetFormat? defaultValue, +]) { + return enums.PersonsNameImagesImageTypeImageIndexGetFormat.values + .firstWhereOrNull((e) => + e.value == personsNameImagesImageTypeImageIndexGetFormat) ?? + defaultValue ?? + enums.PersonsNameImagesImageTypeImageIndexGetFormat + .swaggerGeneratedUnknown; +} + +enums.PersonsNameImagesImageTypeImageIndexGetFormat? + personsNameImagesImageTypeImageIndexGetFormatNullableFromJson( + Object? personsNameImagesImageTypeImageIndexGetFormat, [ + enums.PersonsNameImagesImageTypeImageIndexGetFormat? defaultValue, +]) { + if (personsNameImagesImageTypeImageIndexGetFormat == null) { + return null; + } + return enums.PersonsNameImagesImageTypeImageIndexGetFormat.values + .firstWhereOrNull((e) => + e.value == personsNameImagesImageTypeImageIndexGetFormat) ?? + defaultValue; +} + +String personsNameImagesImageTypeImageIndexGetFormatExplodedListToJson( + List? + personsNameImagesImageTypeImageIndexGetFormat) { + return personsNameImagesImageTypeImageIndexGetFormat + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List personsNameImagesImageTypeImageIndexGetFormatListToJson( + List? + personsNameImagesImageTypeImageIndexGetFormat) { + if (personsNameImagesImageTypeImageIndexGetFormat == null) { + return []; + } + + return personsNameImagesImageTypeImageIndexGetFormat + .map((e) => e.value!) + .toList(); +} + +List + personsNameImagesImageTypeImageIndexGetFormatListFromJson( + List? personsNameImagesImageTypeImageIndexGetFormat, [ + List? defaultValue, +]) { + if (personsNameImagesImageTypeImageIndexGetFormat == null) { + return defaultValue ?? []; + } + + return personsNameImagesImageTypeImageIndexGetFormat + .map((e) => + personsNameImagesImageTypeImageIndexGetFormatFromJson(e.toString())) + .toList(); +} + +List? + personsNameImagesImageTypeImageIndexGetFormatNullableListFromJson( + List? personsNameImagesImageTypeImageIndexGetFormat, [ + List? defaultValue, +]) { + if (personsNameImagesImageTypeImageIndexGetFormat == null) { + return defaultValue; + } + + return personsNameImagesImageTypeImageIndexGetFormat + .map((e) => + personsNameImagesImageTypeImageIndexGetFormatFromJson(e.toString())) + .toList(); +} + +String? personsNameImagesImageTypeImageIndexHeadImageTypeNullableToJson( + enums.PersonsNameImagesImageTypeImageIndexHeadImageType? + personsNameImagesImageTypeImageIndexHeadImageType) { + return personsNameImagesImageTypeImageIndexHeadImageType?.value; +} + +String? personsNameImagesImageTypeImageIndexHeadImageTypeToJson( + enums.PersonsNameImagesImageTypeImageIndexHeadImageType + personsNameImagesImageTypeImageIndexHeadImageType) { + return personsNameImagesImageTypeImageIndexHeadImageType.value; +} + +enums.PersonsNameImagesImageTypeImageIndexHeadImageType + personsNameImagesImageTypeImageIndexHeadImageTypeFromJson( + Object? personsNameImagesImageTypeImageIndexHeadImageType, [ + enums.PersonsNameImagesImageTypeImageIndexHeadImageType? defaultValue, +]) { + return enums.PersonsNameImagesImageTypeImageIndexHeadImageType.values + .firstWhereOrNull((e) => + e.value == personsNameImagesImageTypeImageIndexHeadImageType) ?? + defaultValue ?? + enums.PersonsNameImagesImageTypeImageIndexHeadImageType + .swaggerGeneratedUnknown; +} + +enums.PersonsNameImagesImageTypeImageIndexHeadImageType? + personsNameImagesImageTypeImageIndexHeadImageTypeNullableFromJson( + Object? personsNameImagesImageTypeImageIndexHeadImageType, [ + enums.PersonsNameImagesImageTypeImageIndexHeadImageType? defaultValue, +]) { + if (personsNameImagesImageTypeImageIndexHeadImageType == null) { + return null; + } + return enums.PersonsNameImagesImageTypeImageIndexHeadImageType.values + .firstWhereOrNull((e) => + e.value == personsNameImagesImageTypeImageIndexHeadImageType) ?? + defaultValue; +} + +String personsNameImagesImageTypeImageIndexHeadImageTypeExplodedListToJson( + List? + personsNameImagesImageTypeImageIndexHeadImageType) { + return personsNameImagesImageTypeImageIndexHeadImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List personsNameImagesImageTypeImageIndexHeadImageTypeListToJson( + List? + personsNameImagesImageTypeImageIndexHeadImageType) { + if (personsNameImagesImageTypeImageIndexHeadImageType == null) { + return []; + } + + return personsNameImagesImageTypeImageIndexHeadImageType + .map((e) => e.value!) + .toList(); +} + +List + personsNameImagesImageTypeImageIndexHeadImageTypeListFromJson( + List? personsNameImagesImageTypeImageIndexHeadImageType, [ + List? defaultValue, +]) { + if (personsNameImagesImageTypeImageIndexHeadImageType == null) { + return defaultValue ?? []; + } + + return personsNameImagesImageTypeImageIndexHeadImageType + .map((e) => personsNameImagesImageTypeImageIndexHeadImageTypeFromJson( + e.toString())) + .toList(); +} + +List? + personsNameImagesImageTypeImageIndexHeadImageTypeNullableListFromJson( + List? personsNameImagesImageTypeImageIndexHeadImageType, [ + List? defaultValue, +]) { + if (personsNameImagesImageTypeImageIndexHeadImageType == null) { + return defaultValue; + } + + return personsNameImagesImageTypeImageIndexHeadImageType + .map((e) => personsNameImagesImageTypeImageIndexHeadImageTypeFromJson( + e.toString())) + .toList(); +} + +String? personsNameImagesImageTypeImageIndexHeadFormatNullableToJson( + enums.PersonsNameImagesImageTypeImageIndexHeadFormat? + personsNameImagesImageTypeImageIndexHeadFormat) { + return personsNameImagesImageTypeImageIndexHeadFormat?.value; +} + +String? personsNameImagesImageTypeImageIndexHeadFormatToJson( + enums.PersonsNameImagesImageTypeImageIndexHeadFormat + personsNameImagesImageTypeImageIndexHeadFormat) { + return personsNameImagesImageTypeImageIndexHeadFormat.value; +} + +enums.PersonsNameImagesImageTypeImageIndexHeadFormat + personsNameImagesImageTypeImageIndexHeadFormatFromJson( + Object? personsNameImagesImageTypeImageIndexHeadFormat, [ + enums.PersonsNameImagesImageTypeImageIndexHeadFormat? defaultValue, +]) { + return enums.PersonsNameImagesImageTypeImageIndexHeadFormat.values + .firstWhereOrNull((e) => + e.value == personsNameImagesImageTypeImageIndexHeadFormat) ?? + defaultValue ?? + enums.PersonsNameImagesImageTypeImageIndexHeadFormat + .swaggerGeneratedUnknown; +} + +enums.PersonsNameImagesImageTypeImageIndexHeadFormat? + personsNameImagesImageTypeImageIndexHeadFormatNullableFromJson( + Object? personsNameImagesImageTypeImageIndexHeadFormat, [ + enums.PersonsNameImagesImageTypeImageIndexHeadFormat? defaultValue, +]) { + if (personsNameImagesImageTypeImageIndexHeadFormat == null) { + return null; + } + return enums.PersonsNameImagesImageTypeImageIndexHeadFormat.values + .firstWhereOrNull((e) => + e.value == personsNameImagesImageTypeImageIndexHeadFormat) ?? + defaultValue; +} + +String personsNameImagesImageTypeImageIndexHeadFormatExplodedListToJson( + List? + personsNameImagesImageTypeImageIndexHeadFormat) { + return personsNameImagesImageTypeImageIndexHeadFormat + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List personsNameImagesImageTypeImageIndexHeadFormatListToJson( + List? + personsNameImagesImageTypeImageIndexHeadFormat) { + if (personsNameImagesImageTypeImageIndexHeadFormat == null) { + return []; + } + + return personsNameImagesImageTypeImageIndexHeadFormat + .map((e) => e.value!) + .toList(); +} + +List + personsNameImagesImageTypeImageIndexHeadFormatListFromJson( + List? personsNameImagesImageTypeImageIndexHeadFormat, [ + List? defaultValue, +]) { + if (personsNameImagesImageTypeImageIndexHeadFormat == null) { + return defaultValue ?? []; + } + + return personsNameImagesImageTypeImageIndexHeadFormat + .map((e) => + personsNameImagesImageTypeImageIndexHeadFormatFromJson(e.toString())) + .toList(); +} + +List? + personsNameImagesImageTypeImageIndexHeadFormatNullableListFromJson( + List? personsNameImagesImageTypeImageIndexHeadFormat, [ + List? defaultValue, +]) { + if (personsNameImagesImageTypeImageIndexHeadFormat == null) { + return defaultValue; + } + + return personsNameImagesImageTypeImageIndexHeadFormat + .map((e) => + personsNameImagesImageTypeImageIndexHeadFormatFromJson(e.toString())) + .toList(); +} + +String? studiosNameImagesImageTypeGetImageTypeNullableToJson( + enums.StudiosNameImagesImageTypeGetImageType? + studiosNameImagesImageTypeGetImageType) { + return studiosNameImagesImageTypeGetImageType?.value; +} + +String? studiosNameImagesImageTypeGetImageTypeToJson( + enums.StudiosNameImagesImageTypeGetImageType + studiosNameImagesImageTypeGetImageType) { + return studiosNameImagesImageTypeGetImageType.value; +} + +enums.StudiosNameImagesImageTypeGetImageType + studiosNameImagesImageTypeGetImageTypeFromJson( + Object? studiosNameImagesImageTypeGetImageType, [ + enums.StudiosNameImagesImageTypeGetImageType? defaultValue, +]) { + return enums.StudiosNameImagesImageTypeGetImageType.values.firstWhereOrNull( + (e) => e.value == studiosNameImagesImageTypeGetImageType) ?? + defaultValue ?? + enums.StudiosNameImagesImageTypeGetImageType.swaggerGeneratedUnknown; +} + +enums.StudiosNameImagesImageTypeGetImageType? + studiosNameImagesImageTypeGetImageTypeNullableFromJson( + Object? studiosNameImagesImageTypeGetImageType, [ + enums.StudiosNameImagesImageTypeGetImageType? defaultValue, +]) { + if (studiosNameImagesImageTypeGetImageType == null) { + return null; + } + return enums.StudiosNameImagesImageTypeGetImageType.values.firstWhereOrNull( + (e) => e.value == studiosNameImagesImageTypeGetImageType) ?? + defaultValue; +} + +String studiosNameImagesImageTypeGetImageTypeExplodedListToJson( + List? + studiosNameImagesImageTypeGetImageType) { + return studiosNameImagesImageTypeGetImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List studiosNameImagesImageTypeGetImageTypeListToJson( + List? + studiosNameImagesImageTypeGetImageType) { + if (studiosNameImagesImageTypeGetImageType == null) { + return []; + } + + return studiosNameImagesImageTypeGetImageType.map((e) => e.value!).toList(); +} + +List + studiosNameImagesImageTypeGetImageTypeListFromJson( + List? studiosNameImagesImageTypeGetImageType, [ + List? defaultValue, +]) { + if (studiosNameImagesImageTypeGetImageType == null) { + return defaultValue ?? []; + } + + return studiosNameImagesImageTypeGetImageType + .map((e) => studiosNameImagesImageTypeGetImageTypeFromJson(e.toString())) + .toList(); +} + +List? + studiosNameImagesImageTypeGetImageTypeNullableListFromJson( + List? studiosNameImagesImageTypeGetImageType, [ + List? defaultValue, +]) { + if (studiosNameImagesImageTypeGetImageType == null) { + return defaultValue; + } + + return studiosNameImagesImageTypeGetImageType + .map((e) => studiosNameImagesImageTypeGetImageTypeFromJson(e.toString())) + .toList(); +} + +String? studiosNameImagesImageTypeGetFormatNullableToJson( + enums.StudiosNameImagesImageTypeGetFormat? + studiosNameImagesImageTypeGetFormat) { + return studiosNameImagesImageTypeGetFormat?.value; +} + +String? studiosNameImagesImageTypeGetFormatToJson( + enums.StudiosNameImagesImageTypeGetFormat + studiosNameImagesImageTypeGetFormat) { + return studiosNameImagesImageTypeGetFormat.value; +} + +enums.StudiosNameImagesImageTypeGetFormat + studiosNameImagesImageTypeGetFormatFromJson( + Object? studiosNameImagesImageTypeGetFormat, [ + enums.StudiosNameImagesImageTypeGetFormat? defaultValue, +]) { + return enums.StudiosNameImagesImageTypeGetFormat.values.firstWhereOrNull( + (e) => e.value == studiosNameImagesImageTypeGetFormat) ?? + defaultValue ?? + enums.StudiosNameImagesImageTypeGetFormat.swaggerGeneratedUnknown; +} + +enums.StudiosNameImagesImageTypeGetFormat? + studiosNameImagesImageTypeGetFormatNullableFromJson( + Object? studiosNameImagesImageTypeGetFormat, [ + enums.StudiosNameImagesImageTypeGetFormat? defaultValue, +]) { + if (studiosNameImagesImageTypeGetFormat == null) { + return null; + } + return enums.StudiosNameImagesImageTypeGetFormat.values.firstWhereOrNull( + (e) => e.value == studiosNameImagesImageTypeGetFormat) ?? + defaultValue; +} + +String studiosNameImagesImageTypeGetFormatExplodedListToJson( + List? + studiosNameImagesImageTypeGetFormat) { + return studiosNameImagesImageTypeGetFormat?.map((e) => e.value!).join(',') ?? + ''; +} + +List studiosNameImagesImageTypeGetFormatListToJson( + List? + studiosNameImagesImageTypeGetFormat) { + if (studiosNameImagesImageTypeGetFormat == null) { + return []; + } + + return studiosNameImagesImageTypeGetFormat.map((e) => e.value!).toList(); +} + +List + studiosNameImagesImageTypeGetFormatListFromJson( + List? studiosNameImagesImageTypeGetFormat, [ + List? defaultValue, +]) { + if (studiosNameImagesImageTypeGetFormat == null) { + return defaultValue ?? []; + } + + return studiosNameImagesImageTypeGetFormat + .map((e) => studiosNameImagesImageTypeGetFormatFromJson(e.toString())) + .toList(); +} + +List? + studiosNameImagesImageTypeGetFormatNullableListFromJson( + List? studiosNameImagesImageTypeGetFormat, [ + List? defaultValue, +]) { + if (studiosNameImagesImageTypeGetFormat == null) { + return defaultValue; + } + + return studiosNameImagesImageTypeGetFormat + .map((e) => studiosNameImagesImageTypeGetFormatFromJson(e.toString())) + .toList(); +} + +String? studiosNameImagesImageTypeHeadImageTypeNullableToJson( + enums.StudiosNameImagesImageTypeHeadImageType? + studiosNameImagesImageTypeHeadImageType) { + return studiosNameImagesImageTypeHeadImageType?.value; +} + +String? studiosNameImagesImageTypeHeadImageTypeToJson( + enums.StudiosNameImagesImageTypeHeadImageType + studiosNameImagesImageTypeHeadImageType) { + return studiosNameImagesImageTypeHeadImageType.value; +} + +enums.StudiosNameImagesImageTypeHeadImageType + studiosNameImagesImageTypeHeadImageTypeFromJson( + Object? studiosNameImagesImageTypeHeadImageType, [ + enums.StudiosNameImagesImageTypeHeadImageType? defaultValue, +]) { + return enums.StudiosNameImagesImageTypeHeadImageType.values.firstWhereOrNull( + (e) => e.value == studiosNameImagesImageTypeHeadImageType) ?? + defaultValue ?? + enums.StudiosNameImagesImageTypeHeadImageType.swaggerGeneratedUnknown; +} + +enums.StudiosNameImagesImageTypeHeadImageType? + studiosNameImagesImageTypeHeadImageTypeNullableFromJson( + Object? studiosNameImagesImageTypeHeadImageType, [ + enums.StudiosNameImagesImageTypeHeadImageType? defaultValue, +]) { + if (studiosNameImagesImageTypeHeadImageType == null) { + return null; + } + return enums.StudiosNameImagesImageTypeHeadImageType.values.firstWhereOrNull( + (e) => e.value == studiosNameImagesImageTypeHeadImageType) ?? + defaultValue; +} + +String studiosNameImagesImageTypeHeadImageTypeExplodedListToJson( + List? + studiosNameImagesImageTypeHeadImageType) { + return studiosNameImagesImageTypeHeadImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List studiosNameImagesImageTypeHeadImageTypeListToJson( + List? + studiosNameImagesImageTypeHeadImageType) { + if (studiosNameImagesImageTypeHeadImageType == null) { + return []; + } + + return studiosNameImagesImageTypeHeadImageType.map((e) => e.value!).toList(); +} + +List + studiosNameImagesImageTypeHeadImageTypeListFromJson( + List? studiosNameImagesImageTypeHeadImageType, [ + List? defaultValue, +]) { + if (studiosNameImagesImageTypeHeadImageType == null) { + return defaultValue ?? []; + } + + return studiosNameImagesImageTypeHeadImageType + .map((e) => studiosNameImagesImageTypeHeadImageTypeFromJson(e.toString())) + .toList(); +} + +List? + studiosNameImagesImageTypeHeadImageTypeNullableListFromJson( + List? studiosNameImagesImageTypeHeadImageType, [ + List? defaultValue, +]) { + if (studiosNameImagesImageTypeHeadImageType == null) { + return defaultValue; + } + + return studiosNameImagesImageTypeHeadImageType + .map((e) => studiosNameImagesImageTypeHeadImageTypeFromJson(e.toString())) + .toList(); +} + +String? studiosNameImagesImageTypeHeadFormatNullableToJson( + enums.StudiosNameImagesImageTypeHeadFormat? + studiosNameImagesImageTypeHeadFormat) { + return studiosNameImagesImageTypeHeadFormat?.value; +} + +String? studiosNameImagesImageTypeHeadFormatToJson( + enums.StudiosNameImagesImageTypeHeadFormat + studiosNameImagesImageTypeHeadFormat) { + return studiosNameImagesImageTypeHeadFormat.value; +} + +enums.StudiosNameImagesImageTypeHeadFormat + studiosNameImagesImageTypeHeadFormatFromJson( + Object? studiosNameImagesImageTypeHeadFormat, [ + enums.StudiosNameImagesImageTypeHeadFormat? defaultValue, +]) { + return enums.StudiosNameImagesImageTypeHeadFormat.values.firstWhereOrNull( + (e) => e.value == studiosNameImagesImageTypeHeadFormat) ?? + defaultValue ?? + enums.StudiosNameImagesImageTypeHeadFormat.swaggerGeneratedUnknown; +} + +enums.StudiosNameImagesImageTypeHeadFormat? + studiosNameImagesImageTypeHeadFormatNullableFromJson( + Object? studiosNameImagesImageTypeHeadFormat, [ + enums.StudiosNameImagesImageTypeHeadFormat? defaultValue, +]) { + if (studiosNameImagesImageTypeHeadFormat == null) { + return null; + } + return enums.StudiosNameImagesImageTypeHeadFormat.values.firstWhereOrNull( + (e) => e.value == studiosNameImagesImageTypeHeadFormat) ?? + defaultValue; +} + +String studiosNameImagesImageTypeHeadFormatExplodedListToJson( + List? + studiosNameImagesImageTypeHeadFormat) { + return studiosNameImagesImageTypeHeadFormat?.map((e) => e.value!).join(',') ?? + ''; +} + +List studiosNameImagesImageTypeHeadFormatListToJson( + List? + studiosNameImagesImageTypeHeadFormat) { + if (studiosNameImagesImageTypeHeadFormat == null) { + return []; + } + + return studiosNameImagesImageTypeHeadFormat.map((e) => e.value!).toList(); +} + +List + studiosNameImagesImageTypeHeadFormatListFromJson( + List? studiosNameImagesImageTypeHeadFormat, [ + List? defaultValue, +]) { + if (studiosNameImagesImageTypeHeadFormat == null) { + return defaultValue ?? []; + } + + return studiosNameImagesImageTypeHeadFormat + .map((e) => studiosNameImagesImageTypeHeadFormatFromJson(e.toString())) + .toList(); +} + +List? + studiosNameImagesImageTypeHeadFormatNullableListFromJson( + List? studiosNameImagesImageTypeHeadFormat, [ + List? defaultValue, +]) { + if (studiosNameImagesImageTypeHeadFormat == null) { + return defaultValue; + } + + return studiosNameImagesImageTypeHeadFormat + .map((e) => studiosNameImagesImageTypeHeadFormatFromJson(e.toString())) + .toList(); +} + +String? studiosNameImagesImageTypeImageIndexGetImageTypeNullableToJson( + enums.StudiosNameImagesImageTypeImageIndexGetImageType? + studiosNameImagesImageTypeImageIndexGetImageType) { + return studiosNameImagesImageTypeImageIndexGetImageType?.value; +} + +String? studiosNameImagesImageTypeImageIndexGetImageTypeToJson( + enums.StudiosNameImagesImageTypeImageIndexGetImageType + studiosNameImagesImageTypeImageIndexGetImageType) { + return studiosNameImagesImageTypeImageIndexGetImageType.value; +} + +enums.StudiosNameImagesImageTypeImageIndexGetImageType + studiosNameImagesImageTypeImageIndexGetImageTypeFromJson( + Object? studiosNameImagesImageTypeImageIndexGetImageType, [ + enums.StudiosNameImagesImageTypeImageIndexGetImageType? defaultValue, +]) { + return enums.StudiosNameImagesImageTypeImageIndexGetImageType.values + .firstWhereOrNull((e) => + e.value == studiosNameImagesImageTypeImageIndexGetImageType) ?? + defaultValue ?? + enums.StudiosNameImagesImageTypeImageIndexGetImageType + .swaggerGeneratedUnknown; +} + +enums.StudiosNameImagesImageTypeImageIndexGetImageType? + studiosNameImagesImageTypeImageIndexGetImageTypeNullableFromJson( + Object? studiosNameImagesImageTypeImageIndexGetImageType, [ + enums.StudiosNameImagesImageTypeImageIndexGetImageType? defaultValue, +]) { + if (studiosNameImagesImageTypeImageIndexGetImageType == null) { + return null; + } + return enums.StudiosNameImagesImageTypeImageIndexGetImageType.values + .firstWhereOrNull((e) => + e.value == studiosNameImagesImageTypeImageIndexGetImageType) ?? + defaultValue; +} + +String studiosNameImagesImageTypeImageIndexGetImageTypeExplodedListToJson( + List? + studiosNameImagesImageTypeImageIndexGetImageType) { + return studiosNameImagesImageTypeImageIndexGetImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List studiosNameImagesImageTypeImageIndexGetImageTypeListToJson( + List? + studiosNameImagesImageTypeImageIndexGetImageType) { + if (studiosNameImagesImageTypeImageIndexGetImageType == null) { + return []; + } + + return studiosNameImagesImageTypeImageIndexGetImageType + .map((e) => e.value!) + .toList(); +} + +List + studiosNameImagesImageTypeImageIndexGetImageTypeListFromJson( + List? studiosNameImagesImageTypeImageIndexGetImageType, [ + List? defaultValue, +]) { + if (studiosNameImagesImageTypeImageIndexGetImageType == null) { + return defaultValue ?? []; + } + + return studiosNameImagesImageTypeImageIndexGetImageType + .map((e) => studiosNameImagesImageTypeImageIndexGetImageTypeFromJson( + e.toString())) + .toList(); +} + +List? + studiosNameImagesImageTypeImageIndexGetImageTypeNullableListFromJson( + List? studiosNameImagesImageTypeImageIndexGetImageType, [ + List? defaultValue, +]) { + if (studiosNameImagesImageTypeImageIndexGetImageType == null) { + return defaultValue; + } + + return studiosNameImagesImageTypeImageIndexGetImageType + .map((e) => studiosNameImagesImageTypeImageIndexGetImageTypeFromJson( + e.toString())) + .toList(); +} + +String? studiosNameImagesImageTypeImageIndexGetFormatNullableToJson( + enums.StudiosNameImagesImageTypeImageIndexGetFormat? + studiosNameImagesImageTypeImageIndexGetFormat) { + return studiosNameImagesImageTypeImageIndexGetFormat?.value; +} + +String? studiosNameImagesImageTypeImageIndexGetFormatToJson( + enums.StudiosNameImagesImageTypeImageIndexGetFormat + studiosNameImagesImageTypeImageIndexGetFormat) { + return studiosNameImagesImageTypeImageIndexGetFormat.value; +} + +enums.StudiosNameImagesImageTypeImageIndexGetFormat + studiosNameImagesImageTypeImageIndexGetFormatFromJson( + Object? studiosNameImagesImageTypeImageIndexGetFormat, [ + enums.StudiosNameImagesImageTypeImageIndexGetFormat? defaultValue, +]) { + return enums.StudiosNameImagesImageTypeImageIndexGetFormat.values + .firstWhereOrNull((e) => + e.value == studiosNameImagesImageTypeImageIndexGetFormat) ?? + defaultValue ?? + enums.StudiosNameImagesImageTypeImageIndexGetFormat + .swaggerGeneratedUnknown; +} + +enums.StudiosNameImagesImageTypeImageIndexGetFormat? + studiosNameImagesImageTypeImageIndexGetFormatNullableFromJson( + Object? studiosNameImagesImageTypeImageIndexGetFormat, [ + enums.StudiosNameImagesImageTypeImageIndexGetFormat? defaultValue, +]) { + if (studiosNameImagesImageTypeImageIndexGetFormat == null) { + return null; + } + return enums.StudiosNameImagesImageTypeImageIndexGetFormat.values + .firstWhereOrNull((e) => + e.value == studiosNameImagesImageTypeImageIndexGetFormat) ?? + defaultValue; +} + +String studiosNameImagesImageTypeImageIndexGetFormatExplodedListToJson( + List? + studiosNameImagesImageTypeImageIndexGetFormat) { + return studiosNameImagesImageTypeImageIndexGetFormat + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List studiosNameImagesImageTypeImageIndexGetFormatListToJson( + List? + studiosNameImagesImageTypeImageIndexGetFormat) { + if (studiosNameImagesImageTypeImageIndexGetFormat == null) { + return []; + } + + return studiosNameImagesImageTypeImageIndexGetFormat + .map((e) => e.value!) + .toList(); +} + +List + studiosNameImagesImageTypeImageIndexGetFormatListFromJson( + List? studiosNameImagesImageTypeImageIndexGetFormat, [ + List? defaultValue, +]) { + if (studiosNameImagesImageTypeImageIndexGetFormat == null) { + return defaultValue ?? []; + } + + return studiosNameImagesImageTypeImageIndexGetFormat + .map((e) => + studiosNameImagesImageTypeImageIndexGetFormatFromJson(e.toString())) + .toList(); +} + +List? + studiosNameImagesImageTypeImageIndexGetFormatNullableListFromJson( + List? studiosNameImagesImageTypeImageIndexGetFormat, [ + List? defaultValue, +]) { + if (studiosNameImagesImageTypeImageIndexGetFormat == null) { + return defaultValue; + } + + return studiosNameImagesImageTypeImageIndexGetFormat + .map((e) => + studiosNameImagesImageTypeImageIndexGetFormatFromJson(e.toString())) + .toList(); +} + +String? studiosNameImagesImageTypeImageIndexHeadImageTypeNullableToJson( + enums.StudiosNameImagesImageTypeImageIndexHeadImageType? + studiosNameImagesImageTypeImageIndexHeadImageType) { + return studiosNameImagesImageTypeImageIndexHeadImageType?.value; +} + +String? studiosNameImagesImageTypeImageIndexHeadImageTypeToJson( + enums.StudiosNameImagesImageTypeImageIndexHeadImageType + studiosNameImagesImageTypeImageIndexHeadImageType) { + return studiosNameImagesImageTypeImageIndexHeadImageType.value; +} + +enums.StudiosNameImagesImageTypeImageIndexHeadImageType + studiosNameImagesImageTypeImageIndexHeadImageTypeFromJson( + Object? studiosNameImagesImageTypeImageIndexHeadImageType, [ + enums.StudiosNameImagesImageTypeImageIndexHeadImageType? defaultValue, +]) { + return enums.StudiosNameImagesImageTypeImageIndexHeadImageType.values + .firstWhereOrNull((e) => + e.value == studiosNameImagesImageTypeImageIndexHeadImageType) ?? + defaultValue ?? + enums.StudiosNameImagesImageTypeImageIndexHeadImageType + .swaggerGeneratedUnknown; +} + +enums.StudiosNameImagesImageTypeImageIndexHeadImageType? + studiosNameImagesImageTypeImageIndexHeadImageTypeNullableFromJson( + Object? studiosNameImagesImageTypeImageIndexHeadImageType, [ + enums.StudiosNameImagesImageTypeImageIndexHeadImageType? defaultValue, +]) { + if (studiosNameImagesImageTypeImageIndexHeadImageType == null) { + return null; + } + return enums.StudiosNameImagesImageTypeImageIndexHeadImageType.values + .firstWhereOrNull((e) => + e.value == studiosNameImagesImageTypeImageIndexHeadImageType) ?? + defaultValue; +} + +String studiosNameImagesImageTypeImageIndexHeadImageTypeExplodedListToJson( + List? + studiosNameImagesImageTypeImageIndexHeadImageType) { + return studiosNameImagesImageTypeImageIndexHeadImageType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List studiosNameImagesImageTypeImageIndexHeadImageTypeListToJson( + List? + studiosNameImagesImageTypeImageIndexHeadImageType) { + if (studiosNameImagesImageTypeImageIndexHeadImageType == null) { + return []; + } + + return studiosNameImagesImageTypeImageIndexHeadImageType + .map((e) => e.value!) + .toList(); +} + +List + studiosNameImagesImageTypeImageIndexHeadImageTypeListFromJson( + List? studiosNameImagesImageTypeImageIndexHeadImageType, [ + List? defaultValue, +]) { + if (studiosNameImagesImageTypeImageIndexHeadImageType == null) { + return defaultValue ?? []; + } + + return studiosNameImagesImageTypeImageIndexHeadImageType + .map((e) => studiosNameImagesImageTypeImageIndexHeadImageTypeFromJson( + e.toString())) + .toList(); +} + +List? + studiosNameImagesImageTypeImageIndexHeadImageTypeNullableListFromJson( + List? studiosNameImagesImageTypeImageIndexHeadImageType, [ + List? defaultValue, +]) { + if (studiosNameImagesImageTypeImageIndexHeadImageType == null) { + return defaultValue; + } + + return studiosNameImagesImageTypeImageIndexHeadImageType + .map((e) => studiosNameImagesImageTypeImageIndexHeadImageTypeFromJson( + e.toString())) + .toList(); +} + +String? studiosNameImagesImageTypeImageIndexHeadFormatNullableToJson( + enums.StudiosNameImagesImageTypeImageIndexHeadFormat? + studiosNameImagesImageTypeImageIndexHeadFormat) { + return studiosNameImagesImageTypeImageIndexHeadFormat?.value; +} + +String? studiosNameImagesImageTypeImageIndexHeadFormatToJson( + enums.StudiosNameImagesImageTypeImageIndexHeadFormat + studiosNameImagesImageTypeImageIndexHeadFormat) { + return studiosNameImagesImageTypeImageIndexHeadFormat.value; +} + +enums.StudiosNameImagesImageTypeImageIndexHeadFormat + studiosNameImagesImageTypeImageIndexHeadFormatFromJson( + Object? studiosNameImagesImageTypeImageIndexHeadFormat, [ + enums.StudiosNameImagesImageTypeImageIndexHeadFormat? defaultValue, +]) { + return enums.StudiosNameImagesImageTypeImageIndexHeadFormat.values + .firstWhereOrNull((e) => + e.value == studiosNameImagesImageTypeImageIndexHeadFormat) ?? + defaultValue ?? + enums.StudiosNameImagesImageTypeImageIndexHeadFormat + .swaggerGeneratedUnknown; +} + +enums.StudiosNameImagesImageTypeImageIndexHeadFormat? + studiosNameImagesImageTypeImageIndexHeadFormatNullableFromJson( + Object? studiosNameImagesImageTypeImageIndexHeadFormat, [ + enums.StudiosNameImagesImageTypeImageIndexHeadFormat? defaultValue, +]) { + if (studiosNameImagesImageTypeImageIndexHeadFormat == null) { + return null; + } + return enums.StudiosNameImagesImageTypeImageIndexHeadFormat.values + .firstWhereOrNull((e) => + e.value == studiosNameImagesImageTypeImageIndexHeadFormat) ?? + defaultValue; +} + +String studiosNameImagesImageTypeImageIndexHeadFormatExplodedListToJson( + List? + studiosNameImagesImageTypeImageIndexHeadFormat) { + return studiosNameImagesImageTypeImageIndexHeadFormat + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List studiosNameImagesImageTypeImageIndexHeadFormatListToJson( + List? + studiosNameImagesImageTypeImageIndexHeadFormat) { + if (studiosNameImagesImageTypeImageIndexHeadFormat == null) { + return []; + } + + return studiosNameImagesImageTypeImageIndexHeadFormat + .map((e) => e.value!) + .toList(); +} + +List + studiosNameImagesImageTypeImageIndexHeadFormatListFromJson( + List? studiosNameImagesImageTypeImageIndexHeadFormat, [ + List? defaultValue, +]) { + if (studiosNameImagesImageTypeImageIndexHeadFormat == null) { + return defaultValue ?? []; + } + + return studiosNameImagesImageTypeImageIndexHeadFormat + .map((e) => + studiosNameImagesImageTypeImageIndexHeadFormatFromJson(e.toString())) + .toList(); +} + +List? + studiosNameImagesImageTypeImageIndexHeadFormatNullableListFromJson( + List? studiosNameImagesImageTypeImageIndexHeadFormat, [ + List? defaultValue, +]) { + if (studiosNameImagesImageTypeImageIndexHeadFormat == null) { + return defaultValue; + } + + return studiosNameImagesImageTypeImageIndexHeadFormat + .map((e) => + studiosNameImagesImageTypeImageIndexHeadFormatFromJson(e.toString())) + .toList(); +} + +String? userImageGetFormatNullableToJson( + enums.UserImageGetFormat? userImageGetFormat) { + return userImageGetFormat?.value; +} + +String? userImageGetFormatToJson(enums.UserImageGetFormat userImageGetFormat) { + return userImageGetFormat.value; +} + +enums.UserImageGetFormat userImageGetFormatFromJson( + Object? userImageGetFormat, [ + enums.UserImageGetFormat? defaultValue, +]) { + return enums.UserImageGetFormat.values + .firstWhereOrNull((e) => e.value == userImageGetFormat) ?? + defaultValue ?? + enums.UserImageGetFormat.swaggerGeneratedUnknown; +} + +enums.UserImageGetFormat? userImageGetFormatNullableFromJson( + Object? userImageGetFormat, [ + enums.UserImageGetFormat? defaultValue, +]) { + if (userImageGetFormat == null) { + return null; + } + return enums.UserImageGetFormat.values + .firstWhereOrNull((e) => e.value == userImageGetFormat) ?? + defaultValue; +} + +String userImageGetFormatExplodedListToJson( + List? userImageGetFormat) { + return userImageGetFormat?.map((e) => e.value!).join(',') ?? ''; +} + +List userImageGetFormatListToJson( + List? userImageGetFormat) { + if (userImageGetFormat == null) { + return []; + } + + return userImageGetFormat.map((e) => e.value!).toList(); +} + +List userImageGetFormatListFromJson( + List? userImageGetFormat, [ + List? defaultValue, +]) { + if (userImageGetFormat == null) { + return defaultValue ?? []; + } + + return userImageGetFormat + .map((e) => userImageGetFormatFromJson(e.toString())) + .toList(); +} + +List? userImageGetFormatNullableListFromJson( + List? userImageGetFormat, [ + List? defaultValue, +]) { + if (userImageGetFormat == null) { + return defaultValue; + } + + return userImageGetFormat + .map((e) => userImageGetFormatFromJson(e.toString())) + .toList(); +} + +String? userImageHeadFormatNullableToJson( + enums.UserImageHeadFormat? userImageHeadFormat) { + return userImageHeadFormat?.value; +} + +String? userImageHeadFormatToJson( + enums.UserImageHeadFormat userImageHeadFormat) { + return userImageHeadFormat.value; +} + +enums.UserImageHeadFormat userImageHeadFormatFromJson( + Object? userImageHeadFormat, [ + enums.UserImageHeadFormat? defaultValue, +]) { + return enums.UserImageHeadFormat.values + .firstWhereOrNull((e) => e.value == userImageHeadFormat) ?? + defaultValue ?? + enums.UserImageHeadFormat.swaggerGeneratedUnknown; +} + +enums.UserImageHeadFormat? userImageHeadFormatNullableFromJson( + Object? userImageHeadFormat, [ + enums.UserImageHeadFormat? defaultValue, +]) { + if (userImageHeadFormat == null) { + return null; + } + return enums.UserImageHeadFormat.values + .firstWhereOrNull((e) => e.value == userImageHeadFormat) ?? + defaultValue; +} + +String userImageHeadFormatExplodedListToJson( + List? userImageHeadFormat) { + return userImageHeadFormat?.map((e) => e.value!).join(',') ?? ''; +} + +List userImageHeadFormatListToJson( + List? userImageHeadFormat) { + if (userImageHeadFormat == null) { + return []; + } + + return userImageHeadFormat.map((e) => e.value!).toList(); +} + +List userImageHeadFormatListFromJson( + List? userImageHeadFormat, [ + List? defaultValue, +]) { + if (userImageHeadFormat == null) { + return defaultValue ?? []; + } + + return userImageHeadFormat + .map((e) => userImageHeadFormatFromJson(e.toString())) + .toList(); +} + +List? userImageHeadFormatNullableListFromJson( + List? userImageHeadFormat, [ + List? defaultValue, +]) { + if (userImageHeadFormat == null) { + return defaultValue; + } + + return userImageHeadFormat + .map((e) => userImageHeadFormatFromJson(e.toString())) + .toList(); +} + +String? itemsItemIdRefreshPostMetadataRefreshModeNullableToJson( + enums.ItemsItemIdRefreshPostMetadataRefreshMode? + itemsItemIdRefreshPostMetadataRefreshMode) { + return itemsItemIdRefreshPostMetadataRefreshMode?.value; +} + +String? itemsItemIdRefreshPostMetadataRefreshModeToJson( + enums.ItemsItemIdRefreshPostMetadataRefreshMode + itemsItemIdRefreshPostMetadataRefreshMode) { + return itemsItemIdRefreshPostMetadataRefreshMode.value; +} + +enums.ItemsItemIdRefreshPostMetadataRefreshMode + itemsItemIdRefreshPostMetadataRefreshModeFromJson( + Object? itemsItemIdRefreshPostMetadataRefreshMode, [ + enums.ItemsItemIdRefreshPostMetadataRefreshMode? defaultValue, +]) { + return enums.ItemsItemIdRefreshPostMetadataRefreshMode.values + .firstWhereOrNull( + (e) => e.value == itemsItemIdRefreshPostMetadataRefreshMode) ?? + defaultValue ?? + enums.ItemsItemIdRefreshPostMetadataRefreshMode.swaggerGeneratedUnknown; +} + +enums.ItemsItemIdRefreshPostMetadataRefreshMode? + itemsItemIdRefreshPostMetadataRefreshModeNullableFromJson( + Object? itemsItemIdRefreshPostMetadataRefreshMode, [ + enums.ItemsItemIdRefreshPostMetadataRefreshMode? defaultValue, +]) { + if (itemsItemIdRefreshPostMetadataRefreshMode == null) { + return null; + } + return enums.ItemsItemIdRefreshPostMetadataRefreshMode.values + .firstWhereOrNull( + (e) => e.value == itemsItemIdRefreshPostMetadataRefreshMode) ?? + defaultValue; +} + +String itemsItemIdRefreshPostMetadataRefreshModeExplodedListToJson( + List? + itemsItemIdRefreshPostMetadataRefreshMode) { + return itemsItemIdRefreshPostMetadataRefreshMode + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List itemsItemIdRefreshPostMetadataRefreshModeListToJson( + List? + itemsItemIdRefreshPostMetadataRefreshMode) { + if (itemsItemIdRefreshPostMetadataRefreshMode == null) { + return []; + } + + return itemsItemIdRefreshPostMetadataRefreshMode + .map((e) => e.value!) + .toList(); +} + +List + itemsItemIdRefreshPostMetadataRefreshModeListFromJson( + List? itemsItemIdRefreshPostMetadataRefreshMode, [ + List? defaultValue, +]) { + if (itemsItemIdRefreshPostMetadataRefreshMode == null) { + return defaultValue ?? []; + } + + return itemsItemIdRefreshPostMetadataRefreshMode + .map((e) => + itemsItemIdRefreshPostMetadataRefreshModeFromJson(e.toString())) + .toList(); +} + +List? + itemsItemIdRefreshPostMetadataRefreshModeNullableListFromJson( + List? itemsItemIdRefreshPostMetadataRefreshMode, [ + List? defaultValue, +]) { + if (itemsItemIdRefreshPostMetadataRefreshMode == null) { + return defaultValue; + } + + return itemsItemIdRefreshPostMetadataRefreshMode + .map((e) => + itemsItemIdRefreshPostMetadataRefreshModeFromJson(e.toString())) + .toList(); +} + +String? itemsItemIdRefreshPostImageRefreshModeNullableToJson( + enums.ItemsItemIdRefreshPostImageRefreshMode? + itemsItemIdRefreshPostImageRefreshMode) { + return itemsItemIdRefreshPostImageRefreshMode?.value; +} + +String? itemsItemIdRefreshPostImageRefreshModeToJson( + enums.ItemsItemIdRefreshPostImageRefreshMode + itemsItemIdRefreshPostImageRefreshMode) { + return itemsItemIdRefreshPostImageRefreshMode.value; +} + +enums.ItemsItemIdRefreshPostImageRefreshMode + itemsItemIdRefreshPostImageRefreshModeFromJson( + Object? itemsItemIdRefreshPostImageRefreshMode, [ + enums.ItemsItemIdRefreshPostImageRefreshMode? defaultValue, +]) { + return enums.ItemsItemIdRefreshPostImageRefreshMode.values.firstWhereOrNull( + (e) => e.value == itemsItemIdRefreshPostImageRefreshMode) ?? + defaultValue ?? + enums.ItemsItemIdRefreshPostImageRefreshMode.swaggerGeneratedUnknown; +} + +enums.ItemsItemIdRefreshPostImageRefreshMode? + itemsItemIdRefreshPostImageRefreshModeNullableFromJson( + Object? itemsItemIdRefreshPostImageRefreshMode, [ + enums.ItemsItemIdRefreshPostImageRefreshMode? defaultValue, +]) { + if (itemsItemIdRefreshPostImageRefreshMode == null) { + return null; + } + return enums.ItemsItemIdRefreshPostImageRefreshMode.values.firstWhereOrNull( + (e) => e.value == itemsItemIdRefreshPostImageRefreshMode) ?? + defaultValue; +} + +String itemsItemIdRefreshPostImageRefreshModeExplodedListToJson( + List? + itemsItemIdRefreshPostImageRefreshMode) { + return itemsItemIdRefreshPostImageRefreshMode + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List itemsItemIdRefreshPostImageRefreshModeListToJson( + List? + itemsItemIdRefreshPostImageRefreshMode) { + if (itemsItemIdRefreshPostImageRefreshMode == null) { + return []; + } + + return itemsItemIdRefreshPostImageRefreshMode.map((e) => e.value!).toList(); +} + +List + itemsItemIdRefreshPostImageRefreshModeListFromJson( + List? itemsItemIdRefreshPostImageRefreshMode, [ + List? defaultValue, +]) { + if (itemsItemIdRefreshPostImageRefreshMode == null) { + return defaultValue ?? []; + } + + return itemsItemIdRefreshPostImageRefreshMode + .map((e) => itemsItemIdRefreshPostImageRefreshModeFromJson(e.toString())) + .toList(); +} + +List? + itemsItemIdRefreshPostImageRefreshModeNullableListFromJson( + List? itemsItemIdRefreshPostImageRefreshMode, [ + List? defaultValue, +]) { + if (itemsItemIdRefreshPostImageRefreshMode == null) { + return defaultValue; + } + + return itemsItemIdRefreshPostImageRefreshMode + .map((e) => itemsItemIdRefreshPostImageRefreshModeFromJson(e.toString())) + .toList(); +} + +String? librariesAvailableOptionsGetLibraryContentTypeNullableToJson( + enums.LibrariesAvailableOptionsGetLibraryContentType? + librariesAvailableOptionsGetLibraryContentType) { + return librariesAvailableOptionsGetLibraryContentType?.value; +} + +String? librariesAvailableOptionsGetLibraryContentTypeToJson( + enums.LibrariesAvailableOptionsGetLibraryContentType + librariesAvailableOptionsGetLibraryContentType) { + return librariesAvailableOptionsGetLibraryContentType.value; +} + +enums.LibrariesAvailableOptionsGetLibraryContentType + librariesAvailableOptionsGetLibraryContentTypeFromJson( + Object? librariesAvailableOptionsGetLibraryContentType, [ + enums.LibrariesAvailableOptionsGetLibraryContentType? defaultValue, +]) { + return enums.LibrariesAvailableOptionsGetLibraryContentType.values + .firstWhereOrNull((e) => + e.value == librariesAvailableOptionsGetLibraryContentType) ?? + defaultValue ?? + enums.LibrariesAvailableOptionsGetLibraryContentType + .swaggerGeneratedUnknown; +} + +enums.LibrariesAvailableOptionsGetLibraryContentType? + librariesAvailableOptionsGetLibraryContentTypeNullableFromJson( + Object? librariesAvailableOptionsGetLibraryContentType, [ + enums.LibrariesAvailableOptionsGetLibraryContentType? defaultValue, +]) { + if (librariesAvailableOptionsGetLibraryContentType == null) { + return null; + } + return enums.LibrariesAvailableOptionsGetLibraryContentType.values + .firstWhereOrNull((e) => + e.value == librariesAvailableOptionsGetLibraryContentType) ?? + defaultValue; +} + +String librariesAvailableOptionsGetLibraryContentTypeExplodedListToJson( + List? + librariesAvailableOptionsGetLibraryContentType) { + return librariesAvailableOptionsGetLibraryContentType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List librariesAvailableOptionsGetLibraryContentTypeListToJson( + List? + librariesAvailableOptionsGetLibraryContentType) { + if (librariesAvailableOptionsGetLibraryContentType == null) { + return []; + } + + return librariesAvailableOptionsGetLibraryContentType + .map((e) => e.value!) + .toList(); +} + +List + librariesAvailableOptionsGetLibraryContentTypeListFromJson( + List? librariesAvailableOptionsGetLibraryContentType, [ + List? defaultValue, +]) { + if (librariesAvailableOptionsGetLibraryContentType == null) { + return defaultValue ?? []; + } + + return librariesAvailableOptionsGetLibraryContentType + .map((e) => + librariesAvailableOptionsGetLibraryContentTypeFromJson(e.toString())) + .toList(); +} + +List? + librariesAvailableOptionsGetLibraryContentTypeNullableListFromJson( + List? librariesAvailableOptionsGetLibraryContentType, [ + List? defaultValue, +]) { + if (librariesAvailableOptionsGetLibraryContentType == null) { + return defaultValue; + } + + return librariesAvailableOptionsGetLibraryContentType + .map((e) => + librariesAvailableOptionsGetLibraryContentTypeFromJson(e.toString())) + .toList(); +} + +String? libraryVirtualFoldersPostCollectionTypeNullableToJson( + enums.LibraryVirtualFoldersPostCollectionType? + libraryVirtualFoldersPostCollectionType) { + return libraryVirtualFoldersPostCollectionType?.value; +} + +String? libraryVirtualFoldersPostCollectionTypeToJson( + enums.LibraryVirtualFoldersPostCollectionType + libraryVirtualFoldersPostCollectionType) { + return libraryVirtualFoldersPostCollectionType.value; +} + +enums.LibraryVirtualFoldersPostCollectionType + libraryVirtualFoldersPostCollectionTypeFromJson( + Object? libraryVirtualFoldersPostCollectionType, [ + enums.LibraryVirtualFoldersPostCollectionType? defaultValue, +]) { + return enums.LibraryVirtualFoldersPostCollectionType.values.firstWhereOrNull( + (e) => e.value == libraryVirtualFoldersPostCollectionType) ?? + defaultValue ?? + enums.LibraryVirtualFoldersPostCollectionType.swaggerGeneratedUnknown; +} + +enums.LibraryVirtualFoldersPostCollectionType? + libraryVirtualFoldersPostCollectionTypeNullableFromJson( + Object? libraryVirtualFoldersPostCollectionType, [ + enums.LibraryVirtualFoldersPostCollectionType? defaultValue, +]) { + if (libraryVirtualFoldersPostCollectionType == null) { + return null; + } + return enums.LibraryVirtualFoldersPostCollectionType.values.firstWhereOrNull( + (e) => e.value == libraryVirtualFoldersPostCollectionType) ?? + defaultValue; +} + +String libraryVirtualFoldersPostCollectionTypeExplodedListToJson( + List? + libraryVirtualFoldersPostCollectionType) { + return libraryVirtualFoldersPostCollectionType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List libraryVirtualFoldersPostCollectionTypeListToJson( + List? + libraryVirtualFoldersPostCollectionType) { + if (libraryVirtualFoldersPostCollectionType == null) { + return []; + } + + return libraryVirtualFoldersPostCollectionType.map((e) => e.value!).toList(); +} + +List + libraryVirtualFoldersPostCollectionTypeListFromJson( + List? libraryVirtualFoldersPostCollectionType, [ + List? defaultValue, +]) { + if (libraryVirtualFoldersPostCollectionType == null) { + return defaultValue ?? []; + } + + return libraryVirtualFoldersPostCollectionType + .map((e) => libraryVirtualFoldersPostCollectionTypeFromJson(e.toString())) + .toList(); +} + +List? + libraryVirtualFoldersPostCollectionTypeNullableListFromJson( + List? libraryVirtualFoldersPostCollectionType, [ + List? defaultValue, +]) { + if (libraryVirtualFoldersPostCollectionType == null) { + return defaultValue; + } + + return libraryVirtualFoldersPostCollectionType + .map((e) => libraryVirtualFoldersPostCollectionTypeFromJson(e.toString())) + .toList(); +} + +String? liveTvChannelsGetTypeNullableToJson( + enums.LiveTvChannelsGetType? liveTvChannelsGetType) { + return liveTvChannelsGetType?.value; +} + +String? liveTvChannelsGetTypeToJson( + enums.LiveTvChannelsGetType liveTvChannelsGetType) { + return liveTvChannelsGetType.value; +} + +enums.LiveTvChannelsGetType liveTvChannelsGetTypeFromJson( + Object? liveTvChannelsGetType, [ + enums.LiveTvChannelsGetType? defaultValue, +]) { + return enums.LiveTvChannelsGetType.values + .firstWhereOrNull((e) => e.value == liveTvChannelsGetType) ?? + defaultValue ?? + enums.LiveTvChannelsGetType.swaggerGeneratedUnknown; +} + +enums.LiveTvChannelsGetType? liveTvChannelsGetTypeNullableFromJson( + Object? liveTvChannelsGetType, [ + enums.LiveTvChannelsGetType? defaultValue, +]) { + if (liveTvChannelsGetType == null) { + return null; + } + return enums.LiveTvChannelsGetType.values + .firstWhereOrNull((e) => e.value == liveTvChannelsGetType) ?? + defaultValue; +} + +String liveTvChannelsGetTypeExplodedListToJson( + List? liveTvChannelsGetType) { + return liveTvChannelsGetType?.map((e) => e.value!).join(',') ?? ''; +} + +List liveTvChannelsGetTypeListToJson( + List? liveTvChannelsGetType) { + if (liveTvChannelsGetType == null) { + return []; + } + + return liveTvChannelsGetType.map((e) => e.value!).toList(); +} + +List liveTvChannelsGetTypeListFromJson( + List? liveTvChannelsGetType, [ + List? defaultValue, +]) { + if (liveTvChannelsGetType == null) { + return defaultValue ?? []; + } + + return liveTvChannelsGetType + .map((e) => liveTvChannelsGetTypeFromJson(e.toString())) + .toList(); +} + +List? liveTvChannelsGetTypeNullableListFromJson( + List? liveTvChannelsGetType, [ + List? defaultValue, +]) { + if (liveTvChannelsGetType == null) { + return defaultValue; + } + + return liveTvChannelsGetType + .map((e) => liveTvChannelsGetTypeFromJson(e.toString())) + .toList(); +} + +String? liveTvChannelsGetSortOrderNullableToJson( + enums.LiveTvChannelsGetSortOrder? liveTvChannelsGetSortOrder) { + return liveTvChannelsGetSortOrder?.value; +} + +String? liveTvChannelsGetSortOrderToJson( + enums.LiveTvChannelsGetSortOrder liveTvChannelsGetSortOrder) { + return liveTvChannelsGetSortOrder.value; +} + +enums.LiveTvChannelsGetSortOrder liveTvChannelsGetSortOrderFromJson( + Object? liveTvChannelsGetSortOrder, [ + enums.LiveTvChannelsGetSortOrder? defaultValue, +]) { + return enums.LiveTvChannelsGetSortOrder.values + .firstWhereOrNull((e) => e.value == liveTvChannelsGetSortOrder) ?? + defaultValue ?? + enums.LiveTvChannelsGetSortOrder.swaggerGeneratedUnknown; +} + +enums.LiveTvChannelsGetSortOrder? liveTvChannelsGetSortOrderNullableFromJson( + Object? liveTvChannelsGetSortOrder, [ + enums.LiveTvChannelsGetSortOrder? defaultValue, +]) { + if (liveTvChannelsGetSortOrder == null) { + return null; + } + return enums.LiveTvChannelsGetSortOrder.values + .firstWhereOrNull((e) => e.value == liveTvChannelsGetSortOrder) ?? + defaultValue; +} + +String liveTvChannelsGetSortOrderExplodedListToJson( + List? liveTvChannelsGetSortOrder) { + return liveTvChannelsGetSortOrder?.map((e) => e.value!).join(',') ?? ''; +} + +List liveTvChannelsGetSortOrderListToJson( + List? liveTvChannelsGetSortOrder) { + if (liveTvChannelsGetSortOrder == null) { + return []; + } + + return liveTvChannelsGetSortOrder.map((e) => e.value!).toList(); +} + +List liveTvChannelsGetSortOrderListFromJson( + List? liveTvChannelsGetSortOrder, [ + List? defaultValue, +]) { + if (liveTvChannelsGetSortOrder == null) { + return defaultValue ?? []; + } + + return liveTvChannelsGetSortOrder + .map((e) => liveTvChannelsGetSortOrderFromJson(e.toString())) + .toList(); +} + +List? + liveTvChannelsGetSortOrderNullableListFromJson( + List? liveTvChannelsGetSortOrder, [ + List? defaultValue, +]) { + if (liveTvChannelsGetSortOrder == null) { + return defaultValue; + } + + return liveTvChannelsGetSortOrder + .map((e) => liveTvChannelsGetSortOrderFromJson(e.toString())) + .toList(); +} + +String? liveTvRecordingsGetStatusNullableToJson( + enums.LiveTvRecordingsGetStatus? liveTvRecordingsGetStatus) { + return liveTvRecordingsGetStatus?.value; +} + +String? liveTvRecordingsGetStatusToJson( + enums.LiveTvRecordingsGetStatus liveTvRecordingsGetStatus) { + return liveTvRecordingsGetStatus.value; +} + +enums.LiveTvRecordingsGetStatus liveTvRecordingsGetStatusFromJson( + Object? liveTvRecordingsGetStatus, [ + enums.LiveTvRecordingsGetStatus? defaultValue, +]) { + return enums.LiveTvRecordingsGetStatus.values + .firstWhereOrNull((e) => e.value == liveTvRecordingsGetStatus) ?? + defaultValue ?? + enums.LiveTvRecordingsGetStatus.swaggerGeneratedUnknown; +} + +enums.LiveTvRecordingsGetStatus? liveTvRecordingsGetStatusNullableFromJson( + Object? liveTvRecordingsGetStatus, [ + enums.LiveTvRecordingsGetStatus? defaultValue, +]) { + if (liveTvRecordingsGetStatus == null) { + return null; + } + return enums.LiveTvRecordingsGetStatus.values + .firstWhereOrNull((e) => e.value == liveTvRecordingsGetStatus) ?? + defaultValue; +} + +String liveTvRecordingsGetStatusExplodedListToJson( + List? liveTvRecordingsGetStatus) { + return liveTvRecordingsGetStatus?.map((e) => e.value!).join(',') ?? ''; +} + +List liveTvRecordingsGetStatusListToJson( + List? liveTvRecordingsGetStatus) { + if (liveTvRecordingsGetStatus == null) { + return []; + } + + return liveTvRecordingsGetStatus.map((e) => e.value!).toList(); +} + +List liveTvRecordingsGetStatusListFromJson( + List? liveTvRecordingsGetStatus, [ + List? defaultValue, +]) { + if (liveTvRecordingsGetStatus == null) { + return defaultValue ?? []; + } + + return liveTvRecordingsGetStatus + .map((e) => liveTvRecordingsGetStatusFromJson(e.toString())) + .toList(); +} + +List? + liveTvRecordingsGetStatusNullableListFromJson( + List? liveTvRecordingsGetStatus, [ + List? defaultValue, +]) { + if (liveTvRecordingsGetStatus == null) { + return defaultValue; + } + + return liveTvRecordingsGetStatus + .map((e) => liveTvRecordingsGetStatusFromJson(e.toString())) + .toList(); +} + +String? liveTvRecordingsSeriesGetStatusNullableToJson( + enums.LiveTvRecordingsSeriesGetStatus? liveTvRecordingsSeriesGetStatus) { + return liveTvRecordingsSeriesGetStatus?.value; +} + +String? liveTvRecordingsSeriesGetStatusToJson( + enums.LiveTvRecordingsSeriesGetStatus liveTvRecordingsSeriesGetStatus) { + return liveTvRecordingsSeriesGetStatus.value; +} + +enums.LiveTvRecordingsSeriesGetStatus liveTvRecordingsSeriesGetStatusFromJson( + Object? liveTvRecordingsSeriesGetStatus, [ + enums.LiveTvRecordingsSeriesGetStatus? defaultValue, +]) { + return enums.LiveTvRecordingsSeriesGetStatus.values.firstWhereOrNull( + (e) => e.value == liveTvRecordingsSeriesGetStatus) ?? + defaultValue ?? + enums.LiveTvRecordingsSeriesGetStatus.swaggerGeneratedUnknown; +} + +enums.LiveTvRecordingsSeriesGetStatus? + liveTvRecordingsSeriesGetStatusNullableFromJson( + Object? liveTvRecordingsSeriesGetStatus, [ + enums.LiveTvRecordingsSeriesGetStatus? defaultValue, +]) { + if (liveTvRecordingsSeriesGetStatus == null) { + return null; + } + return enums.LiveTvRecordingsSeriesGetStatus.values.firstWhereOrNull( + (e) => e.value == liveTvRecordingsSeriesGetStatus) ?? + defaultValue; +} + +String liveTvRecordingsSeriesGetStatusExplodedListToJson( + List? + liveTvRecordingsSeriesGetStatus) { + return liveTvRecordingsSeriesGetStatus?.map((e) => e.value!).join(',') ?? ''; +} + +List liveTvRecordingsSeriesGetStatusListToJson( + List? + liveTvRecordingsSeriesGetStatus) { + if (liveTvRecordingsSeriesGetStatus == null) { + return []; + } + + return liveTvRecordingsSeriesGetStatus.map((e) => e.value!).toList(); +} + +List + liveTvRecordingsSeriesGetStatusListFromJson( + List? liveTvRecordingsSeriesGetStatus, [ + List? defaultValue, +]) { + if (liveTvRecordingsSeriesGetStatus == null) { + return defaultValue ?? []; + } + + return liveTvRecordingsSeriesGetStatus + .map((e) => liveTvRecordingsSeriesGetStatusFromJson(e.toString())) + .toList(); +} + +List? + liveTvRecordingsSeriesGetStatusNullableListFromJson( + List? liveTvRecordingsSeriesGetStatus, [ + List? defaultValue, +]) { + if (liveTvRecordingsSeriesGetStatus == null) { + return defaultValue; + } + + return liveTvRecordingsSeriesGetStatus + .map((e) => liveTvRecordingsSeriesGetStatusFromJson(e.toString())) + .toList(); +} + +String? liveTvSeriesTimersGetSortOrderNullableToJson( + enums.LiveTvSeriesTimersGetSortOrder? liveTvSeriesTimersGetSortOrder) { + return liveTvSeriesTimersGetSortOrder?.value; +} + +String? liveTvSeriesTimersGetSortOrderToJson( + enums.LiveTvSeriesTimersGetSortOrder liveTvSeriesTimersGetSortOrder) { + return liveTvSeriesTimersGetSortOrder.value; +} + +enums.LiveTvSeriesTimersGetSortOrder liveTvSeriesTimersGetSortOrderFromJson( + Object? liveTvSeriesTimersGetSortOrder, [ + enums.LiveTvSeriesTimersGetSortOrder? defaultValue, +]) { + return enums.LiveTvSeriesTimersGetSortOrder.values + .firstWhereOrNull((e) => e.value == liveTvSeriesTimersGetSortOrder) ?? + defaultValue ?? + enums.LiveTvSeriesTimersGetSortOrder.swaggerGeneratedUnknown; +} + +enums.LiveTvSeriesTimersGetSortOrder? + liveTvSeriesTimersGetSortOrderNullableFromJson( + Object? liveTvSeriesTimersGetSortOrder, [ + enums.LiveTvSeriesTimersGetSortOrder? defaultValue, +]) { + if (liveTvSeriesTimersGetSortOrder == null) { + return null; + } + return enums.LiveTvSeriesTimersGetSortOrder.values + .firstWhereOrNull((e) => e.value == liveTvSeriesTimersGetSortOrder) ?? + defaultValue; +} + +String liveTvSeriesTimersGetSortOrderExplodedListToJson( + List? + liveTvSeriesTimersGetSortOrder) { + return liveTvSeriesTimersGetSortOrder?.map((e) => e.value!).join(',') ?? ''; +} + +List liveTvSeriesTimersGetSortOrderListToJson( + List? + liveTvSeriesTimersGetSortOrder) { + if (liveTvSeriesTimersGetSortOrder == null) { + return []; + } + + return liveTvSeriesTimersGetSortOrder.map((e) => e.value!).toList(); +} + +List + liveTvSeriesTimersGetSortOrderListFromJson( + List? liveTvSeriesTimersGetSortOrder, [ + List? defaultValue, +]) { + if (liveTvSeriesTimersGetSortOrder == null) { + return defaultValue ?? []; + } + + return liveTvSeriesTimersGetSortOrder + .map((e) => liveTvSeriesTimersGetSortOrderFromJson(e.toString())) + .toList(); +} + +List? + liveTvSeriesTimersGetSortOrderNullableListFromJson( + List? liveTvSeriesTimersGetSortOrder, [ + List? defaultValue, +]) { + if (liveTvSeriesTimersGetSortOrder == null) { + return defaultValue; + } + + return liveTvSeriesTimersGetSortOrder + .map((e) => liveTvSeriesTimersGetSortOrderFromJson(e.toString())) + .toList(); +} + +String? playlistsPostMediaTypeNullableToJson( + enums.PlaylistsPostMediaType? playlistsPostMediaType) { + return playlistsPostMediaType?.value; +} + +String? playlistsPostMediaTypeToJson( + enums.PlaylistsPostMediaType playlistsPostMediaType) { + return playlistsPostMediaType.value; +} + +enums.PlaylistsPostMediaType playlistsPostMediaTypeFromJson( + Object? playlistsPostMediaType, [ + enums.PlaylistsPostMediaType? defaultValue, +]) { + return enums.PlaylistsPostMediaType.values + .firstWhereOrNull((e) => e.value == playlistsPostMediaType) ?? + defaultValue ?? + enums.PlaylistsPostMediaType.swaggerGeneratedUnknown; +} + +enums.PlaylistsPostMediaType? playlistsPostMediaTypeNullableFromJson( + Object? playlistsPostMediaType, [ + enums.PlaylistsPostMediaType? defaultValue, +]) { + if (playlistsPostMediaType == null) { + return null; + } + return enums.PlaylistsPostMediaType.values + .firstWhereOrNull((e) => e.value == playlistsPostMediaType) ?? + defaultValue; +} + +String playlistsPostMediaTypeExplodedListToJson( + List? playlistsPostMediaType) { + return playlistsPostMediaType?.map((e) => e.value!).join(',') ?? ''; +} + +List playlistsPostMediaTypeListToJson( + List? playlistsPostMediaType) { + if (playlistsPostMediaType == null) { + return []; + } + + return playlistsPostMediaType.map((e) => e.value!).toList(); +} + +List playlistsPostMediaTypeListFromJson( + List? playlistsPostMediaType, [ + List? defaultValue, +]) { + if (playlistsPostMediaType == null) { + return defaultValue ?? []; + } + + return playlistsPostMediaType + .map((e) => playlistsPostMediaTypeFromJson(e.toString())) + .toList(); +} + +List? playlistsPostMediaTypeNullableListFromJson( + List? playlistsPostMediaType, [ + List? defaultValue, +]) { + if (playlistsPostMediaType == null) { + return defaultValue; + } + + return playlistsPostMediaType + .map((e) => playlistsPostMediaTypeFromJson(e.toString())) + .toList(); +} + +String? playingItemsItemIdPostPlayMethodNullableToJson( + enums.PlayingItemsItemIdPostPlayMethod? playingItemsItemIdPostPlayMethod) { + return playingItemsItemIdPostPlayMethod?.value; +} + +String? playingItemsItemIdPostPlayMethodToJson( + enums.PlayingItemsItemIdPostPlayMethod playingItemsItemIdPostPlayMethod) { + return playingItemsItemIdPostPlayMethod.value; +} + +enums.PlayingItemsItemIdPostPlayMethod playingItemsItemIdPostPlayMethodFromJson( + Object? playingItemsItemIdPostPlayMethod, [ + enums.PlayingItemsItemIdPostPlayMethod? defaultValue, +]) { + return enums.PlayingItemsItemIdPostPlayMethod.values.firstWhereOrNull( + (e) => e.value == playingItemsItemIdPostPlayMethod) ?? + defaultValue ?? + enums.PlayingItemsItemIdPostPlayMethod.swaggerGeneratedUnknown; +} + +enums.PlayingItemsItemIdPostPlayMethod? + playingItemsItemIdPostPlayMethodNullableFromJson( + Object? playingItemsItemIdPostPlayMethod, [ + enums.PlayingItemsItemIdPostPlayMethod? defaultValue, +]) { + if (playingItemsItemIdPostPlayMethod == null) { + return null; + } + return enums.PlayingItemsItemIdPostPlayMethod.values.firstWhereOrNull( + (e) => e.value == playingItemsItemIdPostPlayMethod) ?? + defaultValue; +} + +String playingItemsItemIdPostPlayMethodExplodedListToJson( + List? + playingItemsItemIdPostPlayMethod) { + return playingItemsItemIdPostPlayMethod?.map((e) => e.value!).join(',') ?? ''; +} + +List playingItemsItemIdPostPlayMethodListToJson( + List? + playingItemsItemIdPostPlayMethod) { + if (playingItemsItemIdPostPlayMethod == null) { + return []; + } + + return playingItemsItemIdPostPlayMethod.map((e) => e.value!).toList(); +} + +List + playingItemsItemIdPostPlayMethodListFromJson( + List? playingItemsItemIdPostPlayMethod, [ + List? defaultValue, +]) { + if (playingItemsItemIdPostPlayMethod == null) { + return defaultValue ?? []; + } + + return playingItemsItemIdPostPlayMethod + .map((e) => playingItemsItemIdPostPlayMethodFromJson(e.toString())) + .toList(); +} + +List? + playingItemsItemIdPostPlayMethodNullableListFromJson( + List? playingItemsItemIdPostPlayMethod, [ + List? defaultValue, +]) { + if (playingItemsItemIdPostPlayMethod == null) { + return defaultValue; + } + + return playingItemsItemIdPostPlayMethod + .map((e) => playingItemsItemIdPostPlayMethodFromJson(e.toString())) + .toList(); +} + +String? playingItemsItemIdProgressPostPlayMethodNullableToJson( + enums.PlayingItemsItemIdProgressPostPlayMethod? + playingItemsItemIdProgressPostPlayMethod) { + return playingItemsItemIdProgressPostPlayMethod?.value; +} + +String? playingItemsItemIdProgressPostPlayMethodToJson( + enums.PlayingItemsItemIdProgressPostPlayMethod + playingItemsItemIdProgressPostPlayMethod) { + return playingItemsItemIdProgressPostPlayMethod.value; +} + +enums.PlayingItemsItemIdProgressPostPlayMethod + playingItemsItemIdProgressPostPlayMethodFromJson( + Object? playingItemsItemIdProgressPostPlayMethod, [ + enums.PlayingItemsItemIdProgressPostPlayMethod? defaultValue, +]) { + return enums.PlayingItemsItemIdProgressPostPlayMethod.values.firstWhereOrNull( + (e) => e.value == playingItemsItemIdProgressPostPlayMethod) ?? + defaultValue ?? + enums.PlayingItemsItemIdProgressPostPlayMethod.swaggerGeneratedUnknown; +} + +enums.PlayingItemsItemIdProgressPostPlayMethod? + playingItemsItemIdProgressPostPlayMethodNullableFromJson( + Object? playingItemsItemIdProgressPostPlayMethod, [ + enums.PlayingItemsItemIdProgressPostPlayMethod? defaultValue, +]) { + if (playingItemsItemIdProgressPostPlayMethod == null) { + return null; + } + return enums.PlayingItemsItemIdProgressPostPlayMethod.values.firstWhereOrNull( + (e) => e.value == playingItemsItemIdProgressPostPlayMethod) ?? + defaultValue; +} + +String playingItemsItemIdProgressPostPlayMethodExplodedListToJson( + List? + playingItemsItemIdProgressPostPlayMethod) { + return playingItemsItemIdProgressPostPlayMethod + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List playingItemsItemIdProgressPostPlayMethodListToJson( + List? + playingItemsItemIdProgressPostPlayMethod) { + if (playingItemsItemIdProgressPostPlayMethod == null) { + return []; + } + + return playingItemsItemIdProgressPostPlayMethod.map((e) => e.value!).toList(); +} + +List + playingItemsItemIdProgressPostPlayMethodListFromJson( + List? playingItemsItemIdProgressPostPlayMethod, [ + List? defaultValue, +]) { + if (playingItemsItemIdProgressPostPlayMethod == null) { + return defaultValue ?? []; + } + + return playingItemsItemIdProgressPostPlayMethod + .map( + (e) => playingItemsItemIdProgressPostPlayMethodFromJson(e.toString())) + .toList(); +} + +List? + playingItemsItemIdProgressPostPlayMethodNullableListFromJson( + List? playingItemsItemIdProgressPostPlayMethod, [ + List? defaultValue, +]) { + if (playingItemsItemIdProgressPostPlayMethod == null) { + return defaultValue; + } + + return playingItemsItemIdProgressPostPlayMethod + .map( + (e) => playingItemsItemIdProgressPostPlayMethodFromJson(e.toString())) + .toList(); +} + +String? playingItemsItemIdProgressPostRepeatModeNullableToJson( + enums.PlayingItemsItemIdProgressPostRepeatMode? + playingItemsItemIdProgressPostRepeatMode) { + return playingItemsItemIdProgressPostRepeatMode?.value; +} + +String? playingItemsItemIdProgressPostRepeatModeToJson( + enums.PlayingItemsItemIdProgressPostRepeatMode + playingItemsItemIdProgressPostRepeatMode) { + return playingItemsItemIdProgressPostRepeatMode.value; +} + +enums.PlayingItemsItemIdProgressPostRepeatMode + playingItemsItemIdProgressPostRepeatModeFromJson( + Object? playingItemsItemIdProgressPostRepeatMode, [ + enums.PlayingItemsItemIdProgressPostRepeatMode? defaultValue, +]) { + return enums.PlayingItemsItemIdProgressPostRepeatMode.values.firstWhereOrNull( + (e) => e.value == playingItemsItemIdProgressPostRepeatMode) ?? + defaultValue ?? + enums.PlayingItemsItemIdProgressPostRepeatMode.swaggerGeneratedUnknown; +} + +enums.PlayingItemsItemIdProgressPostRepeatMode? + playingItemsItemIdProgressPostRepeatModeNullableFromJson( + Object? playingItemsItemIdProgressPostRepeatMode, [ + enums.PlayingItemsItemIdProgressPostRepeatMode? defaultValue, +]) { + if (playingItemsItemIdProgressPostRepeatMode == null) { + return null; + } + return enums.PlayingItemsItemIdProgressPostRepeatMode.values.firstWhereOrNull( + (e) => e.value == playingItemsItemIdProgressPostRepeatMode) ?? + defaultValue; +} + +String playingItemsItemIdProgressPostRepeatModeExplodedListToJson( + List? + playingItemsItemIdProgressPostRepeatMode) { + return playingItemsItemIdProgressPostRepeatMode + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List playingItemsItemIdProgressPostRepeatModeListToJson( + List? + playingItemsItemIdProgressPostRepeatMode) { + if (playingItemsItemIdProgressPostRepeatMode == null) { + return []; + } + + return playingItemsItemIdProgressPostRepeatMode.map((e) => e.value!).toList(); +} + +List + playingItemsItemIdProgressPostRepeatModeListFromJson( + List? playingItemsItemIdProgressPostRepeatMode, [ + List? defaultValue, +]) { + if (playingItemsItemIdProgressPostRepeatMode == null) { + return defaultValue ?? []; + } + + return playingItemsItemIdProgressPostRepeatMode + .map( + (e) => playingItemsItemIdProgressPostRepeatModeFromJson(e.toString())) + .toList(); +} + +List? + playingItemsItemIdProgressPostRepeatModeNullableListFromJson( + List? playingItemsItemIdProgressPostRepeatMode, [ + List? defaultValue, +]) { + if (playingItemsItemIdProgressPostRepeatMode == null) { + return defaultValue; + } + + return playingItemsItemIdProgressPostRepeatMode + .map( + (e) => playingItemsItemIdProgressPostRepeatModeFromJson(e.toString())) + .toList(); +} + +String? itemsItemIdRemoteImagesGetTypeNullableToJson( + enums.ItemsItemIdRemoteImagesGetType? itemsItemIdRemoteImagesGetType) { + return itemsItemIdRemoteImagesGetType?.value; +} + +String? itemsItemIdRemoteImagesGetTypeToJson( + enums.ItemsItemIdRemoteImagesGetType itemsItemIdRemoteImagesGetType) { + return itemsItemIdRemoteImagesGetType.value; +} + +enums.ItemsItemIdRemoteImagesGetType itemsItemIdRemoteImagesGetTypeFromJson( + Object? itemsItemIdRemoteImagesGetType, [ + enums.ItemsItemIdRemoteImagesGetType? defaultValue, +]) { + return enums.ItemsItemIdRemoteImagesGetType.values + .firstWhereOrNull((e) => e.value == itemsItemIdRemoteImagesGetType) ?? + defaultValue ?? + enums.ItemsItemIdRemoteImagesGetType.swaggerGeneratedUnknown; +} + +enums.ItemsItemIdRemoteImagesGetType? + itemsItemIdRemoteImagesGetTypeNullableFromJson( + Object? itemsItemIdRemoteImagesGetType, [ + enums.ItemsItemIdRemoteImagesGetType? defaultValue, +]) { + if (itemsItemIdRemoteImagesGetType == null) { + return null; + } + return enums.ItemsItemIdRemoteImagesGetType.values + .firstWhereOrNull((e) => e.value == itemsItemIdRemoteImagesGetType) ?? + defaultValue; +} + +String itemsItemIdRemoteImagesGetTypeExplodedListToJson( + List? + itemsItemIdRemoteImagesGetType) { + return itemsItemIdRemoteImagesGetType?.map((e) => e.value!).join(',') ?? ''; +} + +List itemsItemIdRemoteImagesGetTypeListToJson( + List? + itemsItemIdRemoteImagesGetType) { + if (itemsItemIdRemoteImagesGetType == null) { + return []; + } + + return itemsItemIdRemoteImagesGetType.map((e) => e.value!).toList(); +} + +List + itemsItemIdRemoteImagesGetTypeListFromJson( + List? itemsItemIdRemoteImagesGetType, [ + List? defaultValue, +]) { + if (itemsItemIdRemoteImagesGetType == null) { + return defaultValue ?? []; + } + + return itemsItemIdRemoteImagesGetType + .map((e) => itemsItemIdRemoteImagesGetTypeFromJson(e.toString())) + .toList(); +} + +List? + itemsItemIdRemoteImagesGetTypeNullableListFromJson( + List? itemsItemIdRemoteImagesGetType, [ + List? defaultValue, +]) { + if (itemsItemIdRemoteImagesGetType == null) { + return defaultValue; + } + + return itemsItemIdRemoteImagesGetType + .map((e) => itemsItemIdRemoteImagesGetTypeFromJson(e.toString())) + .toList(); +} + +String? itemsItemIdRemoteImagesDownloadPostTypeNullableToJson( + enums.ItemsItemIdRemoteImagesDownloadPostType? + itemsItemIdRemoteImagesDownloadPostType) { + return itemsItemIdRemoteImagesDownloadPostType?.value; +} + +String? itemsItemIdRemoteImagesDownloadPostTypeToJson( + enums.ItemsItemIdRemoteImagesDownloadPostType + itemsItemIdRemoteImagesDownloadPostType) { + return itemsItemIdRemoteImagesDownloadPostType.value; +} + +enums.ItemsItemIdRemoteImagesDownloadPostType + itemsItemIdRemoteImagesDownloadPostTypeFromJson( + Object? itemsItemIdRemoteImagesDownloadPostType, [ + enums.ItemsItemIdRemoteImagesDownloadPostType? defaultValue, +]) { + return enums.ItemsItemIdRemoteImagesDownloadPostType.values.firstWhereOrNull( + (e) => e.value == itemsItemIdRemoteImagesDownloadPostType) ?? + defaultValue ?? + enums.ItemsItemIdRemoteImagesDownloadPostType.swaggerGeneratedUnknown; +} + +enums.ItemsItemIdRemoteImagesDownloadPostType? + itemsItemIdRemoteImagesDownloadPostTypeNullableFromJson( + Object? itemsItemIdRemoteImagesDownloadPostType, [ + enums.ItemsItemIdRemoteImagesDownloadPostType? defaultValue, +]) { + if (itemsItemIdRemoteImagesDownloadPostType == null) { + return null; + } + return enums.ItemsItemIdRemoteImagesDownloadPostType.values.firstWhereOrNull( + (e) => e.value == itemsItemIdRemoteImagesDownloadPostType) ?? + defaultValue; +} + +String itemsItemIdRemoteImagesDownloadPostTypeExplodedListToJson( + List? + itemsItemIdRemoteImagesDownloadPostType) { + return itemsItemIdRemoteImagesDownloadPostType + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List itemsItemIdRemoteImagesDownloadPostTypeListToJson( + List? + itemsItemIdRemoteImagesDownloadPostType) { + if (itemsItemIdRemoteImagesDownloadPostType == null) { + return []; + } + + return itemsItemIdRemoteImagesDownloadPostType.map((e) => e.value!).toList(); +} + +List + itemsItemIdRemoteImagesDownloadPostTypeListFromJson( + List? itemsItemIdRemoteImagesDownloadPostType, [ + List? defaultValue, +]) { + if (itemsItemIdRemoteImagesDownloadPostType == null) { + return defaultValue ?? []; + } + + return itemsItemIdRemoteImagesDownloadPostType + .map((e) => itemsItemIdRemoteImagesDownloadPostTypeFromJson(e.toString())) + .toList(); +} + +List? + itemsItemIdRemoteImagesDownloadPostTypeNullableListFromJson( + List? itemsItemIdRemoteImagesDownloadPostType, [ + List? defaultValue, +]) { + if (itemsItemIdRemoteImagesDownloadPostType == null) { + return defaultValue; + } + + return itemsItemIdRemoteImagesDownloadPostType + .map((e) => itemsItemIdRemoteImagesDownloadPostTypeFromJson(e.toString())) + .toList(); +} + +String? sessionsSessionIdCommandCommandPostCommandNullableToJson( + enums.SessionsSessionIdCommandCommandPostCommand? + sessionsSessionIdCommandCommandPostCommand) { + return sessionsSessionIdCommandCommandPostCommand?.value; +} + +String? sessionsSessionIdCommandCommandPostCommandToJson( + enums.SessionsSessionIdCommandCommandPostCommand + sessionsSessionIdCommandCommandPostCommand) { + return sessionsSessionIdCommandCommandPostCommand.value; +} + +enums.SessionsSessionIdCommandCommandPostCommand + sessionsSessionIdCommandCommandPostCommandFromJson( + Object? sessionsSessionIdCommandCommandPostCommand, [ + enums.SessionsSessionIdCommandCommandPostCommand? defaultValue, +]) { + return enums.SessionsSessionIdCommandCommandPostCommand.values + .firstWhereOrNull( + (e) => e.value == sessionsSessionIdCommandCommandPostCommand) ?? + defaultValue ?? + enums.SessionsSessionIdCommandCommandPostCommand.swaggerGeneratedUnknown; +} + +enums.SessionsSessionIdCommandCommandPostCommand? + sessionsSessionIdCommandCommandPostCommandNullableFromJson( + Object? sessionsSessionIdCommandCommandPostCommand, [ + enums.SessionsSessionIdCommandCommandPostCommand? defaultValue, +]) { + if (sessionsSessionIdCommandCommandPostCommand == null) { + return null; + } + return enums.SessionsSessionIdCommandCommandPostCommand.values + .firstWhereOrNull( + (e) => e.value == sessionsSessionIdCommandCommandPostCommand) ?? + defaultValue; +} + +String sessionsSessionIdCommandCommandPostCommandExplodedListToJson( + List? + sessionsSessionIdCommandCommandPostCommand) { + return sessionsSessionIdCommandCommandPostCommand + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List sessionsSessionIdCommandCommandPostCommandListToJson( + List? + sessionsSessionIdCommandCommandPostCommand) { + if (sessionsSessionIdCommandCommandPostCommand == null) { + return []; + } + + return sessionsSessionIdCommandCommandPostCommand + .map((e) => e.value!) + .toList(); +} + +List + sessionsSessionIdCommandCommandPostCommandListFromJson( + List? sessionsSessionIdCommandCommandPostCommand, [ + List? defaultValue, +]) { + if (sessionsSessionIdCommandCommandPostCommand == null) { + return defaultValue ?? []; + } + + return sessionsSessionIdCommandCommandPostCommand + .map((e) => + sessionsSessionIdCommandCommandPostCommandFromJson(e.toString())) + .toList(); +} + +List? + sessionsSessionIdCommandCommandPostCommandNullableListFromJson( + List? sessionsSessionIdCommandCommandPostCommand, [ + List? defaultValue, +]) { + if (sessionsSessionIdCommandCommandPostCommand == null) { + return defaultValue; + } + + return sessionsSessionIdCommandCommandPostCommand + .map((e) => + sessionsSessionIdCommandCommandPostCommandFromJson(e.toString())) + .toList(); +} + +String? sessionsSessionIdPlayingPostPlayCommandNullableToJson( + enums.SessionsSessionIdPlayingPostPlayCommand? + sessionsSessionIdPlayingPostPlayCommand) { + return sessionsSessionIdPlayingPostPlayCommand?.value; +} + +String? sessionsSessionIdPlayingPostPlayCommandToJson( + enums.SessionsSessionIdPlayingPostPlayCommand + sessionsSessionIdPlayingPostPlayCommand) { + return sessionsSessionIdPlayingPostPlayCommand.value; +} + +enums.SessionsSessionIdPlayingPostPlayCommand + sessionsSessionIdPlayingPostPlayCommandFromJson( + Object? sessionsSessionIdPlayingPostPlayCommand, [ + enums.SessionsSessionIdPlayingPostPlayCommand? defaultValue, +]) { + return enums.SessionsSessionIdPlayingPostPlayCommand.values.firstWhereOrNull( + (e) => e.value == sessionsSessionIdPlayingPostPlayCommand) ?? + defaultValue ?? + enums.SessionsSessionIdPlayingPostPlayCommand.swaggerGeneratedUnknown; +} + +enums.SessionsSessionIdPlayingPostPlayCommand? + sessionsSessionIdPlayingPostPlayCommandNullableFromJson( + Object? sessionsSessionIdPlayingPostPlayCommand, [ + enums.SessionsSessionIdPlayingPostPlayCommand? defaultValue, +]) { + if (sessionsSessionIdPlayingPostPlayCommand == null) { + return null; + } + return enums.SessionsSessionIdPlayingPostPlayCommand.values.firstWhereOrNull( + (e) => e.value == sessionsSessionIdPlayingPostPlayCommand) ?? + defaultValue; +} + +String sessionsSessionIdPlayingPostPlayCommandExplodedListToJson( + List? + sessionsSessionIdPlayingPostPlayCommand) { + return sessionsSessionIdPlayingPostPlayCommand + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List sessionsSessionIdPlayingPostPlayCommandListToJson( + List? + sessionsSessionIdPlayingPostPlayCommand) { + if (sessionsSessionIdPlayingPostPlayCommand == null) { + return []; + } + + return sessionsSessionIdPlayingPostPlayCommand.map((e) => e.value!).toList(); +} + +List + sessionsSessionIdPlayingPostPlayCommandListFromJson( + List? sessionsSessionIdPlayingPostPlayCommand, [ + List? defaultValue, +]) { + if (sessionsSessionIdPlayingPostPlayCommand == null) { + return defaultValue ?? []; + } + + return sessionsSessionIdPlayingPostPlayCommand + .map((e) => sessionsSessionIdPlayingPostPlayCommandFromJson(e.toString())) + .toList(); +} + +List? + sessionsSessionIdPlayingPostPlayCommandNullableListFromJson( + List? sessionsSessionIdPlayingPostPlayCommand, [ + List? defaultValue, +]) { + if (sessionsSessionIdPlayingPostPlayCommand == null) { + return defaultValue; + } + + return sessionsSessionIdPlayingPostPlayCommand + .map((e) => sessionsSessionIdPlayingPostPlayCommandFromJson(e.toString())) + .toList(); +} + +String? sessionsSessionIdPlayingCommandPostCommandNullableToJson( + enums.SessionsSessionIdPlayingCommandPostCommand? + sessionsSessionIdPlayingCommandPostCommand) { + return sessionsSessionIdPlayingCommandPostCommand?.value; +} + +String? sessionsSessionIdPlayingCommandPostCommandToJson( + enums.SessionsSessionIdPlayingCommandPostCommand + sessionsSessionIdPlayingCommandPostCommand) { + return sessionsSessionIdPlayingCommandPostCommand.value; +} + +enums.SessionsSessionIdPlayingCommandPostCommand + sessionsSessionIdPlayingCommandPostCommandFromJson( + Object? sessionsSessionIdPlayingCommandPostCommand, [ + enums.SessionsSessionIdPlayingCommandPostCommand? defaultValue, +]) { + return enums.SessionsSessionIdPlayingCommandPostCommand.values + .firstWhereOrNull( + (e) => e.value == sessionsSessionIdPlayingCommandPostCommand) ?? + defaultValue ?? + enums.SessionsSessionIdPlayingCommandPostCommand.swaggerGeneratedUnknown; +} + +enums.SessionsSessionIdPlayingCommandPostCommand? + sessionsSessionIdPlayingCommandPostCommandNullableFromJson( + Object? sessionsSessionIdPlayingCommandPostCommand, [ + enums.SessionsSessionIdPlayingCommandPostCommand? defaultValue, +]) { + if (sessionsSessionIdPlayingCommandPostCommand == null) { + return null; + } + return enums.SessionsSessionIdPlayingCommandPostCommand.values + .firstWhereOrNull( + (e) => e.value == sessionsSessionIdPlayingCommandPostCommand) ?? + defaultValue; +} + +String sessionsSessionIdPlayingCommandPostCommandExplodedListToJson( + List? + sessionsSessionIdPlayingCommandPostCommand) { + return sessionsSessionIdPlayingCommandPostCommand + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List sessionsSessionIdPlayingCommandPostCommandListToJson( + List? + sessionsSessionIdPlayingCommandPostCommand) { + if (sessionsSessionIdPlayingCommandPostCommand == null) { + return []; + } + + return sessionsSessionIdPlayingCommandPostCommand + .map((e) => e.value!) + .toList(); +} + +List + sessionsSessionIdPlayingCommandPostCommandListFromJson( + List? sessionsSessionIdPlayingCommandPostCommand, [ + List? defaultValue, +]) { + if (sessionsSessionIdPlayingCommandPostCommand == null) { + return defaultValue ?? []; + } + + return sessionsSessionIdPlayingCommandPostCommand + .map((e) => + sessionsSessionIdPlayingCommandPostCommandFromJson(e.toString())) + .toList(); +} + +List? + sessionsSessionIdPlayingCommandPostCommandNullableListFromJson( + List? sessionsSessionIdPlayingCommandPostCommand, [ + List? defaultValue, +]) { + if (sessionsSessionIdPlayingCommandPostCommand == null) { + return defaultValue; + } + + return sessionsSessionIdPlayingCommandPostCommand + .map((e) => + sessionsSessionIdPlayingCommandPostCommandFromJson(e.toString())) + .toList(); +} + +String? sessionsSessionIdSystemCommandPostCommandNullableToJson( + enums.SessionsSessionIdSystemCommandPostCommand? + sessionsSessionIdSystemCommandPostCommand) { + return sessionsSessionIdSystemCommandPostCommand?.value; +} + +String? sessionsSessionIdSystemCommandPostCommandToJson( + enums.SessionsSessionIdSystemCommandPostCommand + sessionsSessionIdSystemCommandPostCommand) { + return sessionsSessionIdSystemCommandPostCommand.value; +} + +enums.SessionsSessionIdSystemCommandPostCommand + sessionsSessionIdSystemCommandPostCommandFromJson( + Object? sessionsSessionIdSystemCommandPostCommand, [ + enums.SessionsSessionIdSystemCommandPostCommand? defaultValue, +]) { + return enums.SessionsSessionIdSystemCommandPostCommand.values + .firstWhereOrNull( + (e) => e.value == sessionsSessionIdSystemCommandPostCommand) ?? + defaultValue ?? + enums.SessionsSessionIdSystemCommandPostCommand.swaggerGeneratedUnknown; +} + +enums.SessionsSessionIdSystemCommandPostCommand? + sessionsSessionIdSystemCommandPostCommandNullableFromJson( + Object? sessionsSessionIdSystemCommandPostCommand, [ + enums.SessionsSessionIdSystemCommandPostCommand? defaultValue, +]) { + if (sessionsSessionIdSystemCommandPostCommand == null) { + return null; + } + return enums.SessionsSessionIdSystemCommandPostCommand.values + .firstWhereOrNull( + (e) => e.value == sessionsSessionIdSystemCommandPostCommand) ?? + defaultValue; +} + +String sessionsSessionIdSystemCommandPostCommandExplodedListToJson( + List? + sessionsSessionIdSystemCommandPostCommand) { + return sessionsSessionIdSystemCommandPostCommand + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List sessionsSessionIdSystemCommandPostCommandListToJson( + List? + sessionsSessionIdSystemCommandPostCommand) { + if (sessionsSessionIdSystemCommandPostCommand == null) { + return []; + } + + return sessionsSessionIdSystemCommandPostCommand + .map((e) => e.value!) + .toList(); +} + +List + sessionsSessionIdSystemCommandPostCommandListFromJson( + List? sessionsSessionIdSystemCommandPostCommand, [ + List? defaultValue, +]) { + if (sessionsSessionIdSystemCommandPostCommand == null) { + return defaultValue ?? []; + } + + return sessionsSessionIdSystemCommandPostCommand + .map((e) => + sessionsSessionIdSystemCommandPostCommandFromJson(e.toString())) + .toList(); +} + +List? + sessionsSessionIdSystemCommandPostCommandNullableListFromJson( + List? sessionsSessionIdSystemCommandPostCommand, [ + List? defaultValue, +]) { + if (sessionsSessionIdSystemCommandPostCommand == null) { + return defaultValue; + } + + return sessionsSessionIdSystemCommandPostCommand + .map((e) => + sessionsSessionIdSystemCommandPostCommandFromJson(e.toString())) + .toList(); +} + +String? sessionsSessionIdViewingPostItemTypeNullableToJson( + enums.SessionsSessionIdViewingPostItemType? + sessionsSessionIdViewingPostItemType) { + return sessionsSessionIdViewingPostItemType?.value; +} + +String? sessionsSessionIdViewingPostItemTypeToJson( + enums.SessionsSessionIdViewingPostItemType + sessionsSessionIdViewingPostItemType) { + return sessionsSessionIdViewingPostItemType.value; +} + +enums.SessionsSessionIdViewingPostItemType + sessionsSessionIdViewingPostItemTypeFromJson( + Object? sessionsSessionIdViewingPostItemType, [ + enums.SessionsSessionIdViewingPostItemType? defaultValue, +]) { + return enums.SessionsSessionIdViewingPostItemType.values.firstWhereOrNull( + (e) => e.value == sessionsSessionIdViewingPostItemType) ?? + defaultValue ?? + enums.SessionsSessionIdViewingPostItemType.swaggerGeneratedUnknown; +} + +enums.SessionsSessionIdViewingPostItemType? + sessionsSessionIdViewingPostItemTypeNullableFromJson( + Object? sessionsSessionIdViewingPostItemType, [ + enums.SessionsSessionIdViewingPostItemType? defaultValue, +]) { + if (sessionsSessionIdViewingPostItemType == null) { + return null; + } + return enums.SessionsSessionIdViewingPostItemType.values.firstWhereOrNull( + (e) => e.value == sessionsSessionIdViewingPostItemType) ?? + defaultValue; +} + +String sessionsSessionIdViewingPostItemTypeExplodedListToJson( + List? + sessionsSessionIdViewingPostItemType) { + return sessionsSessionIdViewingPostItemType?.map((e) => e.value!).join(',') ?? + ''; +} + +List sessionsSessionIdViewingPostItemTypeListToJson( + List? + sessionsSessionIdViewingPostItemType) { + if (sessionsSessionIdViewingPostItemType == null) { + return []; + } + + return sessionsSessionIdViewingPostItemType.map((e) => e.value!).toList(); +} + +List + sessionsSessionIdViewingPostItemTypeListFromJson( + List? sessionsSessionIdViewingPostItemType, [ + List? defaultValue, +]) { + if (sessionsSessionIdViewingPostItemType == null) { + return defaultValue ?? []; + } + + return sessionsSessionIdViewingPostItemType + .map((e) => sessionsSessionIdViewingPostItemTypeFromJson(e.toString())) + .toList(); +} + +List? + sessionsSessionIdViewingPostItemTypeNullableListFromJson( + List? sessionsSessionIdViewingPostItemType, [ + List? defaultValue, +]) { + if (sessionsSessionIdViewingPostItemType == null) { + return defaultValue; + } + + return sessionsSessionIdViewingPostItemType + .map((e) => sessionsSessionIdViewingPostItemTypeFromJson(e.toString())) + .toList(); +} + +String? episodeIdIntroTimestampsGetModeNullableToJson( + enums.EpisodeIdIntroTimestampsGetMode? episodeIdIntroTimestampsGetMode) { + return episodeIdIntroTimestampsGetMode?.value; +} + +String? episodeIdIntroTimestampsGetModeToJson( + enums.EpisodeIdIntroTimestampsGetMode episodeIdIntroTimestampsGetMode) { + return episodeIdIntroTimestampsGetMode.value; +} + +enums.EpisodeIdIntroTimestampsGetMode episodeIdIntroTimestampsGetModeFromJson( + Object? episodeIdIntroTimestampsGetMode, [ + enums.EpisodeIdIntroTimestampsGetMode? defaultValue, +]) { + return enums.EpisodeIdIntroTimestampsGetMode.values.firstWhereOrNull( + (e) => e.value == episodeIdIntroTimestampsGetMode) ?? + defaultValue ?? + enums.EpisodeIdIntroTimestampsGetMode.swaggerGeneratedUnknown; +} + +enums.EpisodeIdIntroTimestampsGetMode? + episodeIdIntroTimestampsGetModeNullableFromJson( + Object? episodeIdIntroTimestampsGetMode, [ + enums.EpisodeIdIntroTimestampsGetMode? defaultValue, +]) { + if (episodeIdIntroTimestampsGetMode == null) { + return null; + } + return enums.EpisodeIdIntroTimestampsGetMode.values.firstWhereOrNull( + (e) => e.value == episodeIdIntroTimestampsGetMode) ?? + defaultValue; +} + +String episodeIdIntroTimestampsGetModeExplodedListToJson( + List? + episodeIdIntroTimestampsGetMode) { + return episodeIdIntroTimestampsGetMode?.map((e) => e.value!).join(',') ?? ''; +} + +List episodeIdIntroTimestampsGetModeListToJson( + List? + episodeIdIntroTimestampsGetMode) { + if (episodeIdIntroTimestampsGetMode == null) { + return []; + } + + return episodeIdIntroTimestampsGetMode.map((e) => e.value!).toList(); +} + +List + episodeIdIntroTimestampsGetModeListFromJson( + List? episodeIdIntroTimestampsGetMode, [ + List? defaultValue, +]) { + if (episodeIdIntroTimestampsGetMode == null) { + return defaultValue ?? []; + } + + return episodeIdIntroTimestampsGetMode + .map((e) => episodeIdIntroTimestampsGetModeFromJson(e.toString())) + .toList(); +} + +List? + episodeIdIntroTimestampsGetModeNullableListFromJson( + List? episodeIdIntroTimestampsGetMode, [ + List? defaultValue, +]) { + if (episodeIdIntroTimestampsGetMode == null) { + return defaultValue; + } + + return episodeIdIntroTimestampsGetMode + .map((e) => episodeIdIntroTimestampsGetModeFromJson(e.toString())) + .toList(); +} + +String? episodeIdIntroTimestampsV1GetModeNullableToJson( + enums.EpisodeIdIntroTimestampsV1GetMode? + episodeIdIntroTimestampsV1GetMode) { + return episodeIdIntroTimestampsV1GetMode?.value; +} + +String? episodeIdIntroTimestampsV1GetModeToJson( + enums.EpisodeIdIntroTimestampsV1GetMode episodeIdIntroTimestampsV1GetMode) { + return episodeIdIntroTimestampsV1GetMode.value; +} + +enums.EpisodeIdIntroTimestampsV1GetMode + episodeIdIntroTimestampsV1GetModeFromJson( + Object? episodeIdIntroTimestampsV1GetMode, [ + enums.EpisodeIdIntroTimestampsV1GetMode? defaultValue, +]) { + return enums.EpisodeIdIntroTimestampsV1GetMode.values.firstWhereOrNull( + (e) => e.value == episodeIdIntroTimestampsV1GetMode) ?? + defaultValue ?? + enums.EpisodeIdIntroTimestampsV1GetMode.swaggerGeneratedUnknown; +} + +enums.EpisodeIdIntroTimestampsV1GetMode? + episodeIdIntroTimestampsV1GetModeNullableFromJson( + Object? episodeIdIntroTimestampsV1GetMode, [ + enums.EpisodeIdIntroTimestampsV1GetMode? defaultValue, +]) { + if (episodeIdIntroTimestampsV1GetMode == null) { + return null; + } + return enums.EpisodeIdIntroTimestampsV1GetMode.values.firstWhereOrNull( + (e) => e.value == episodeIdIntroTimestampsV1GetMode) ?? + defaultValue; +} + +String episodeIdIntroTimestampsV1GetModeExplodedListToJson( + List? + episodeIdIntroTimestampsV1GetMode) { + return episodeIdIntroTimestampsV1GetMode?.map((e) => e.value!).join(',') ?? + ''; +} + +List episodeIdIntroTimestampsV1GetModeListToJson( + List? + episodeIdIntroTimestampsV1GetMode) { + if (episodeIdIntroTimestampsV1GetMode == null) { + return []; + } + + return episodeIdIntroTimestampsV1GetMode.map((e) => e.value!).toList(); +} + +List + episodeIdIntroTimestampsV1GetModeListFromJson( + List? episodeIdIntroTimestampsV1GetMode, [ + List? defaultValue, +]) { + if (episodeIdIntroTimestampsV1GetMode == null) { + return defaultValue ?? []; + } + + return episodeIdIntroTimestampsV1GetMode + .map((e) => episodeIdIntroTimestampsV1GetModeFromJson(e.toString())) + .toList(); +} + +List? + episodeIdIntroTimestampsV1GetModeNullableListFromJson( + List? episodeIdIntroTimestampsV1GetMode, [ + List? defaultValue, +]) { + if (episodeIdIntroTimestampsV1GetMode == null) { + return defaultValue; + } + + return episodeIdIntroTimestampsV1GetMode + .map((e) => episodeIdIntroTimestampsV1GetModeFromJson(e.toString())) + .toList(); +} + +String? introsAllGetModeNullableToJson( + enums.IntrosAllGetMode? introsAllGetMode) { + return introsAllGetMode?.value; +} + +String? introsAllGetModeToJson(enums.IntrosAllGetMode introsAllGetMode) { + return introsAllGetMode.value; +} + +enums.IntrosAllGetMode introsAllGetModeFromJson( + Object? introsAllGetMode, [ + enums.IntrosAllGetMode? defaultValue, +]) { + return enums.IntrosAllGetMode.values + .firstWhereOrNull((e) => e.value == introsAllGetMode) ?? + defaultValue ?? + enums.IntrosAllGetMode.swaggerGeneratedUnknown; +} + +enums.IntrosAllGetMode? introsAllGetModeNullableFromJson( + Object? introsAllGetMode, [ + enums.IntrosAllGetMode? defaultValue, +]) { + if (introsAllGetMode == null) { + return null; + } + return enums.IntrosAllGetMode.values + .firstWhereOrNull((e) => e.value == introsAllGetMode) ?? + defaultValue; +} + +String introsAllGetModeExplodedListToJson( + List? introsAllGetMode) { + return introsAllGetMode?.map((e) => e.value!).join(',') ?? ''; +} + +List introsAllGetModeListToJson( + List? introsAllGetMode) { + if (introsAllGetMode == null) { + return []; + } + + return introsAllGetMode.map((e) => e.value!).toList(); +} + +List introsAllGetModeListFromJson( + List? introsAllGetMode, [ + List? defaultValue, +]) { + if (introsAllGetMode == null) { + return defaultValue ?? []; + } + + return introsAllGetMode + .map((e) => introsAllGetModeFromJson(e.toString())) + .toList(); +} + +List? introsAllGetModeNullableListFromJson( + List? introsAllGetMode, [ + List? defaultValue, +]) { + if (introsAllGetMode == null) { + return defaultValue; + } + + return introsAllGetMode + .map((e) => introsAllGetModeFromJson(e.toString())) + .toList(); +} + +String? introsEraseTimestampsPostModeNullableToJson( + enums.IntrosEraseTimestampsPostMode? introsEraseTimestampsPostMode) { + return introsEraseTimestampsPostMode?.value; +} + +String? introsEraseTimestampsPostModeToJson( + enums.IntrosEraseTimestampsPostMode introsEraseTimestampsPostMode) { + return introsEraseTimestampsPostMode.value; +} + +enums.IntrosEraseTimestampsPostMode introsEraseTimestampsPostModeFromJson( + Object? introsEraseTimestampsPostMode, [ + enums.IntrosEraseTimestampsPostMode? defaultValue, +]) { + return enums.IntrosEraseTimestampsPostMode.values + .firstWhereOrNull((e) => e.value == introsEraseTimestampsPostMode) ?? + defaultValue ?? + enums.IntrosEraseTimestampsPostMode.swaggerGeneratedUnknown; +} + +enums.IntrosEraseTimestampsPostMode? + introsEraseTimestampsPostModeNullableFromJson( + Object? introsEraseTimestampsPostMode, [ + enums.IntrosEraseTimestampsPostMode? defaultValue, +]) { + if (introsEraseTimestampsPostMode == null) { + return null; + } + return enums.IntrosEraseTimestampsPostMode.values + .firstWhereOrNull((e) => e.value == introsEraseTimestampsPostMode) ?? + defaultValue; +} + +String introsEraseTimestampsPostModeExplodedListToJson( + List? introsEraseTimestampsPostMode) { + return introsEraseTimestampsPostMode?.map((e) => e.value!).join(',') ?? ''; +} + +List introsEraseTimestampsPostModeListToJson( + List? introsEraseTimestampsPostMode) { + if (introsEraseTimestampsPostMode == null) { + return []; + } + + return introsEraseTimestampsPostMode.map((e) => e.value!).toList(); +} + +List + introsEraseTimestampsPostModeListFromJson( + List? introsEraseTimestampsPostMode, [ + List? defaultValue, +]) { + if (introsEraseTimestampsPostMode == null) { + return defaultValue ?? []; + } + + return introsEraseTimestampsPostMode + .map((e) => introsEraseTimestampsPostModeFromJson(e.toString())) + .toList(); +} + +List? + introsEraseTimestampsPostModeNullableListFromJson( + List? introsEraseTimestampsPostMode, [ + List? defaultValue, +]) { + if (introsEraseTimestampsPostMode == null) { + return defaultValue; + } + + return introsEraseTimestampsPostMode + .map((e) => introsEraseTimestampsPostModeFromJson(e.toString())) + .toList(); +} + +String? showsSeriesIdEpisodesGetSortByNullableToJson( + enums.ShowsSeriesIdEpisodesGetSortBy? showsSeriesIdEpisodesGetSortBy) { + return showsSeriesIdEpisodesGetSortBy?.value; +} + +String? showsSeriesIdEpisodesGetSortByToJson( + enums.ShowsSeriesIdEpisodesGetSortBy showsSeriesIdEpisodesGetSortBy) { + return showsSeriesIdEpisodesGetSortBy.value; +} + +enums.ShowsSeriesIdEpisodesGetSortBy showsSeriesIdEpisodesGetSortByFromJson( + Object? showsSeriesIdEpisodesGetSortBy, [ + enums.ShowsSeriesIdEpisodesGetSortBy? defaultValue, +]) { + return enums.ShowsSeriesIdEpisodesGetSortBy.values + .firstWhereOrNull((e) => e.value == showsSeriesIdEpisodesGetSortBy) ?? + defaultValue ?? + enums.ShowsSeriesIdEpisodesGetSortBy.swaggerGeneratedUnknown; +} + +enums.ShowsSeriesIdEpisodesGetSortBy? + showsSeriesIdEpisodesGetSortByNullableFromJson( + Object? showsSeriesIdEpisodesGetSortBy, [ + enums.ShowsSeriesIdEpisodesGetSortBy? defaultValue, +]) { + if (showsSeriesIdEpisodesGetSortBy == null) { + return null; + } + return enums.ShowsSeriesIdEpisodesGetSortBy.values + .firstWhereOrNull((e) => e.value == showsSeriesIdEpisodesGetSortBy) ?? + defaultValue; +} + +String showsSeriesIdEpisodesGetSortByExplodedListToJson( + List? + showsSeriesIdEpisodesGetSortBy) { + return showsSeriesIdEpisodesGetSortBy?.map((e) => e.value!).join(',') ?? ''; +} + +List showsSeriesIdEpisodesGetSortByListToJson( + List? + showsSeriesIdEpisodesGetSortBy) { + if (showsSeriesIdEpisodesGetSortBy == null) { + return []; + } + + return showsSeriesIdEpisodesGetSortBy.map((e) => e.value!).toList(); +} + +List + showsSeriesIdEpisodesGetSortByListFromJson( + List? showsSeriesIdEpisodesGetSortBy, [ + List? defaultValue, +]) { + if (showsSeriesIdEpisodesGetSortBy == null) { + return defaultValue ?? []; + } + + return showsSeriesIdEpisodesGetSortBy + .map((e) => showsSeriesIdEpisodesGetSortByFromJson(e.toString())) + .toList(); +} + +List? + showsSeriesIdEpisodesGetSortByNullableListFromJson( + List? showsSeriesIdEpisodesGetSortBy, [ + List? defaultValue, +]) { + if (showsSeriesIdEpisodesGetSortBy == null) { + return defaultValue; + } + + return showsSeriesIdEpisodesGetSortBy + .map((e) => showsSeriesIdEpisodesGetSortByFromJson(e.toString())) + .toList(); +} + +String? audioItemIdUniversalGetTranscodingProtocolNullableToJson( + enums.AudioItemIdUniversalGetTranscodingProtocol? + audioItemIdUniversalGetTranscodingProtocol) { + return audioItemIdUniversalGetTranscodingProtocol?.value; +} + +String? audioItemIdUniversalGetTranscodingProtocolToJson( + enums.AudioItemIdUniversalGetTranscodingProtocol + audioItemIdUniversalGetTranscodingProtocol) { + return audioItemIdUniversalGetTranscodingProtocol.value; +} + +enums.AudioItemIdUniversalGetTranscodingProtocol + audioItemIdUniversalGetTranscodingProtocolFromJson( + Object? audioItemIdUniversalGetTranscodingProtocol, [ + enums.AudioItemIdUniversalGetTranscodingProtocol? defaultValue, +]) { + return enums.AudioItemIdUniversalGetTranscodingProtocol.values + .firstWhereOrNull( + (e) => e.value == audioItemIdUniversalGetTranscodingProtocol) ?? + defaultValue ?? + enums.AudioItemIdUniversalGetTranscodingProtocol.swaggerGeneratedUnknown; +} + +enums.AudioItemIdUniversalGetTranscodingProtocol? + audioItemIdUniversalGetTranscodingProtocolNullableFromJson( + Object? audioItemIdUniversalGetTranscodingProtocol, [ + enums.AudioItemIdUniversalGetTranscodingProtocol? defaultValue, +]) { + if (audioItemIdUniversalGetTranscodingProtocol == null) { + return null; + } + return enums.AudioItemIdUniversalGetTranscodingProtocol.values + .firstWhereOrNull( + (e) => e.value == audioItemIdUniversalGetTranscodingProtocol) ?? + defaultValue; +} + +String audioItemIdUniversalGetTranscodingProtocolExplodedListToJson( + List? + audioItemIdUniversalGetTranscodingProtocol) { + return audioItemIdUniversalGetTranscodingProtocol + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List audioItemIdUniversalGetTranscodingProtocolListToJson( + List? + audioItemIdUniversalGetTranscodingProtocol) { + if (audioItemIdUniversalGetTranscodingProtocol == null) { + return []; + } + + return audioItemIdUniversalGetTranscodingProtocol + .map((e) => e.value!) + .toList(); +} + +List + audioItemIdUniversalGetTranscodingProtocolListFromJson( + List? audioItemIdUniversalGetTranscodingProtocol, [ + List? defaultValue, +]) { + if (audioItemIdUniversalGetTranscodingProtocol == null) { + return defaultValue ?? []; + } + + return audioItemIdUniversalGetTranscodingProtocol + .map((e) => + audioItemIdUniversalGetTranscodingProtocolFromJson(e.toString())) + .toList(); +} + +List? + audioItemIdUniversalGetTranscodingProtocolNullableListFromJson( + List? audioItemIdUniversalGetTranscodingProtocol, [ + List? defaultValue, +]) { + if (audioItemIdUniversalGetTranscodingProtocol == null) { + return defaultValue; + } + + return audioItemIdUniversalGetTranscodingProtocol + .map((e) => + audioItemIdUniversalGetTranscodingProtocolFromJson(e.toString())) + .toList(); +} + +String? audioItemIdUniversalHeadTranscodingProtocolNullableToJson( + enums.AudioItemIdUniversalHeadTranscodingProtocol? + audioItemIdUniversalHeadTranscodingProtocol) { + return audioItemIdUniversalHeadTranscodingProtocol?.value; +} + +String? audioItemIdUniversalHeadTranscodingProtocolToJson( + enums.AudioItemIdUniversalHeadTranscodingProtocol + audioItemIdUniversalHeadTranscodingProtocol) { + return audioItemIdUniversalHeadTranscodingProtocol.value; +} + +enums.AudioItemIdUniversalHeadTranscodingProtocol + audioItemIdUniversalHeadTranscodingProtocolFromJson( + Object? audioItemIdUniversalHeadTranscodingProtocol, [ + enums.AudioItemIdUniversalHeadTranscodingProtocol? defaultValue, +]) { + return enums.AudioItemIdUniversalHeadTranscodingProtocol.values + .firstWhereOrNull( + (e) => e.value == audioItemIdUniversalHeadTranscodingProtocol) ?? + defaultValue ?? + enums.AudioItemIdUniversalHeadTranscodingProtocol.swaggerGeneratedUnknown; +} + +enums.AudioItemIdUniversalHeadTranscodingProtocol? + audioItemIdUniversalHeadTranscodingProtocolNullableFromJson( + Object? audioItemIdUniversalHeadTranscodingProtocol, [ + enums.AudioItemIdUniversalHeadTranscodingProtocol? defaultValue, +]) { + if (audioItemIdUniversalHeadTranscodingProtocol == null) { + return null; + } + return enums.AudioItemIdUniversalHeadTranscodingProtocol.values + .firstWhereOrNull( + (e) => e.value == audioItemIdUniversalHeadTranscodingProtocol) ?? + defaultValue; +} + +String audioItemIdUniversalHeadTranscodingProtocolExplodedListToJson( + List? + audioItemIdUniversalHeadTranscodingProtocol) { + return audioItemIdUniversalHeadTranscodingProtocol + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List audioItemIdUniversalHeadTranscodingProtocolListToJson( + List? + audioItemIdUniversalHeadTranscodingProtocol) { + if (audioItemIdUniversalHeadTranscodingProtocol == null) { + return []; + } + + return audioItemIdUniversalHeadTranscodingProtocol + .map((e) => e.value!) + .toList(); +} + +List + audioItemIdUniversalHeadTranscodingProtocolListFromJson( + List? audioItemIdUniversalHeadTranscodingProtocol, [ + List? defaultValue, +]) { + if (audioItemIdUniversalHeadTranscodingProtocol == null) { + return defaultValue ?? []; + } + + return audioItemIdUniversalHeadTranscodingProtocol + .map((e) => + audioItemIdUniversalHeadTranscodingProtocolFromJson(e.toString())) + .toList(); +} + +List? + audioItemIdUniversalHeadTranscodingProtocolNullableListFromJson( + List? audioItemIdUniversalHeadTranscodingProtocol, [ + List? defaultValue, +]) { + if (audioItemIdUniversalHeadTranscodingProtocol == null) { + return defaultValue; + } + + return audioItemIdUniversalHeadTranscodingProtocol + .map((e) => + audioItemIdUniversalHeadTranscodingProtocolFromJson(e.toString())) + .toList(); +} + +String? videosItemIdStreamGetSubtitleMethodNullableToJson( + enums.VideosItemIdStreamGetSubtitleMethod? + videosItemIdStreamGetSubtitleMethod) { + return videosItemIdStreamGetSubtitleMethod?.value; +} + +String? videosItemIdStreamGetSubtitleMethodToJson( + enums.VideosItemIdStreamGetSubtitleMethod + videosItemIdStreamGetSubtitleMethod) { + return videosItemIdStreamGetSubtitleMethod.value; +} + +enums.VideosItemIdStreamGetSubtitleMethod + videosItemIdStreamGetSubtitleMethodFromJson( + Object? videosItemIdStreamGetSubtitleMethod, [ + enums.VideosItemIdStreamGetSubtitleMethod? defaultValue, +]) { + return enums.VideosItemIdStreamGetSubtitleMethod.values.firstWhereOrNull( + (e) => e.value == videosItemIdStreamGetSubtitleMethod) ?? + defaultValue ?? + enums.VideosItemIdStreamGetSubtitleMethod.swaggerGeneratedUnknown; +} + +enums.VideosItemIdStreamGetSubtitleMethod? + videosItemIdStreamGetSubtitleMethodNullableFromJson( + Object? videosItemIdStreamGetSubtitleMethod, [ + enums.VideosItemIdStreamGetSubtitleMethod? defaultValue, +]) { + if (videosItemIdStreamGetSubtitleMethod == null) { + return null; + } + return enums.VideosItemIdStreamGetSubtitleMethod.values.firstWhereOrNull( + (e) => e.value == videosItemIdStreamGetSubtitleMethod) ?? + defaultValue; +} + +String videosItemIdStreamGetSubtitleMethodExplodedListToJson( + List? + videosItemIdStreamGetSubtitleMethod) { + return videosItemIdStreamGetSubtitleMethod?.map((e) => e.value!).join(',') ?? + ''; +} + +List videosItemIdStreamGetSubtitleMethodListToJson( + List? + videosItemIdStreamGetSubtitleMethod) { + if (videosItemIdStreamGetSubtitleMethod == null) { + return []; + } + + return videosItemIdStreamGetSubtitleMethod.map((e) => e.value!).toList(); +} + +List + videosItemIdStreamGetSubtitleMethodListFromJson( + List? videosItemIdStreamGetSubtitleMethod, [ + List? defaultValue, +]) { + if (videosItemIdStreamGetSubtitleMethod == null) { + return defaultValue ?? []; + } + + return videosItemIdStreamGetSubtitleMethod + .map((e) => videosItemIdStreamGetSubtitleMethodFromJson(e.toString())) + .toList(); +} + +List? + videosItemIdStreamGetSubtitleMethodNullableListFromJson( + List? videosItemIdStreamGetSubtitleMethod, [ + List? defaultValue, +]) { + if (videosItemIdStreamGetSubtitleMethod == null) { + return defaultValue; + } + + return videosItemIdStreamGetSubtitleMethod + .map((e) => videosItemIdStreamGetSubtitleMethodFromJson(e.toString())) + .toList(); +} + +String? videosItemIdStreamGetContextNullableToJson( + enums.VideosItemIdStreamGetContext? videosItemIdStreamGetContext) { + return videosItemIdStreamGetContext?.value; +} + +String? videosItemIdStreamGetContextToJson( + enums.VideosItemIdStreamGetContext videosItemIdStreamGetContext) { + return videosItemIdStreamGetContext.value; +} + +enums.VideosItemIdStreamGetContext videosItemIdStreamGetContextFromJson( + Object? videosItemIdStreamGetContext, [ + enums.VideosItemIdStreamGetContext? defaultValue, +]) { + return enums.VideosItemIdStreamGetContext.values + .firstWhereOrNull((e) => e.value == videosItemIdStreamGetContext) ?? + defaultValue ?? + enums.VideosItemIdStreamGetContext.swaggerGeneratedUnknown; +} + +enums.VideosItemIdStreamGetContext? + videosItemIdStreamGetContextNullableFromJson( + Object? videosItemIdStreamGetContext, [ + enums.VideosItemIdStreamGetContext? defaultValue, +]) { + if (videosItemIdStreamGetContext == null) { + return null; + } + return enums.VideosItemIdStreamGetContext.values + .firstWhereOrNull((e) => e.value == videosItemIdStreamGetContext) ?? + defaultValue; +} + +String videosItemIdStreamGetContextExplodedListToJson( + List? videosItemIdStreamGetContext) { + return videosItemIdStreamGetContext?.map((e) => e.value!).join(',') ?? ''; +} + +List videosItemIdStreamGetContextListToJson( + List? videosItemIdStreamGetContext) { + if (videosItemIdStreamGetContext == null) { + return []; + } + + return videosItemIdStreamGetContext.map((e) => e.value!).toList(); +} + +List + videosItemIdStreamGetContextListFromJson( + List? videosItemIdStreamGetContext, [ + List? defaultValue, +]) { + if (videosItemIdStreamGetContext == null) { + return defaultValue ?? []; + } + + return videosItemIdStreamGetContext + .map((e) => videosItemIdStreamGetContextFromJson(e.toString())) + .toList(); +} + +List? + videosItemIdStreamGetContextNullableListFromJson( + List? videosItemIdStreamGetContext, [ + List? defaultValue, +]) { + if (videosItemIdStreamGetContext == null) { + return defaultValue; + } + + return videosItemIdStreamGetContext + .map((e) => videosItemIdStreamGetContextFromJson(e.toString())) + .toList(); +} + +String? videosItemIdStreamHeadSubtitleMethodNullableToJson( + enums.VideosItemIdStreamHeadSubtitleMethod? + videosItemIdStreamHeadSubtitleMethod) { + return videosItemIdStreamHeadSubtitleMethod?.value; +} + +String? videosItemIdStreamHeadSubtitleMethodToJson( + enums.VideosItemIdStreamHeadSubtitleMethod + videosItemIdStreamHeadSubtitleMethod) { + return videosItemIdStreamHeadSubtitleMethod.value; +} + +enums.VideosItemIdStreamHeadSubtitleMethod + videosItemIdStreamHeadSubtitleMethodFromJson( + Object? videosItemIdStreamHeadSubtitleMethod, [ + enums.VideosItemIdStreamHeadSubtitleMethod? defaultValue, +]) { + return enums.VideosItemIdStreamHeadSubtitleMethod.values.firstWhereOrNull( + (e) => e.value == videosItemIdStreamHeadSubtitleMethod) ?? + defaultValue ?? + enums.VideosItemIdStreamHeadSubtitleMethod.swaggerGeneratedUnknown; +} + +enums.VideosItemIdStreamHeadSubtitleMethod? + videosItemIdStreamHeadSubtitleMethodNullableFromJson( + Object? videosItemIdStreamHeadSubtitleMethod, [ + enums.VideosItemIdStreamHeadSubtitleMethod? defaultValue, +]) { + if (videosItemIdStreamHeadSubtitleMethod == null) { + return null; + } + return enums.VideosItemIdStreamHeadSubtitleMethod.values.firstWhereOrNull( + (e) => e.value == videosItemIdStreamHeadSubtitleMethod) ?? + defaultValue; +} + +String videosItemIdStreamHeadSubtitleMethodExplodedListToJson( + List? + videosItemIdStreamHeadSubtitleMethod) { + return videosItemIdStreamHeadSubtitleMethod?.map((e) => e.value!).join(',') ?? + ''; +} + +List videosItemIdStreamHeadSubtitleMethodListToJson( + List? + videosItemIdStreamHeadSubtitleMethod) { + if (videosItemIdStreamHeadSubtitleMethod == null) { + return []; + } + + return videosItemIdStreamHeadSubtitleMethod.map((e) => e.value!).toList(); +} + +List + videosItemIdStreamHeadSubtitleMethodListFromJson( + List? videosItemIdStreamHeadSubtitleMethod, [ + List? defaultValue, +]) { + if (videosItemIdStreamHeadSubtitleMethod == null) { + return defaultValue ?? []; + } + + return videosItemIdStreamHeadSubtitleMethod + .map((e) => videosItemIdStreamHeadSubtitleMethodFromJson(e.toString())) + .toList(); +} + +List? + videosItemIdStreamHeadSubtitleMethodNullableListFromJson( + List? videosItemIdStreamHeadSubtitleMethod, [ + List? defaultValue, +]) { + if (videosItemIdStreamHeadSubtitleMethod == null) { + return defaultValue; + } + + return videosItemIdStreamHeadSubtitleMethod + .map((e) => videosItemIdStreamHeadSubtitleMethodFromJson(e.toString())) + .toList(); +} + +String? videosItemIdStreamHeadContextNullableToJson( + enums.VideosItemIdStreamHeadContext? videosItemIdStreamHeadContext) { + return videosItemIdStreamHeadContext?.value; +} + +String? videosItemIdStreamHeadContextToJson( + enums.VideosItemIdStreamHeadContext videosItemIdStreamHeadContext) { + return videosItemIdStreamHeadContext.value; +} + +enums.VideosItemIdStreamHeadContext videosItemIdStreamHeadContextFromJson( + Object? videosItemIdStreamHeadContext, [ + enums.VideosItemIdStreamHeadContext? defaultValue, +]) { + return enums.VideosItemIdStreamHeadContext.values + .firstWhereOrNull((e) => e.value == videosItemIdStreamHeadContext) ?? + defaultValue ?? + enums.VideosItemIdStreamHeadContext.swaggerGeneratedUnknown; +} + +enums.VideosItemIdStreamHeadContext? + videosItemIdStreamHeadContextNullableFromJson( + Object? videosItemIdStreamHeadContext, [ + enums.VideosItemIdStreamHeadContext? defaultValue, +]) { + if (videosItemIdStreamHeadContext == null) { + return null; + } + return enums.VideosItemIdStreamHeadContext.values + .firstWhereOrNull((e) => e.value == videosItemIdStreamHeadContext) ?? + defaultValue; +} + +String videosItemIdStreamHeadContextExplodedListToJson( + List? videosItemIdStreamHeadContext) { + return videosItemIdStreamHeadContext?.map((e) => e.value!).join(',') ?? ''; +} + +List videosItemIdStreamHeadContextListToJson( + List? videosItemIdStreamHeadContext) { + if (videosItemIdStreamHeadContext == null) { + return []; + } + + return videosItemIdStreamHeadContext.map((e) => e.value!).toList(); +} + +List + videosItemIdStreamHeadContextListFromJson( + List? videosItemIdStreamHeadContext, [ + List? defaultValue, +]) { + if (videosItemIdStreamHeadContext == null) { + return defaultValue ?? []; + } + + return videosItemIdStreamHeadContext + .map((e) => videosItemIdStreamHeadContextFromJson(e.toString())) + .toList(); +} + +List? + videosItemIdStreamHeadContextNullableListFromJson( + List? videosItemIdStreamHeadContext, [ + List? defaultValue, +]) { + if (videosItemIdStreamHeadContext == null) { + return defaultValue; + } + + return videosItemIdStreamHeadContext + .map((e) => videosItemIdStreamHeadContextFromJson(e.toString())) + .toList(); +} + +String? videosItemIdStreamContainerGetSubtitleMethodNullableToJson( + enums.VideosItemIdStreamContainerGetSubtitleMethod? + videosItemIdStreamContainerGetSubtitleMethod) { + return videosItemIdStreamContainerGetSubtitleMethod?.value; +} + +String? videosItemIdStreamContainerGetSubtitleMethodToJson( + enums.VideosItemIdStreamContainerGetSubtitleMethod + videosItemIdStreamContainerGetSubtitleMethod) { + return videosItemIdStreamContainerGetSubtitleMethod.value; +} + +enums.VideosItemIdStreamContainerGetSubtitleMethod + videosItemIdStreamContainerGetSubtitleMethodFromJson( + Object? videosItemIdStreamContainerGetSubtitleMethod, [ + enums.VideosItemIdStreamContainerGetSubtitleMethod? defaultValue, +]) { + return enums.VideosItemIdStreamContainerGetSubtitleMethod.values + .firstWhereOrNull( + (e) => e.value == videosItemIdStreamContainerGetSubtitleMethod) ?? + defaultValue ?? + enums + .VideosItemIdStreamContainerGetSubtitleMethod.swaggerGeneratedUnknown; +} + +enums.VideosItemIdStreamContainerGetSubtitleMethod? + videosItemIdStreamContainerGetSubtitleMethodNullableFromJson( + Object? videosItemIdStreamContainerGetSubtitleMethod, [ + enums.VideosItemIdStreamContainerGetSubtitleMethod? defaultValue, +]) { + if (videosItemIdStreamContainerGetSubtitleMethod == null) { + return null; + } + return enums.VideosItemIdStreamContainerGetSubtitleMethod.values + .firstWhereOrNull( + (e) => e.value == videosItemIdStreamContainerGetSubtitleMethod) ?? + defaultValue; +} + +String videosItemIdStreamContainerGetSubtitleMethodExplodedListToJson( + List? + videosItemIdStreamContainerGetSubtitleMethod) { + return videosItemIdStreamContainerGetSubtitleMethod + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List videosItemIdStreamContainerGetSubtitleMethodListToJson( + List? + videosItemIdStreamContainerGetSubtitleMethod) { + if (videosItemIdStreamContainerGetSubtitleMethod == null) { + return []; + } + + return videosItemIdStreamContainerGetSubtitleMethod + .map((e) => e.value!) + .toList(); +} + +List + videosItemIdStreamContainerGetSubtitleMethodListFromJson( + List? videosItemIdStreamContainerGetSubtitleMethod, [ + List? defaultValue, +]) { + if (videosItemIdStreamContainerGetSubtitleMethod == null) { + return defaultValue ?? []; + } + + return videosItemIdStreamContainerGetSubtitleMethod + .map((e) => + videosItemIdStreamContainerGetSubtitleMethodFromJson(e.toString())) + .toList(); +} + +List? + videosItemIdStreamContainerGetSubtitleMethodNullableListFromJson( + List? videosItemIdStreamContainerGetSubtitleMethod, [ + List? defaultValue, +]) { + if (videosItemIdStreamContainerGetSubtitleMethod == null) { + return defaultValue; + } + + return videosItemIdStreamContainerGetSubtitleMethod + .map((e) => + videosItemIdStreamContainerGetSubtitleMethodFromJson(e.toString())) + .toList(); +} + +String? videosItemIdStreamContainerGetContextNullableToJson( + enums.VideosItemIdStreamContainerGetContext? + videosItemIdStreamContainerGetContext) { + return videosItemIdStreamContainerGetContext?.value; +} + +String? videosItemIdStreamContainerGetContextToJson( + enums.VideosItemIdStreamContainerGetContext + videosItemIdStreamContainerGetContext) { + return videosItemIdStreamContainerGetContext.value; +} + +enums.VideosItemIdStreamContainerGetContext + videosItemIdStreamContainerGetContextFromJson( + Object? videosItemIdStreamContainerGetContext, [ + enums.VideosItemIdStreamContainerGetContext? defaultValue, +]) { + return enums.VideosItemIdStreamContainerGetContext.values.firstWhereOrNull( + (e) => e.value == videosItemIdStreamContainerGetContext) ?? + defaultValue ?? + enums.VideosItemIdStreamContainerGetContext.swaggerGeneratedUnknown; +} + +enums.VideosItemIdStreamContainerGetContext? + videosItemIdStreamContainerGetContextNullableFromJson( + Object? videosItemIdStreamContainerGetContext, [ + enums.VideosItemIdStreamContainerGetContext? defaultValue, +]) { + if (videosItemIdStreamContainerGetContext == null) { + return null; + } + return enums.VideosItemIdStreamContainerGetContext.values.firstWhereOrNull( + (e) => e.value == videosItemIdStreamContainerGetContext) ?? + defaultValue; +} + +String videosItemIdStreamContainerGetContextExplodedListToJson( + List? + videosItemIdStreamContainerGetContext) { + return videosItemIdStreamContainerGetContext + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List videosItemIdStreamContainerGetContextListToJson( + List? + videosItemIdStreamContainerGetContext) { + if (videosItemIdStreamContainerGetContext == null) { + return []; + } + + return videosItemIdStreamContainerGetContext.map((e) => e.value!).toList(); +} + +List + videosItemIdStreamContainerGetContextListFromJson( + List? videosItemIdStreamContainerGetContext, [ + List? defaultValue, +]) { + if (videosItemIdStreamContainerGetContext == null) { + return defaultValue ?? []; + } + + return videosItemIdStreamContainerGetContext + .map((e) => videosItemIdStreamContainerGetContextFromJson(e.toString())) + .toList(); +} + +List? + videosItemIdStreamContainerGetContextNullableListFromJson( + List? videosItemIdStreamContainerGetContext, [ + List? defaultValue, +]) { + if (videosItemIdStreamContainerGetContext == null) { + return defaultValue; + } + + return videosItemIdStreamContainerGetContext + .map((e) => videosItemIdStreamContainerGetContextFromJson(e.toString())) + .toList(); +} + +String? videosItemIdStreamContainerHeadSubtitleMethodNullableToJson( + enums.VideosItemIdStreamContainerHeadSubtitleMethod? + videosItemIdStreamContainerHeadSubtitleMethod) { + return videosItemIdStreamContainerHeadSubtitleMethod?.value; +} + +String? videosItemIdStreamContainerHeadSubtitleMethodToJson( + enums.VideosItemIdStreamContainerHeadSubtitleMethod + videosItemIdStreamContainerHeadSubtitleMethod) { + return videosItemIdStreamContainerHeadSubtitleMethod.value; +} + +enums.VideosItemIdStreamContainerHeadSubtitleMethod + videosItemIdStreamContainerHeadSubtitleMethodFromJson( + Object? videosItemIdStreamContainerHeadSubtitleMethod, [ + enums.VideosItemIdStreamContainerHeadSubtitleMethod? defaultValue, +]) { + return enums.VideosItemIdStreamContainerHeadSubtitleMethod.values + .firstWhereOrNull((e) => + e.value == videosItemIdStreamContainerHeadSubtitleMethod) ?? + defaultValue ?? + enums.VideosItemIdStreamContainerHeadSubtitleMethod + .swaggerGeneratedUnknown; +} + +enums.VideosItemIdStreamContainerHeadSubtitleMethod? + videosItemIdStreamContainerHeadSubtitleMethodNullableFromJson( + Object? videosItemIdStreamContainerHeadSubtitleMethod, [ + enums.VideosItemIdStreamContainerHeadSubtitleMethod? defaultValue, +]) { + if (videosItemIdStreamContainerHeadSubtitleMethod == null) { + return null; + } + return enums.VideosItemIdStreamContainerHeadSubtitleMethod.values + .firstWhereOrNull((e) => + e.value == videosItemIdStreamContainerHeadSubtitleMethod) ?? + defaultValue; +} + +String videosItemIdStreamContainerHeadSubtitleMethodExplodedListToJson( + List? + videosItemIdStreamContainerHeadSubtitleMethod) { + return videosItemIdStreamContainerHeadSubtitleMethod + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List videosItemIdStreamContainerHeadSubtitleMethodListToJson( + List? + videosItemIdStreamContainerHeadSubtitleMethod) { + if (videosItemIdStreamContainerHeadSubtitleMethod == null) { + return []; + } + + return videosItemIdStreamContainerHeadSubtitleMethod + .map((e) => e.value!) + .toList(); +} + +List + videosItemIdStreamContainerHeadSubtitleMethodListFromJson( + List? videosItemIdStreamContainerHeadSubtitleMethod, [ + List? defaultValue, +]) { + if (videosItemIdStreamContainerHeadSubtitleMethod == null) { + return defaultValue ?? []; + } + + return videosItemIdStreamContainerHeadSubtitleMethod + .map((e) => + videosItemIdStreamContainerHeadSubtitleMethodFromJson(e.toString())) + .toList(); +} + +List? + videosItemIdStreamContainerHeadSubtitleMethodNullableListFromJson( + List? videosItemIdStreamContainerHeadSubtitleMethod, [ + List? defaultValue, +]) { + if (videosItemIdStreamContainerHeadSubtitleMethod == null) { + return defaultValue; + } + + return videosItemIdStreamContainerHeadSubtitleMethod + .map((e) => + videosItemIdStreamContainerHeadSubtitleMethodFromJson(e.toString())) + .toList(); +} + +String? videosItemIdStreamContainerHeadContextNullableToJson( + enums.VideosItemIdStreamContainerHeadContext? + videosItemIdStreamContainerHeadContext) { + return videosItemIdStreamContainerHeadContext?.value; +} + +String? videosItemIdStreamContainerHeadContextToJson( + enums.VideosItemIdStreamContainerHeadContext + videosItemIdStreamContainerHeadContext) { + return videosItemIdStreamContainerHeadContext.value; +} + +enums.VideosItemIdStreamContainerHeadContext + videosItemIdStreamContainerHeadContextFromJson( + Object? videosItemIdStreamContainerHeadContext, [ + enums.VideosItemIdStreamContainerHeadContext? defaultValue, +]) { + return enums.VideosItemIdStreamContainerHeadContext.values.firstWhereOrNull( + (e) => e.value == videosItemIdStreamContainerHeadContext) ?? + defaultValue ?? + enums.VideosItemIdStreamContainerHeadContext.swaggerGeneratedUnknown; +} + +enums.VideosItemIdStreamContainerHeadContext? + videosItemIdStreamContainerHeadContextNullableFromJson( + Object? videosItemIdStreamContainerHeadContext, [ + enums.VideosItemIdStreamContainerHeadContext? defaultValue, +]) { + if (videosItemIdStreamContainerHeadContext == null) { + return null; + } + return enums.VideosItemIdStreamContainerHeadContext.values.firstWhereOrNull( + (e) => e.value == videosItemIdStreamContainerHeadContext) ?? + defaultValue; +} + +String videosItemIdStreamContainerHeadContextExplodedListToJson( + List? + videosItemIdStreamContainerHeadContext) { + return videosItemIdStreamContainerHeadContext + ?.map((e) => e.value!) + .join(',') ?? + ''; +} + +List videosItemIdStreamContainerHeadContextListToJson( + List? + videosItemIdStreamContainerHeadContext) { + if (videosItemIdStreamContainerHeadContext == null) { + return []; + } + + return videosItemIdStreamContainerHeadContext.map((e) => e.value!).toList(); +} + +List + videosItemIdStreamContainerHeadContextListFromJson( + List? videosItemIdStreamContainerHeadContext, [ + List? defaultValue, +]) { + if (videosItemIdStreamContainerHeadContext == null) { + return defaultValue ?? []; + } + + return videosItemIdStreamContainerHeadContext + .map((e) => videosItemIdStreamContainerHeadContextFromJson(e.toString())) + .toList(); +} + +List? + videosItemIdStreamContainerHeadContextNullableListFromJson( + List? videosItemIdStreamContainerHeadContext, [ + List? defaultValue, +]) { + if (videosItemIdStreamContainerHeadContext == null) { + return defaultValue; + } + + return videosItemIdStreamContainerHeadContext + .map((e) => videosItemIdStreamContainerHeadContextFromJson(e.toString())) + .toList(); +} + +typedef $JsonFactory = T Function(Map json); + +class $CustomJsonDecoder { + $CustomJsonDecoder(this.factories); + + final Map factories; + + dynamic decode(dynamic entity) { + if (entity is Iterable) { + return _decodeList(entity); + } + + if (entity is T) { + return entity; + } + + if (isTypeOf()) { + return entity; + } + + if (isTypeOf()) { + return entity; + } + + if (entity is Map) { + return _decodeMap(entity); + } + + return entity; + } + + T _decodeMap(Map values) { + final jsonFactory = factories[T]; + if (jsonFactory == null || jsonFactory is! $JsonFactory) { + return throw "Could not find factory for type $T. Is '$T: $T.fromJsonFactory' included in the CustomJsonDecoder instance creation in bootstrapper.dart?"; + } + + return jsonFactory(values); + } + + List _decodeList(Iterable values) => + values.where((v) => v != null).map((v) => decode(v) as T).toList(); +} + +class $JsonSerializableConverter extends chopper.JsonConverter { + @override + FutureOr> convertResponse( + chopper.Response response) async { + if (response.bodyString.isEmpty) { + // In rare cases, when let's say 204 (no content) is returned - + // we cannot decode the missing json with the result type specified + return chopper.Response(response.base, null, error: response.error); + } + + if (ResultType == String) { + return response.copyWith(); + } + + if (ResultType == DateTime) { + return response.copyWith( + body: DateTime.parse((response.body as String).replaceAll('"', '')) + as ResultType); + } + + final jsonRes = await super.convertResponse(response); + return jsonRes.copyWith( + body: $jsonDecoder.decode(jsonRes.body) as ResultType); + } +} + +final $jsonDecoder = $CustomJsonDecoder(generatedMapping); + +// ignore: unused_element +String? _dateToJson(DateTime? date) { + if (date == null) { + return null; + } + + final year = date.year.toString(); + final month = date.month < 10 ? '0${date.month}' : date.month.toString(); + final day = date.day < 10 ? '0${date.day}' : date.day.toString(); + + return '$year-$month-$day'; +} + +class Wrapped { + final T value; + const Wrapped.value(this.value); +} diff --git a/lib/jellyfin/jellyfin_open_api.swagger.g.dart b/lib/jellyfin/jellyfin_open_api.swagger.g.dart new file mode 100644 index 0000000..eb25731 --- /dev/null +++ b/lib/jellyfin/jellyfin_open_api.swagger.g.dart @@ -0,0 +1,9317 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'jellyfin_open_api.swagger.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +AccessSchedule _$AccessScheduleFromJson(Map json) => + AccessSchedule( + id: (json['Id'] as num?)?.toInt(), + userId: json['UserId'] as String?, + dayOfWeek: dynamicDayOfWeekNullableFromJson(json['DayOfWeek']), + startHour: (json['StartHour'] as num?)?.toDouble(), + endHour: (json['EndHour'] as num?)?.toDouble(), + ); + +Map _$AccessScheduleToJson(AccessSchedule instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Id', instance.id); + writeNotNull('UserId', instance.userId); + writeNotNull('DayOfWeek', dynamicDayOfWeekNullableToJson(instance.dayOfWeek)); + writeNotNull('StartHour', instance.startHour); + writeNotNull('EndHour', instance.endHour); + return val; +} + +ActivityLogEntry _$ActivityLogEntryFromJson(Map json) => + ActivityLogEntry( + id: (json['Id'] as num?)?.toInt(), + name: json['Name'] as String?, + overview: json['Overview'] as String?, + shortOverview: json['ShortOverview'] as String?, + type: json['Type'] as String?, + itemId: json['ItemId'] as String?, + date: + json['Date'] == null ? null : DateTime.parse(json['Date'] as String), + userId: json['UserId'] as String?, + userPrimaryImageTag: json['UserPrimaryImageTag'] as String?, + severity: logLevelNullableFromJson(json['Severity']), + ); + +Map _$ActivityLogEntryToJson(ActivityLogEntry instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Id', instance.id); + writeNotNull('Name', instance.name); + writeNotNull('Overview', instance.overview); + writeNotNull('ShortOverview', instance.shortOverview); + writeNotNull('Type', instance.type); + writeNotNull('ItemId', instance.itemId); + writeNotNull('Date', instance.date?.toIso8601String()); + writeNotNull('UserId', instance.userId); + writeNotNull('UserPrimaryImageTag', instance.userPrimaryImageTag); + writeNotNull('Severity', logLevelNullableToJson(instance.severity)); + return val; +} + +ActivityLogEntryMessage _$ActivityLogEntryMessageFromJson( + Map json) => + ActivityLogEntryMessage( + data: (json['Data'] as List?) + ?.map((e) => ActivityLogEntry.fromJson(e as Map)) + .toList() ?? + [], + messageId: json['MessageId'] as String?, + messageType: + ActivityLogEntryMessage.sessionMessageTypeMessageTypeNullableFromJson( + json['MessageType']), + ); + +Map _$ActivityLogEntryMessageToJson( + ActivityLogEntryMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Data', instance.data?.map((e) => e.toJson()).toList()); + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +ActivityLogEntryQueryResult _$ActivityLogEntryQueryResultFromJson( + Map json) => + ActivityLogEntryQueryResult( + items: (json['Items'] as List?) + ?.map((e) => ActivityLogEntry.fromJson(e as Map)) + .toList() ?? + [], + totalRecordCount: (json['TotalRecordCount'] as num?)?.toInt(), + startIndex: (json['StartIndex'] as num?)?.toInt(), + ); + +Map _$ActivityLogEntryQueryResultToJson( + ActivityLogEntryQueryResult instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Items', instance.items?.map((e) => e.toJson()).toList()); + writeNotNull('TotalRecordCount', instance.totalRecordCount); + writeNotNull('StartIndex', instance.startIndex); + return val; +} + +ActivityLogEntryStartMessage _$ActivityLogEntryStartMessageFromJson( + Map json) => + ActivityLogEntryStartMessage( + data: json['Data'] as String?, + messageType: ActivityLogEntryStartMessage + .sessionMessageTypeMessageTypeNullableFromJson(json['MessageType']), + ); + +Map _$ActivityLogEntryStartMessageToJson( + ActivityLogEntryStartMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Data', instance.data); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +ActivityLogEntryStopMessage _$ActivityLogEntryStopMessageFromJson( + Map json) => + ActivityLogEntryStopMessage( + messageType: ActivityLogEntryStopMessage + .sessionMessageTypeMessageTypeNullableFromJson(json['MessageType']), + ); + +Map _$ActivityLogEntryStopMessageToJson( + ActivityLogEntryStopMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +AddVirtualFolderDto _$AddVirtualFolderDtoFromJson(Map json) => + AddVirtualFolderDto( + libraryOptions: json['LibraryOptions'] == null + ? null + : LibraryOptions.fromJson( + json['LibraryOptions'] as Map), + ); + +Map _$AddVirtualFolderDtoToJson(AddVirtualFolderDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('LibraryOptions', instance.libraryOptions?.toJson()); + return val; +} + +AlbumInfo _$AlbumInfoFromJson(Map json) => AlbumInfo( + name: json['Name'] as String?, + originalTitle: json['OriginalTitle'] as String?, + path: json['Path'] as String?, + metadataLanguage: json['MetadataLanguage'] as String?, + metadataCountryCode: json['MetadataCountryCode'] as String?, + providerIds: json['ProviderIds'] as Map?, + year: (json['Year'] as num?)?.toInt(), + indexNumber: (json['IndexNumber'] as num?)?.toInt(), + parentIndexNumber: (json['ParentIndexNumber'] as num?)?.toInt(), + premiereDate: json['PremiereDate'] == null + ? null + : DateTime.parse(json['PremiereDate'] as String), + isAutomated: json['IsAutomated'] as bool?, + albumArtists: (json['AlbumArtists'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + artistProviderIds: json['ArtistProviderIds'] as Map?, + songInfos: (json['SongInfos'] as List?) + ?.map((e) => SongInfo.fromJson(e as Map)) + .toList() ?? + [], + ); + +Map _$AlbumInfoToJson(AlbumInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('OriginalTitle', instance.originalTitle); + writeNotNull('Path', instance.path); + writeNotNull('MetadataLanguage', instance.metadataLanguage); + writeNotNull('MetadataCountryCode', instance.metadataCountryCode); + writeNotNull('ProviderIds', instance.providerIds); + writeNotNull('Year', instance.year); + writeNotNull('IndexNumber', instance.indexNumber); + writeNotNull('ParentIndexNumber', instance.parentIndexNumber); + writeNotNull('PremiereDate', instance.premiereDate?.toIso8601String()); + writeNotNull('IsAutomated', instance.isAutomated); + writeNotNull('AlbumArtists', instance.albumArtists); + writeNotNull('ArtistProviderIds', instance.artistProviderIds); + writeNotNull( + 'SongInfos', instance.songInfos?.map((e) => e.toJson()).toList()); + return val; +} + +AlbumInfoRemoteSearchQuery _$AlbumInfoRemoteSearchQueryFromJson( + Map json) => + AlbumInfoRemoteSearchQuery( + searchInfo: json['SearchInfo'] == null + ? null + : AlbumInfo.fromJson(json['SearchInfo'] as Map), + itemId: json['ItemId'] as String?, + searchProviderName: json['SearchProviderName'] as String?, + includeDisabledProviders: json['IncludeDisabledProviders'] as bool?, + ); + +Map _$AlbumInfoRemoteSearchQueryToJson( + AlbumInfoRemoteSearchQuery instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('SearchInfo', instance.searchInfo?.toJson()); + writeNotNull('ItemId', instance.itemId); + writeNotNull('SearchProviderName', instance.searchProviderName); + writeNotNull('IncludeDisabledProviders', instance.includeDisabledProviders); + return val; +} + +AllThemeMediaResult _$AllThemeMediaResultFromJson(Map json) => + AllThemeMediaResult( + themeVideosResult: json['ThemeVideosResult'] == null + ? null + : ThemeMediaResult.fromJson( + json['ThemeVideosResult'] as Map), + themeSongsResult: json['ThemeSongsResult'] == null + ? null + : ThemeMediaResult.fromJson( + json['ThemeSongsResult'] as Map), + soundtrackSongsResult: json['SoundtrackSongsResult'] == null + ? null + : ThemeMediaResult.fromJson( + json['SoundtrackSongsResult'] as Map), + ); + +Map _$AllThemeMediaResultToJson(AllThemeMediaResult instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('ThemeVideosResult', instance.themeVideosResult?.toJson()); + writeNotNull('ThemeSongsResult', instance.themeSongsResult?.toJson()); + writeNotNull( + 'SoundtrackSongsResult', instance.soundtrackSongsResult?.toJson()); + return val; +} + +ArtistInfo _$ArtistInfoFromJson(Map json) => ArtistInfo( + name: json['Name'] as String?, + originalTitle: json['OriginalTitle'] as String?, + path: json['Path'] as String?, + metadataLanguage: json['MetadataLanguage'] as String?, + metadataCountryCode: json['MetadataCountryCode'] as String?, + providerIds: json['ProviderIds'] as Map?, + year: (json['Year'] as num?)?.toInt(), + indexNumber: (json['IndexNumber'] as num?)?.toInt(), + parentIndexNumber: (json['ParentIndexNumber'] as num?)?.toInt(), + premiereDate: json['PremiereDate'] == null + ? null + : DateTime.parse(json['PremiereDate'] as String), + isAutomated: json['IsAutomated'] as bool?, + songInfos: (json['SongInfos'] as List?) + ?.map((e) => SongInfo.fromJson(e as Map)) + .toList() ?? + [], + ); + +Map _$ArtistInfoToJson(ArtistInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('OriginalTitle', instance.originalTitle); + writeNotNull('Path', instance.path); + writeNotNull('MetadataLanguage', instance.metadataLanguage); + writeNotNull('MetadataCountryCode', instance.metadataCountryCode); + writeNotNull('ProviderIds', instance.providerIds); + writeNotNull('Year', instance.year); + writeNotNull('IndexNumber', instance.indexNumber); + writeNotNull('ParentIndexNumber', instance.parentIndexNumber); + writeNotNull('PremiereDate', instance.premiereDate?.toIso8601String()); + writeNotNull('IsAutomated', instance.isAutomated); + writeNotNull( + 'SongInfos', instance.songInfos?.map((e) => e.toJson()).toList()); + return val; +} + +ArtistInfoRemoteSearchQuery _$ArtistInfoRemoteSearchQueryFromJson( + Map json) => + ArtistInfoRemoteSearchQuery( + searchInfo: json['SearchInfo'] == null + ? null + : ArtistInfo.fromJson(json['SearchInfo'] as Map), + itemId: json['ItemId'] as String?, + searchProviderName: json['SearchProviderName'] as String?, + includeDisabledProviders: json['IncludeDisabledProviders'] as bool?, + ); + +Map _$ArtistInfoRemoteSearchQueryToJson( + ArtistInfoRemoteSearchQuery instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('SearchInfo', instance.searchInfo?.toJson()); + writeNotNull('ItemId', instance.itemId); + writeNotNull('SearchProviderName', instance.searchProviderName); + writeNotNull('IncludeDisabledProviders', instance.includeDisabledProviders); + return val; +} + +AuthenticateUserByName _$AuthenticateUserByNameFromJson( + Map json) => + AuthenticateUserByName( + username: json['Username'] as String?, + pw: json['Pw'] as String?, + ); + +Map _$AuthenticateUserByNameToJson( + AuthenticateUserByName instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Username', instance.username); + writeNotNull('Pw', instance.pw); + return val; +} + +AuthenticationInfo _$AuthenticationInfoFromJson(Map json) => + AuthenticationInfo( + id: (json['Id'] as num?)?.toInt(), + accessToken: json['AccessToken'] as String?, + deviceId: json['DeviceId'] as String?, + appName: json['AppName'] as String?, + appVersion: json['AppVersion'] as String?, + deviceName: json['DeviceName'] as String?, + userId: json['UserId'] as String?, + isActive: json['IsActive'] as bool?, + dateCreated: json['DateCreated'] == null + ? null + : DateTime.parse(json['DateCreated'] as String), + dateRevoked: json['DateRevoked'] == null + ? null + : DateTime.parse(json['DateRevoked'] as String), + dateLastActivity: json['DateLastActivity'] == null + ? null + : DateTime.parse(json['DateLastActivity'] as String), + userName: json['UserName'] as String?, + ); + +Map _$AuthenticationInfoToJson(AuthenticationInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Id', instance.id); + writeNotNull('AccessToken', instance.accessToken); + writeNotNull('DeviceId', instance.deviceId); + writeNotNull('AppName', instance.appName); + writeNotNull('AppVersion', instance.appVersion); + writeNotNull('DeviceName', instance.deviceName); + writeNotNull('UserId', instance.userId); + writeNotNull('IsActive', instance.isActive); + writeNotNull('DateCreated', instance.dateCreated?.toIso8601String()); + writeNotNull('DateRevoked', instance.dateRevoked?.toIso8601String()); + writeNotNull( + 'DateLastActivity', instance.dateLastActivity?.toIso8601String()); + writeNotNull('UserName', instance.userName); + return val; +} + +AuthenticationInfoQueryResult _$AuthenticationInfoQueryResultFromJson( + Map json) => + AuthenticationInfoQueryResult( + items: (json['Items'] as List?) + ?.map( + (e) => AuthenticationInfo.fromJson(e as Map)) + .toList() ?? + [], + totalRecordCount: (json['TotalRecordCount'] as num?)?.toInt(), + startIndex: (json['StartIndex'] as num?)?.toInt(), + ); + +Map _$AuthenticationInfoQueryResultToJson( + AuthenticationInfoQueryResult instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Items', instance.items?.map((e) => e.toJson()).toList()); + writeNotNull('TotalRecordCount', instance.totalRecordCount); + writeNotNull('StartIndex', instance.startIndex); + return val; +} + +AuthenticationResult _$AuthenticationResultFromJson( + Map json) => + AuthenticationResult( + user: json['User'] == null + ? null + : UserDto.fromJson(json['User'] as Map), + sessionInfo: json['SessionInfo'] == null + ? null + : SessionInfo.fromJson(json['SessionInfo'] as Map), + accessToken: json['AccessToken'] as String?, + serverId: json['ServerId'] as String?, + ); + +Map _$AuthenticationResultToJson( + AuthenticationResult instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('User', instance.user?.toJson()); + writeNotNull('SessionInfo', instance.sessionInfo?.toJson()); + writeNotNull('AccessToken', instance.accessToken); + writeNotNull('ServerId', instance.serverId); + return val; +} + +BaseItemDto _$BaseItemDtoFromJson(Map json) => BaseItemDto( + name: json['Name'] as String?, + originalTitle: json['OriginalTitle'] as String?, + serverId: json['ServerId'] as String?, + id: json['Id'] as String?, + etag: json['Etag'] as String?, + sourceType: json['SourceType'] as String?, + playlistItemId: json['PlaylistItemId'] as String?, + dateCreated: json['DateCreated'] == null + ? null + : DateTime.parse(json['DateCreated'] as String), + dateLastMediaAdded: json['DateLastMediaAdded'] == null + ? null + : DateTime.parse(json['DateLastMediaAdded'] as String), + extraType: extraTypeNullableFromJson(json['ExtraType']), + airsBeforeSeasonNumber: (json['AirsBeforeSeasonNumber'] as num?)?.toInt(), + airsAfterSeasonNumber: (json['AirsAfterSeasonNumber'] as num?)?.toInt(), + airsBeforeEpisodeNumber: + (json['AirsBeforeEpisodeNumber'] as num?)?.toInt(), + canDelete: json['CanDelete'] as bool?, + canDownload: json['CanDownload'] as bool?, + hasLyrics: json['HasLyrics'] as bool?, + hasSubtitles: json['HasSubtitles'] as bool?, + preferredMetadataLanguage: json['PreferredMetadataLanguage'] as String?, + preferredMetadataCountryCode: + json['PreferredMetadataCountryCode'] as String?, + container: json['Container'] as String?, + sortName: json['SortName'] as String?, + forcedSortName: json['ForcedSortName'] as String?, + video3DFormat: video3DFormatNullableFromJson(json['Video3DFormat']), + premiereDate: json['PremiereDate'] == null + ? null + : DateTime.parse(json['PremiereDate'] as String), + externalUrls: (json['ExternalUrls'] as List?) + ?.map((e) => ExternalUrl.fromJson(e as Map)) + .toList() ?? + [], + mediaSources: (json['MediaSources'] as List?) + ?.map((e) => MediaSourceInfo.fromJson(e as Map)) + .toList() ?? + [], + criticRating: (json['CriticRating'] as num?)?.toDouble(), + productionLocations: (json['ProductionLocations'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + path: json['Path'] as String?, + enableMediaSourceDisplay: json['EnableMediaSourceDisplay'] as bool?, + officialRating: json['OfficialRating'] as String?, + customRating: json['CustomRating'] as String?, + channelId: json['ChannelId'] as String?, + channelName: json['ChannelName'] as String?, + overview: json['Overview'] as String?, + taglines: (json['Taglines'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + genres: (json['Genres'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + communityRating: (json['CommunityRating'] as num?)?.toDouble(), + cumulativeRunTimeTicks: (json['CumulativeRunTimeTicks'] as num?)?.toInt(), + runTimeTicks: (json['RunTimeTicks'] as num?)?.toInt(), + playAccess: playAccessNullableFromJson(json['PlayAccess']), + aspectRatio: json['AspectRatio'] as String?, + productionYear: (json['ProductionYear'] as num?)?.toInt(), + isPlaceHolder: json['IsPlaceHolder'] as bool?, + number: json['Number'] as String?, + channelNumber: json['ChannelNumber'] as String?, + indexNumber: (json['IndexNumber'] as num?)?.toInt(), + indexNumberEnd: (json['IndexNumberEnd'] as num?)?.toInt(), + parentIndexNumber: (json['ParentIndexNumber'] as num?)?.toInt(), + remoteTrailers: (json['RemoteTrailers'] as List?) + ?.map((e) => MediaUrl.fromJson(e as Map)) + .toList() ?? + [], + providerIds: json['ProviderIds'] as Map?, + isHD: json['IsHD'] as bool?, + isFolder: json['IsFolder'] as bool?, + parentId: json['ParentId'] as String?, + type: baseItemKindNullableFromJson(json['Type']), + people: (json['People'] as List?) + ?.map((e) => BaseItemPerson.fromJson(e as Map)) + .toList() ?? + [], + studios: (json['Studios'] as List?) + ?.map((e) => NameGuidPair.fromJson(e as Map)) + .toList() ?? + [], + genreItems: (json['GenreItems'] as List?) + ?.map((e) => NameGuidPair.fromJson(e as Map)) + .toList() ?? + [], + parentLogoItemId: json['ParentLogoItemId'] as String?, + parentBackdropItemId: json['ParentBackdropItemId'] as String?, + parentBackdropImageTags: + (json['ParentBackdropImageTags'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + localTrailerCount: (json['LocalTrailerCount'] as num?)?.toInt(), + userData: json['UserData'] == null + ? null + : UserItemDataDto.fromJson(json['UserData'] as Map), + recursiveItemCount: (json['RecursiveItemCount'] as num?)?.toInt(), + childCount: (json['ChildCount'] as num?)?.toInt(), + seriesName: json['SeriesName'] as String?, + seriesId: json['SeriesId'] as String?, + seasonId: json['SeasonId'] as String?, + specialFeatureCount: (json['SpecialFeatureCount'] as num?)?.toInt(), + displayPreferencesId: json['DisplayPreferencesId'] as String?, + status: json['Status'] as String?, + airTime: json['AirTime'] as String?, + airDays: dayOfWeekListFromJson(json['AirDays'] as List?), + tags: + (json['Tags'] as List?)?.map((e) => e as String).toList() ?? + [], + primaryImageAspectRatio: + (json['PrimaryImageAspectRatio'] as num?)?.toDouble(), + artists: (json['Artists'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + artistItems: (json['ArtistItems'] as List?) + ?.map((e) => NameGuidPair.fromJson(e as Map)) + .toList() ?? + [], + album: json['Album'] as String?, + collectionType: collectionTypeNullableFromJson(json['CollectionType']), + displayOrder: json['DisplayOrder'] as String?, + albumId: json['AlbumId'] as String?, + albumPrimaryImageTag: json['AlbumPrimaryImageTag'] as String?, + seriesPrimaryImageTag: json['SeriesPrimaryImageTag'] as String?, + albumArtist: json['AlbumArtist'] as String?, + albumArtists: (json['AlbumArtists'] as List?) + ?.map((e) => NameGuidPair.fromJson(e as Map)) + .toList() ?? + [], + seasonName: json['SeasonName'] as String?, + mediaStreams: (json['MediaStreams'] as List?) + ?.map((e) => MediaStream.fromJson(e as Map)) + .toList() ?? + [], + videoType: videoTypeNullableFromJson(json['VideoType']), + partCount: (json['PartCount'] as num?)?.toInt(), + mediaSourceCount: (json['MediaSourceCount'] as num?)?.toInt(), + imageTags: json['ImageTags'] as Map?, + backdropImageTags: (json['BackdropImageTags'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + screenshotImageTags: (json['ScreenshotImageTags'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + parentLogoImageTag: json['ParentLogoImageTag'] as String?, + parentArtItemId: json['ParentArtItemId'] as String?, + parentArtImageTag: json['ParentArtImageTag'] as String?, + seriesThumbImageTag: json['SeriesThumbImageTag'] as String?, + imageBlurHashes: json['ImageBlurHashes'] == null + ? null + : BaseItemDto$ImageBlurHashes.fromJson( + json['ImageBlurHashes'] as Map), + seriesStudio: json['SeriesStudio'] as String?, + parentThumbItemId: json['ParentThumbItemId'] as String?, + parentThumbImageTag: json['ParentThumbImageTag'] as String?, + parentPrimaryImageItemId: json['ParentPrimaryImageItemId'] as String?, + parentPrimaryImageTag: json['ParentPrimaryImageTag'] as String?, + chapters: (json['Chapters'] as List?) + ?.map((e) => ChapterInfo.fromJson(e as Map)) + .toList() ?? + [], + trickplay: json['Trickplay'] as Map?, + locationType: locationTypeNullableFromJson(json['LocationType']), + isoType: isoTypeNullableFromJson(json['IsoType']), + mediaType: mediaTypeNullableFromJson(json['MediaType']), + endDate: json['EndDate'] == null + ? null + : DateTime.parse(json['EndDate'] as String), + lockedFields: metadataFieldListFromJson(json['LockedFields'] as List?), + trailerCount: (json['TrailerCount'] as num?)?.toInt(), + movieCount: (json['MovieCount'] as num?)?.toInt(), + seriesCount: (json['SeriesCount'] as num?)?.toInt(), + programCount: (json['ProgramCount'] as num?)?.toInt(), + episodeCount: (json['EpisodeCount'] as num?)?.toInt(), + songCount: (json['SongCount'] as num?)?.toInt(), + albumCount: (json['AlbumCount'] as num?)?.toInt(), + artistCount: (json['ArtistCount'] as num?)?.toInt(), + musicVideoCount: (json['MusicVideoCount'] as num?)?.toInt(), + lockData: json['LockData'] as bool?, + width: (json['Width'] as num?)?.toInt(), + height: (json['Height'] as num?)?.toInt(), + cameraMake: json['CameraMake'] as String?, + cameraModel: json['CameraModel'] as String?, + software: json['Software'] as String?, + exposureTime: (json['ExposureTime'] as num?)?.toDouble(), + focalLength: (json['FocalLength'] as num?)?.toDouble(), + imageOrientation: + imageOrientationNullableFromJson(json['ImageOrientation']), + aperture: (json['Aperture'] as num?)?.toDouble(), + shutterSpeed: (json['ShutterSpeed'] as num?)?.toDouble(), + latitude: (json['Latitude'] as num?)?.toDouble(), + longitude: (json['Longitude'] as num?)?.toDouble(), + altitude: (json['Altitude'] as num?)?.toDouble(), + isoSpeedRating: (json['IsoSpeedRating'] as num?)?.toInt(), + seriesTimerId: json['SeriesTimerId'] as String?, + programId: json['ProgramId'] as String?, + channelPrimaryImageTag: json['ChannelPrimaryImageTag'] as String?, + startDate: json['StartDate'] == null + ? null + : DateTime.parse(json['StartDate'] as String), + completionPercentage: (json['CompletionPercentage'] as num?)?.toDouble(), + isRepeat: json['IsRepeat'] as bool?, + episodeTitle: json['EpisodeTitle'] as String?, + channelType: channelTypeNullableFromJson(json['ChannelType']), + audio: programAudioNullableFromJson(json['Audio']), + isMovie: json['IsMovie'] as bool?, + isSports: json['IsSports'] as bool?, + isSeries: json['IsSeries'] as bool?, + isLive: json['IsLive'] as bool?, + isNews: json['IsNews'] as bool?, + isKids: json['IsKids'] as bool?, + isPremiere: json['IsPremiere'] as bool?, + timerId: json['TimerId'] as String?, + normalizationGain: (json['NormalizationGain'] as num?)?.toDouble(), + currentProgram: json['CurrentProgram'] == null + ? null + : BaseItemDto.fromJson( + json['CurrentProgram'] as Map), + ); + +Map _$BaseItemDtoToJson(BaseItemDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('OriginalTitle', instance.originalTitle); + writeNotNull('ServerId', instance.serverId); + writeNotNull('Id', instance.id); + writeNotNull('Etag', instance.etag); + writeNotNull('SourceType', instance.sourceType); + writeNotNull('PlaylistItemId', instance.playlistItemId); + writeNotNull('DateCreated', instance.dateCreated?.toIso8601String()); + writeNotNull( + 'DateLastMediaAdded', instance.dateLastMediaAdded?.toIso8601String()); + writeNotNull('ExtraType', extraTypeNullableToJson(instance.extraType)); + writeNotNull('AirsBeforeSeasonNumber', instance.airsBeforeSeasonNumber); + writeNotNull('AirsAfterSeasonNumber', instance.airsAfterSeasonNumber); + writeNotNull('AirsBeforeEpisodeNumber', instance.airsBeforeEpisodeNumber); + writeNotNull('CanDelete', instance.canDelete); + writeNotNull('CanDownload', instance.canDownload); + writeNotNull('HasLyrics', instance.hasLyrics); + writeNotNull('HasSubtitles', instance.hasSubtitles); + writeNotNull('PreferredMetadataLanguage', instance.preferredMetadataLanguage); + writeNotNull( + 'PreferredMetadataCountryCode', instance.preferredMetadataCountryCode); + writeNotNull('Container', instance.container); + writeNotNull('SortName', instance.sortName); + writeNotNull('ForcedSortName', instance.forcedSortName); + writeNotNull( + 'Video3DFormat', video3DFormatNullableToJson(instance.video3DFormat)); + writeNotNull('PremiereDate', instance.premiereDate?.toIso8601String()); + writeNotNull( + 'ExternalUrls', instance.externalUrls?.map((e) => e.toJson()).toList()); + writeNotNull( + 'MediaSources', instance.mediaSources?.map((e) => e.toJson()).toList()); + writeNotNull('CriticRating', instance.criticRating); + writeNotNull('ProductionLocations', instance.productionLocations); + writeNotNull('Path', instance.path); + writeNotNull('EnableMediaSourceDisplay', instance.enableMediaSourceDisplay); + writeNotNull('OfficialRating', instance.officialRating); + writeNotNull('CustomRating', instance.customRating); + writeNotNull('ChannelId', instance.channelId); + writeNotNull('ChannelName', instance.channelName); + writeNotNull('Overview', instance.overview); + writeNotNull('Taglines', instance.taglines); + writeNotNull('Genres', instance.genres); + writeNotNull('CommunityRating', instance.communityRating); + writeNotNull('CumulativeRunTimeTicks', instance.cumulativeRunTimeTicks); + writeNotNull('RunTimeTicks', instance.runTimeTicks); + writeNotNull('PlayAccess', playAccessNullableToJson(instance.playAccess)); + writeNotNull('AspectRatio', instance.aspectRatio); + writeNotNull('ProductionYear', instance.productionYear); + writeNotNull('IsPlaceHolder', instance.isPlaceHolder); + writeNotNull('Number', instance.number); + writeNotNull('ChannelNumber', instance.channelNumber); + writeNotNull('IndexNumber', instance.indexNumber); + writeNotNull('IndexNumberEnd', instance.indexNumberEnd); + writeNotNull('ParentIndexNumber', instance.parentIndexNumber); + writeNotNull('RemoteTrailers', + instance.remoteTrailers?.map((e) => e.toJson()).toList()); + writeNotNull('ProviderIds', instance.providerIds); + writeNotNull('IsHD', instance.isHD); + writeNotNull('IsFolder', instance.isFolder); + writeNotNull('ParentId', instance.parentId); + writeNotNull('Type', baseItemKindNullableToJson(instance.type)); + writeNotNull('People', instance.people?.map((e) => e.toJson()).toList()); + writeNotNull('Studios', instance.studios?.map((e) => e.toJson()).toList()); + writeNotNull( + 'GenreItems', instance.genreItems?.map((e) => e.toJson()).toList()); + writeNotNull('ParentLogoItemId', instance.parentLogoItemId); + writeNotNull('ParentBackdropItemId', instance.parentBackdropItemId); + writeNotNull('ParentBackdropImageTags', instance.parentBackdropImageTags); + writeNotNull('LocalTrailerCount', instance.localTrailerCount); + writeNotNull('UserData', instance.userData?.toJson()); + writeNotNull('RecursiveItemCount', instance.recursiveItemCount); + writeNotNull('ChildCount', instance.childCount); + writeNotNull('SeriesName', instance.seriesName); + writeNotNull('SeriesId', instance.seriesId); + writeNotNull('SeasonId', instance.seasonId); + writeNotNull('SpecialFeatureCount', instance.specialFeatureCount); + writeNotNull('DisplayPreferencesId', instance.displayPreferencesId); + writeNotNull('Status', instance.status); + writeNotNull('AirTime', instance.airTime); + val['AirDays'] = dayOfWeekListToJson(instance.airDays); + writeNotNull('Tags', instance.tags); + writeNotNull('PrimaryImageAspectRatio', instance.primaryImageAspectRatio); + writeNotNull('Artists', instance.artists); + writeNotNull( + 'ArtistItems', instance.artistItems?.map((e) => e.toJson()).toList()); + writeNotNull('Album', instance.album); + writeNotNull( + 'CollectionType', collectionTypeNullableToJson(instance.collectionType)); + writeNotNull('DisplayOrder', instance.displayOrder); + writeNotNull('AlbumId', instance.albumId); + writeNotNull('AlbumPrimaryImageTag', instance.albumPrimaryImageTag); + writeNotNull('SeriesPrimaryImageTag', instance.seriesPrimaryImageTag); + writeNotNull('AlbumArtist', instance.albumArtist); + writeNotNull( + 'AlbumArtists', instance.albumArtists?.map((e) => e.toJson()).toList()); + writeNotNull('SeasonName', instance.seasonName); + writeNotNull( + 'MediaStreams', instance.mediaStreams?.map((e) => e.toJson()).toList()); + writeNotNull('VideoType', videoTypeNullableToJson(instance.videoType)); + writeNotNull('PartCount', instance.partCount); + writeNotNull('MediaSourceCount', instance.mediaSourceCount); + writeNotNull('ImageTags', instance.imageTags); + writeNotNull('BackdropImageTags', instance.backdropImageTags); + writeNotNull('ScreenshotImageTags', instance.screenshotImageTags); + writeNotNull('ParentLogoImageTag', instance.parentLogoImageTag); + writeNotNull('ParentArtItemId', instance.parentArtItemId); + writeNotNull('ParentArtImageTag', instance.parentArtImageTag); + writeNotNull('SeriesThumbImageTag', instance.seriesThumbImageTag); + writeNotNull('ImageBlurHashes', instance.imageBlurHashes?.toJson()); + writeNotNull('SeriesStudio', instance.seriesStudio); + writeNotNull('ParentThumbItemId', instance.parentThumbItemId); + writeNotNull('ParentThumbImageTag', instance.parentThumbImageTag); + writeNotNull('ParentPrimaryImageItemId', instance.parentPrimaryImageItemId); + writeNotNull('ParentPrimaryImageTag', instance.parentPrimaryImageTag); + writeNotNull('Chapters', instance.chapters?.map((e) => e.toJson()).toList()); + writeNotNull('Trickplay', instance.trickplay); + writeNotNull( + 'LocationType', locationTypeNullableToJson(instance.locationType)); + writeNotNull('IsoType', isoTypeNullableToJson(instance.isoType)); + writeNotNull('MediaType', mediaTypeNullableToJson(instance.mediaType)); + writeNotNull('EndDate', instance.endDate?.toIso8601String()); + val['LockedFields'] = metadataFieldListToJson(instance.lockedFields); + writeNotNull('TrailerCount', instance.trailerCount); + writeNotNull('MovieCount', instance.movieCount); + writeNotNull('SeriesCount', instance.seriesCount); + writeNotNull('ProgramCount', instance.programCount); + writeNotNull('EpisodeCount', instance.episodeCount); + writeNotNull('SongCount', instance.songCount); + writeNotNull('AlbumCount', instance.albumCount); + writeNotNull('ArtistCount', instance.artistCount); + writeNotNull('MusicVideoCount', instance.musicVideoCount); + writeNotNull('LockData', instance.lockData); + writeNotNull('Width', instance.width); + writeNotNull('Height', instance.height); + writeNotNull('CameraMake', instance.cameraMake); + writeNotNull('CameraModel', instance.cameraModel); + writeNotNull('Software', instance.software); + writeNotNull('ExposureTime', instance.exposureTime); + writeNotNull('FocalLength', instance.focalLength); + writeNotNull('ImageOrientation', + imageOrientationNullableToJson(instance.imageOrientation)); + writeNotNull('Aperture', instance.aperture); + writeNotNull('ShutterSpeed', instance.shutterSpeed); + writeNotNull('Latitude', instance.latitude); + writeNotNull('Longitude', instance.longitude); + writeNotNull('Altitude', instance.altitude); + writeNotNull('IsoSpeedRating', instance.isoSpeedRating); + writeNotNull('SeriesTimerId', instance.seriesTimerId); + writeNotNull('ProgramId', instance.programId); + writeNotNull('ChannelPrimaryImageTag', instance.channelPrimaryImageTag); + writeNotNull('StartDate', instance.startDate?.toIso8601String()); + writeNotNull('CompletionPercentage', instance.completionPercentage); + writeNotNull('IsRepeat', instance.isRepeat); + writeNotNull('EpisodeTitle', instance.episodeTitle); + writeNotNull('ChannelType', channelTypeNullableToJson(instance.channelType)); + writeNotNull('Audio', programAudioNullableToJson(instance.audio)); + writeNotNull('IsMovie', instance.isMovie); + writeNotNull('IsSports', instance.isSports); + writeNotNull('IsSeries', instance.isSeries); + writeNotNull('IsLive', instance.isLive); + writeNotNull('IsNews', instance.isNews); + writeNotNull('IsKids', instance.isKids); + writeNotNull('IsPremiere', instance.isPremiere); + writeNotNull('TimerId', instance.timerId); + writeNotNull('NormalizationGain', instance.normalizationGain); + writeNotNull('CurrentProgram', instance.currentProgram?.toJson()); + return val; +} + +BaseItemDtoQueryResult _$BaseItemDtoQueryResultFromJson( + Map json) => + BaseItemDtoQueryResult( + items: (json['Items'] as List?) + ?.map((e) => BaseItemDto.fromJson(e as Map)) + .toList() ?? + [], + totalRecordCount: (json['TotalRecordCount'] as num?)?.toInt(), + startIndex: (json['StartIndex'] as num?)?.toInt(), + ); + +Map _$BaseItemDtoQueryResultToJson( + BaseItemDtoQueryResult instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Items', instance.items?.map((e) => e.toJson()).toList()); + writeNotNull('TotalRecordCount', instance.totalRecordCount); + writeNotNull('StartIndex', instance.startIndex); + return val; +} + +BaseItemPerson _$BaseItemPersonFromJson(Map json) => + BaseItemPerson( + name: json['Name'] as String?, + id: json['Id'] as String?, + role: json['Role'] as String?, + type: personKindNullableFromJson(json['Type']), + primaryImageTag: json['PrimaryImageTag'] as String?, + imageBlurHashes: json['ImageBlurHashes'] == null + ? null + : BaseItemPerson$ImageBlurHashes.fromJson( + json['ImageBlurHashes'] as Map), + ); + +Map _$BaseItemPersonToJson(BaseItemPerson instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('Id', instance.id); + writeNotNull('Role', instance.role); + writeNotNull('Type', personKindNullableToJson(instance.type)); + writeNotNull('PrimaryImageTag', instance.primaryImageTag); + writeNotNull('ImageBlurHashes', instance.imageBlurHashes?.toJson()); + return val; +} + +BasePluginConfiguration _$BasePluginConfigurationFromJson( + Map json) => + BasePluginConfiguration(); + +Map _$BasePluginConfigurationToJson( + BasePluginConfiguration instance) => + {}; + +BookInfo _$BookInfoFromJson(Map json) => BookInfo( + name: json['Name'] as String?, + originalTitle: json['OriginalTitle'] as String?, + path: json['Path'] as String?, + metadataLanguage: json['MetadataLanguage'] as String?, + metadataCountryCode: json['MetadataCountryCode'] as String?, + providerIds: json['ProviderIds'] as Map?, + year: (json['Year'] as num?)?.toInt(), + indexNumber: (json['IndexNumber'] as num?)?.toInt(), + parentIndexNumber: (json['ParentIndexNumber'] as num?)?.toInt(), + premiereDate: json['PremiereDate'] == null + ? null + : DateTime.parse(json['PremiereDate'] as String), + isAutomated: json['IsAutomated'] as bool?, + seriesName: json['SeriesName'] as String?, + ); + +Map _$BookInfoToJson(BookInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('OriginalTitle', instance.originalTitle); + writeNotNull('Path', instance.path); + writeNotNull('MetadataLanguage', instance.metadataLanguage); + writeNotNull('MetadataCountryCode', instance.metadataCountryCode); + writeNotNull('ProviderIds', instance.providerIds); + writeNotNull('Year', instance.year); + writeNotNull('IndexNumber', instance.indexNumber); + writeNotNull('ParentIndexNumber', instance.parentIndexNumber); + writeNotNull('PremiereDate', instance.premiereDate?.toIso8601String()); + writeNotNull('IsAutomated', instance.isAutomated); + writeNotNull('SeriesName', instance.seriesName); + return val; +} + +BookInfoRemoteSearchQuery _$BookInfoRemoteSearchQueryFromJson( + Map json) => + BookInfoRemoteSearchQuery( + searchInfo: json['SearchInfo'] == null + ? null + : BookInfo.fromJson(json['SearchInfo'] as Map), + itemId: json['ItemId'] as String?, + searchProviderName: json['SearchProviderName'] as String?, + includeDisabledProviders: json['IncludeDisabledProviders'] as bool?, + ); + +Map _$BookInfoRemoteSearchQueryToJson( + BookInfoRemoteSearchQuery instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('SearchInfo', instance.searchInfo?.toJson()); + writeNotNull('ItemId', instance.itemId); + writeNotNull('SearchProviderName', instance.searchProviderName); + writeNotNull('IncludeDisabledProviders', instance.includeDisabledProviders); + return val; +} + +BoxSetInfo _$BoxSetInfoFromJson(Map json) => BoxSetInfo( + name: json['Name'] as String?, + originalTitle: json['OriginalTitle'] as String?, + path: json['Path'] as String?, + metadataLanguage: json['MetadataLanguage'] as String?, + metadataCountryCode: json['MetadataCountryCode'] as String?, + providerIds: json['ProviderIds'] as Map?, + year: (json['Year'] as num?)?.toInt(), + indexNumber: (json['IndexNumber'] as num?)?.toInt(), + parentIndexNumber: (json['ParentIndexNumber'] as num?)?.toInt(), + premiereDate: json['PremiereDate'] == null + ? null + : DateTime.parse(json['PremiereDate'] as String), + isAutomated: json['IsAutomated'] as bool?, + ); + +Map _$BoxSetInfoToJson(BoxSetInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('OriginalTitle', instance.originalTitle); + writeNotNull('Path', instance.path); + writeNotNull('MetadataLanguage', instance.metadataLanguage); + writeNotNull('MetadataCountryCode', instance.metadataCountryCode); + writeNotNull('ProviderIds', instance.providerIds); + writeNotNull('Year', instance.year); + writeNotNull('IndexNumber', instance.indexNumber); + writeNotNull('ParentIndexNumber', instance.parentIndexNumber); + writeNotNull('PremiereDate', instance.premiereDate?.toIso8601String()); + writeNotNull('IsAutomated', instance.isAutomated); + return val; +} + +BoxSetInfoRemoteSearchQuery _$BoxSetInfoRemoteSearchQueryFromJson( + Map json) => + BoxSetInfoRemoteSearchQuery( + searchInfo: json['SearchInfo'] == null + ? null + : BoxSetInfo.fromJson(json['SearchInfo'] as Map), + itemId: json['ItemId'] as String?, + searchProviderName: json['SearchProviderName'] as String?, + includeDisabledProviders: json['IncludeDisabledProviders'] as bool?, + ); + +Map _$BoxSetInfoRemoteSearchQueryToJson( + BoxSetInfoRemoteSearchQuery instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('SearchInfo', instance.searchInfo?.toJson()); + writeNotNull('ItemId', instance.itemId); + writeNotNull('SearchProviderName', instance.searchProviderName); + writeNotNull('IncludeDisabledProviders', instance.includeDisabledProviders); + return val; +} + +BrandingOptions _$BrandingOptionsFromJson(Map json) => + BrandingOptions( + loginDisclaimer: json['LoginDisclaimer'] as String?, + customCss: json['CustomCss'] as String?, + splashscreenEnabled: json['SplashscreenEnabled'] as bool?, + ); + +Map _$BrandingOptionsToJson(BrandingOptions instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('LoginDisclaimer', instance.loginDisclaimer); + writeNotNull('CustomCss', instance.customCss); + writeNotNull('SplashscreenEnabled', instance.splashscreenEnabled); + return val; +} + +BufferRequestDto _$BufferRequestDtoFromJson(Map json) => + BufferRequestDto( + when: + json['When'] == null ? null : DateTime.parse(json['When'] as String), + positionTicks: (json['PositionTicks'] as num?)?.toInt(), + isPlaying: json['IsPlaying'] as bool?, + playlistItemId: json['PlaylistItemId'] as String?, + ); + +Map _$BufferRequestDtoToJson(BufferRequestDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('When', instance.when?.toIso8601String()); + writeNotNull('PositionTicks', instance.positionTicks); + writeNotNull('IsPlaying', instance.isPlaying); + writeNotNull('PlaylistItemId', instance.playlistItemId); + return val; +} + +CastReceiverApplication _$CastReceiverApplicationFromJson( + Map json) => + CastReceiverApplication( + id: json['Id'] as String?, + name: json['Name'] as String?, + ); + +Map _$CastReceiverApplicationToJson( + CastReceiverApplication instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Id', instance.id); + writeNotNull('Name', instance.name); + return val; +} + +ChannelFeatures _$ChannelFeaturesFromJson(Map json) => + ChannelFeatures( + name: json['Name'] as String?, + id: json['Id'] as String?, + canSearch: json['CanSearch'] as bool?, + mediaTypes: channelMediaTypeListFromJson(json['MediaTypes'] as List?), + contentTypes: + channelMediaContentTypeListFromJson(json['ContentTypes'] as List?), + maxPageSize: (json['MaxPageSize'] as num?)?.toInt(), + autoRefreshLevels: (json['AutoRefreshLevels'] as num?)?.toInt(), + defaultSortFields: + channelItemSortFieldListFromJson(json['DefaultSortFields'] as List?), + supportsSortOrderToggle: json['SupportsSortOrderToggle'] as bool?, + supportsLatestMedia: json['SupportsLatestMedia'] as bool?, + canFilter: json['CanFilter'] as bool?, + supportsContentDownloading: json['SupportsContentDownloading'] as bool?, + ); + +Map _$ChannelFeaturesToJson(ChannelFeatures instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('Id', instance.id); + writeNotNull('CanSearch', instance.canSearch); + val['MediaTypes'] = channelMediaTypeListToJson(instance.mediaTypes); + val['ContentTypes'] = + channelMediaContentTypeListToJson(instance.contentTypes); + writeNotNull('MaxPageSize', instance.maxPageSize); + writeNotNull('AutoRefreshLevels', instance.autoRefreshLevels); + val['DefaultSortFields'] = + channelItemSortFieldListToJson(instance.defaultSortFields); + writeNotNull('SupportsSortOrderToggle', instance.supportsSortOrderToggle); + writeNotNull('SupportsLatestMedia', instance.supportsLatestMedia); + writeNotNull('CanFilter', instance.canFilter); + writeNotNull( + 'SupportsContentDownloading', instance.supportsContentDownloading); + return val; +} + +ChannelMappingOptionsDto _$ChannelMappingOptionsDtoFromJson( + Map json) => + ChannelMappingOptionsDto( + tunerChannels: (json['TunerChannels'] as List?) + ?.map((e) => + TunerChannelMapping.fromJson(e as Map)) + .toList() ?? + [], + providerChannels: (json['ProviderChannels'] as List?) + ?.map((e) => NameIdPair.fromJson(e as Map)) + .toList() ?? + [], + mappings: (json['Mappings'] as List?) + ?.map((e) => NameValuePair.fromJson(e as Map)) + .toList() ?? + [], + providerName: json['ProviderName'] as String?, + ); + +Map _$ChannelMappingOptionsDtoToJson( + ChannelMappingOptionsDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull( + 'TunerChannels', instance.tunerChannels?.map((e) => e.toJson()).toList()); + writeNotNull('ProviderChannels', + instance.providerChannels?.map((e) => e.toJson()).toList()); + writeNotNull('Mappings', instance.mappings?.map((e) => e.toJson()).toList()); + writeNotNull('ProviderName', instance.providerName); + return val; +} + +ChapterInfo _$ChapterInfoFromJson(Map json) => ChapterInfo( + startPositionTicks: (json['StartPositionTicks'] as num?)?.toInt(), + name: json['Name'] as String?, + imagePath: json['ImagePath'] as String?, + imageDateModified: json['ImageDateModified'] == null + ? null + : DateTime.parse(json['ImageDateModified'] as String), + imageTag: json['ImageTag'] as String?, + ); + +Map _$ChapterInfoToJson(ChapterInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('StartPositionTicks', instance.startPositionTicks); + writeNotNull('Name', instance.name); + writeNotNull('ImagePath', instance.imagePath); + writeNotNull( + 'ImageDateModified', instance.imageDateModified?.toIso8601String()); + writeNotNull('ImageTag', instance.imageTag); + return val; +} + +ClientCapabilities _$ClientCapabilitiesFromJson(Map json) => + ClientCapabilities( + playableMediaTypes: + mediaTypeListFromJson(json['PlayableMediaTypes'] as List?), + supportedCommands: + generalCommandTypeListFromJson(json['SupportedCommands'] as List?), + supportsMediaControl: json['SupportsMediaControl'] as bool?, + supportsPersistentIdentifier: + json['SupportsPersistentIdentifier'] as bool?, + deviceProfile: json['DeviceProfile'] == null + ? null + : DeviceProfile.fromJson( + json['DeviceProfile'] as Map), + appStoreUrl: json['AppStoreUrl'] as String?, + iconUrl: json['IconUrl'] as String?, + supportsContentUploading: + json['SupportsContentUploading'] as bool? ?? false, + supportsSync: json['SupportsSync'] as bool? ?? false, + ); + +Map _$ClientCapabilitiesToJson(ClientCapabilities instance) { + final val = { + 'PlayableMediaTypes': mediaTypeListToJson(instance.playableMediaTypes), + 'SupportedCommands': + generalCommandTypeListToJson(instance.supportedCommands), + }; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('SupportsMediaControl', instance.supportsMediaControl); + writeNotNull( + 'SupportsPersistentIdentifier', instance.supportsPersistentIdentifier); + writeNotNull('DeviceProfile', instance.deviceProfile?.toJson()); + writeNotNull('AppStoreUrl', instance.appStoreUrl); + writeNotNull('IconUrl', instance.iconUrl); + writeNotNull('SupportsContentUploading', instance.supportsContentUploading); + writeNotNull('SupportsSync', instance.supportsSync); + return val; +} + +ClientCapabilitiesDto _$ClientCapabilitiesDtoFromJson( + Map json) => + ClientCapabilitiesDto( + playableMediaTypes: + mediaTypeListFromJson(json['PlayableMediaTypes'] as List?), + supportedCommands: + generalCommandTypeListFromJson(json['SupportedCommands'] as List?), + supportsMediaControl: json['SupportsMediaControl'] as bool?, + supportsPersistentIdentifier: + json['SupportsPersistentIdentifier'] as bool?, + deviceProfile: json['DeviceProfile'] == null + ? null + : DeviceProfile.fromJson( + json['DeviceProfile'] as Map), + appStoreUrl: json['AppStoreUrl'] as String?, + iconUrl: json['IconUrl'] as String?, + supportsContentUploading: + json['SupportsContentUploading'] as bool? ?? false, + supportsSync: json['SupportsSync'] as bool? ?? false, + ); + +Map _$ClientCapabilitiesDtoToJson( + ClientCapabilitiesDto instance) { + final val = { + 'PlayableMediaTypes': mediaTypeListToJson(instance.playableMediaTypes), + 'SupportedCommands': + generalCommandTypeListToJson(instance.supportedCommands), + }; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('SupportsMediaControl', instance.supportsMediaControl); + writeNotNull( + 'SupportsPersistentIdentifier', instance.supportsPersistentIdentifier); + writeNotNull('DeviceProfile', instance.deviceProfile?.toJson()); + writeNotNull('AppStoreUrl', instance.appStoreUrl); + writeNotNull('IconUrl', instance.iconUrl); + writeNotNull('SupportsContentUploading', instance.supportsContentUploading); + writeNotNull('SupportsSync', instance.supportsSync); + return val; +} + +ClientLogDocumentResponseDto _$ClientLogDocumentResponseDtoFromJson( + Map json) => + ClientLogDocumentResponseDto( + fileName: json['FileName'] as String?, + ); + +Map _$ClientLogDocumentResponseDtoToJson( + ClientLogDocumentResponseDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('FileName', instance.fileName); + return val; +} + +CodecProfile _$CodecProfileFromJson(Map json) => CodecProfile( + type: codecTypeNullableFromJson(json['Type']), + conditions: (json['Conditions'] as List?) + ?.map((e) => ProfileCondition.fromJson(e as Map)) + .toList() ?? + [], + applyConditions: (json['ApplyConditions'] as List?) + ?.map((e) => ProfileCondition.fromJson(e as Map)) + .toList() ?? + [], + codec: json['Codec'] as String?, + container: json['Container'] as String?, + ); + +Map _$CodecProfileToJson(CodecProfile instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Type', codecTypeNullableToJson(instance.type)); + writeNotNull( + 'Conditions', instance.conditions?.map((e) => e.toJson()).toList()); + writeNotNull('ApplyConditions', + instance.applyConditions?.map((e) => e.toJson()).toList()); + writeNotNull('Codec', instance.codec); + writeNotNull('Container', instance.container); + return val; +} + +CollectionCreationResult _$CollectionCreationResultFromJson( + Map json) => + CollectionCreationResult( + id: json['Id'] as String?, + ); + +Map _$CollectionCreationResultToJson( + CollectionCreationResult instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Id', instance.id); + return val; +} + +ConfigImageTypes _$ConfigImageTypesFromJson(Map json) => + ConfigImageTypes( + backdropSizes: (json['BackdropSizes'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + baseUrl: json['BaseUrl'] as String?, + logoSizes: (json['LogoSizes'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + posterSizes: (json['PosterSizes'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + profileSizes: (json['ProfileSizes'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + secureBaseUrl: json['SecureBaseUrl'] as String?, + stillSizes: (json['StillSizes'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + ); + +Map _$ConfigImageTypesToJson(ConfigImageTypes instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('BackdropSizes', instance.backdropSizes); + writeNotNull('BaseUrl', instance.baseUrl); + writeNotNull('LogoSizes', instance.logoSizes); + writeNotNull('PosterSizes', instance.posterSizes); + writeNotNull('ProfileSizes', instance.profileSizes); + writeNotNull('SecureBaseUrl', instance.secureBaseUrl); + writeNotNull('StillSizes', instance.stillSizes); + return val; +} + +ConfigurationPageInfo _$ConfigurationPageInfoFromJson( + Map json) => + ConfigurationPageInfo( + name: json['Name'] as String?, + enableInMainMenu: json['EnableInMainMenu'] as bool?, + menuSection: json['MenuSection'] as String?, + menuIcon: json['MenuIcon'] as String?, + displayName: json['DisplayName'] as String?, + pluginId: json['PluginId'] as String?, + ); + +Map _$ConfigurationPageInfoToJson( + ConfigurationPageInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('EnableInMainMenu', instance.enableInMainMenu); + writeNotNull('MenuSection', instance.menuSection); + writeNotNull('MenuIcon', instance.menuIcon); + writeNotNull('DisplayName', instance.displayName); + writeNotNull('PluginId', instance.pluginId); + return val; +} + +ContainerProfile _$ContainerProfileFromJson(Map json) => + ContainerProfile( + type: dlnaProfileTypeNullableFromJson(json['Type']), + conditions: (json['Conditions'] as List?) + ?.map((e) => ProfileCondition.fromJson(e as Map)) + .toList() ?? + [], + container: json['Container'] as String?, + ); + +Map _$ContainerProfileToJson(ContainerProfile instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Type', dlnaProfileTypeNullableToJson(instance.type)); + writeNotNull( + 'Conditions', instance.conditions?.map((e) => e.toJson()).toList()); + writeNotNull('Container', instance.container); + return val; +} + +CountryInfo _$CountryInfoFromJson(Map json) => CountryInfo( + name: json['Name'] as String?, + displayName: json['DisplayName'] as String?, + twoLetterISORegionName: json['TwoLetterISORegionName'] as String?, + threeLetterISORegionName: json['ThreeLetterISORegionName'] as String?, + ); + +Map _$CountryInfoToJson(CountryInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('DisplayName', instance.displayName); + writeNotNull('TwoLetterISORegionName', instance.twoLetterISORegionName); + writeNotNull('ThreeLetterISORegionName', instance.threeLetterISORegionName); + return val; +} + +CreatePlaylistDto _$CreatePlaylistDtoFromJson(Map json) => + CreatePlaylistDto( + name: json['Name'] as String?, + ids: (json['Ids'] as List?)?.map((e) => e as String).toList() ?? + [], + userId: json['UserId'] as String?, + mediaType: mediaTypeNullableFromJson(json['MediaType']), + users: (json['Users'] as List?) + ?.map((e) => + PlaylistUserPermissions.fromJson(e as Map)) + .toList() ?? + [], + isPublic: json['IsPublic'] as bool?, + ); + +Map _$CreatePlaylistDtoToJson(CreatePlaylistDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('Ids', instance.ids); + writeNotNull('UserId', instance.userId); + writeNotNull('MediaType', mediaTypeNullableToJson(instance.mediaType)); + writeNotNull('Users', instance.users?.map((e) => e.toJson()).toList()); + writeNotNull('IsPublic', instance.isPublic); + return val; +} + +CreateUserByName _$CreateUserByNameFromJson(Map json) => + CreateUserByName( + name: json['Name'] as String, + password: json['Password'] as String?, + ); + +Map _$CreateUserByNameToJson(CreateUserByName instance) { + final val = { + 'Name': instance.name, + }; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Password', instance.password); + return val; +} + +CultureDto _$CultureDtoFromJson(Map json) => CultureDto( + name: json['Name'] as String?, + displayName: json['DisplayName'] as String?, + twoLetterISOLanguageName: json['TwoLetterISOLanguageName'] as String?, + threeLetterISOLanguageName: json['ThreeLetterISOLanguageName'] as String?, + threeLetterISOLanguageNames: + (json['ThreeLetterISOLanguageNames'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + ); + +Map _$CultureDtoToJson(CultureDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('DisplayName', instance.displayName); + writeNotNull('TwoLetterISOLanguageName', instance.twoLetterISOLanguageName); + writeNotNull( + 'ThreeLetterISOLanguageName', instance.threeLetterISOLanguageName); + writeNotNull( + 'ThreeLetterISOLanguageNames', instance.threeLetterISOLanguageNames); + return val; +} + +CustomQueryData _$CustomQueryDataFromJson(Map json) => + CustomQueryData( + customQueryString: json['CustomQueryString'] as String?, + replaceUserId: json['ReplaceUserId'] as bool?, + ); + +Map _$CustomQueryDataToJson(CustomQueryData instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('CustomQueryString', instance.customQueryString); + writeNotNull('ReplaceUserId', instance.replaceUserId); + return val; +} + +DefaultDirectoryBrowserInfoDto _$DefaultDirectoryBrowserInfoDtoFromJson( + Map json) => + DefaultDirectoryBrowserInfoDto( + path: json['Path'] as String?, + ); + +Map _$DefaultDirectoryBrowserInfoDtoToJson( + DefaultDirectoryBrowserInfoDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Path', instance.path); + return val; +} + +DeviceInfo _$DeviceInfoFromJson(Map json) => DeviceInfo( + name: json['Name'] as String?, + customName: json['CustomName'] as String?, + accessToken: json['AccessToken'] as String?, + id: json['Id'] as String?, + lastUserName: json['LastUserName'] as String?, + appName: json['AppName'] as String?, + appVersion: json['AppVersion'] as String?, + lastUserId: json['LastUserId'] as String?, + dateLastActivity: json['DateLastActivity'] == null + ? null + : DateTime.parse(json['DateLastActivity'] as String), + capabilities: json['Capabilities'] == null + ? null + : ClientCapabilities.fromJson( + json['Capabilities'] as Map), + iconUrl: json['IconUrl'] as String?, + ); + +Map _$DeviceInfoToJson(DeviceInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('CustomName', instance.customName); + writeNotNull('AccessToken', instance.accessToken); + writeNotNull('Id', instance.id); + writeNotNull('LastUserName', instance.lastUserName); + writeNotNull('AppName', instance.appName); + writeNotNull('AppVersion', instance.appVersion); + writeNotNull('LastUserId', instance.lastUserId); + writeNotNull( + 'DateLastActivity', instance.dateLastActivity?.toIso8601String()); + writeNotNull('Capabilities', instance.capabilities?.toJson()); + writeNotNull('IconUrl', instance.iconUrl); + return val; +} + +DeviceInfoQueryResult _$DeviceInfoQueryResultFromJson( + Map json) => + DeviceInfoQueryResult( + items: (json['Items'] as List?) + ?.map((e) => DeviceInfo.fromJson(e as Map)) + .toList() ?? + [], + totalRecordCount: (json['TotalRecordCount'] as num?)?.toInt(), + startIndex: (json['StartIndex'] as num?)?.toInt(), + ); + +Map _$DeviceInfoQueryResultToJson( + DeviceInfoQueryResult instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Items', instance.items?.map((e) => e.toJson()).toList()); + writeNotNull('TotalRecordCount', instance.totalRecordCount); + writeNotNull('StartIndex', instance.startIndex); + return val; +} + +DeviceOptions _$DeviceOptionsFromJson(Map json) => + DeviceOptions( + id: (json['Id'] as num?)?.toInt(), + deviceId: json['DeviceId'] as String?, + customName: json['CustomName'] as String?, + ); + +Map _$DeviceOptionsToJson(DeviceOptions instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Id', instance.id); + writeNotNull('DeviceId', instance.deviceId); + writeNotNull('CustomName', instance.customName); + return val; +} + +DeviceOptionsDto _$DeviceOptionsDtoFromJson(Map json) => + DeviceOptionsDto( + id: (json['Id'] as num?)?.toInt(), + deviceId: json['DeviceId'] as String?, + customName: json['CustomName'] as String?, + ); + +Map _$DeviceOptionsDtoToJson(DeviceOptionsDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Id', instance.id); + writeNotNull('DeviceId', instance.deviceId); + writeNotNull('CustomName', instance.customName); + return val; +} + +DeviceProfile _$DeviceProfileFromJson(Map json) => + DeviceProfile( + name: json['Name'] as String?, + id: json['Id'] as String?, + maxStreamingBitrate: (json['MaxStreamingBitrate'] as num?)?.toInt(), + maxStaticBitrate: (json['MaxStaticBitrate'] as num?)?.toInt(), + musicStreamingTranscodingBitrate: + (json['MusicStreamingTranscodingBitrate'] as num?)?.toInt(), + maxStaticMusicBitrate: (json['MaxStaticMusicBitrate'] as num?)?.toInt(), + directPlayProfiles: (json['DirectPlayProfiles'] as List?) + ?.map( + (e) => DirectPlayProfile.fromJson(e as Map)) + .toList() ?? + [], + transcodingProfiles: (json['TranscodingProfiles'] as List?) + ?.map( + (e) => TranscodingProfile.fromJson(e as Map)) + .toList() ?? + [], + containerProfiles: (json['ContainerProfiles'] as List?) + ?.map((e) => ContainerProfile.fromJson(e as Map)) + .toList() ?? + [], + codecProfiles: (json['CodecProfiles'] as List?) + ?.map((e) => CodecProfile.fromJson(e as Map)) + .toList() ?? + [], + subtitleProfiles: (json['SubtitleProfiles'] as List?) + ?.map((e) => SubtitleProfile.fromJson(e as Map)) + .toList() ?? + [], + ); + +Map _$DeviceProfileToJson(DeviceProfile instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('Id', instance.id); + writeNotNull('MaxStreamingBitrate', instance.maxStreamingBitrate); + writeNotNull('MaxStaticBitrate', instance.maxStaticBitrate); + writeNotNull('MusicStreamingTranscodingBitrate', + instance.musicStreamingTranscodingBitrate); + writeNotNull('MaxStaticMusicBitrate', instance.maxStaticMusicBitrate); + writeNotNull('DirectPlayProfiles', + instance.directPlayProfiles?.map((e) => e.toJson()).toList()); + writeNotNull('TranscodingProfiles', + instance.transcodingProfiles?.map((e) => e.toJson()).toList()); + writeNotNull('ContainerProfiles', + instance.containerProfiles?.map((e) => e.toJson()).toList()); + writeNotNull( + 'CodecProfiles', instance.codecProfiles?.map((e) => e.toJson()).toList()); + writeNotNull('SubtitleProfiles', + instance.subtitleProfiles?.map((e) => e.toJson()).toList()); + return val; +} + +DirectPlayProfile _$DirectPlayProfileFromJson(Map json) => + DirectPlayProfile( + container: json['Container'] as String?, + audioCodec: json['AudioCodec'] as String?, + videoCodec: json['VideoCodec'] as String?, + type: dlnaProfileTypeNullableFromJson(json['Type']), + ); + +Map _$DirectPlayProfileToJson(DirectPlayProfile instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Container', instance.container); + writeNotNull('AudioCodec', instance.audioCodec); + writeNotNull('VideoCodec', instance.videoCodec); + writeNotNull('Type', dlnaProfileTypeNullableToJson(instance.type)); + return val; +} + +DisplayPreferencesDto _$DisplayPreferencesDtoFromJson( + Map json) => + DisplayPreferencesDto( + id: json['Id'] as String?, + viewType: json['ViewType'] as String?, + sortBy: json['SortBy'] as String?, + indexBy: json['IndexBy'] as String?, + rememberIndexing: json['RememberIndexing'] as bool?, + primaryImageHeight: (json['PrimaryImageHeight'] as num?)?.toInt(), + primaryImageWidth: (json['PrimaryImageWidth'] as num?)?.toInt(), + customPrefs: json['CustomPrefs'] as Map?, + scrollDirection: scrollDirectionNullableFromJson(json['ScrollDirection']), + showBackdrop: json['ShowBackdrop'] as bool?, + rememberSorting: json['RememberSorting'] as bool?, + sortOrder: sortOrderNullableFromJson(json['SortOrder']), + showSidebar: json['ShowSidebar'] as bool?, + $Client: json['Client'] as String?, + ); + +Map _$DisplayPreferencesDtoToJson( + DisplayPreferencesDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Id', instance.id); + writeNotNull('ViewType', instance.viewType); + writeNotNull('SortBy', instance.sortBy); + writeNotNull('IndexBy', instance.indexBy); + writeNotNull('RememberIndexing', instance.rememberIndexing); + writeNotNull('PrimaryImageHeight', instance.primaryImageHeight); + writeNotNull('PrimaryImageWidth', instance.primaryImageWidth); + writeNotNull('CustomPrefs', instance.customPrefs); + writeNotNull('ScrollDirection', + scrollDirectionNullableToJson(instance.scrollDirection)); + writeNotNull('ShowBackdrop', instance.showBackdrop); + writeNotNull('RememberSorting', instance.rememberSorting); + writeNotNull('SortOrder', sortOrderNullableToJson(instance.sortOrder)); + writeNotNull('ShowSidebar', instance.showSidebar); + writeNotNull('Client', instance.$Client); + return val; +} + +EncodingOptions _$EncodingOptionsFromJson(Map json) => + EncodingOptions( + encodingThreadCount: (json['EncodingThreadCount'] as num?)?.toInt(), + transcodingTempPath: json['TranscodingTempPath'] as String?, + fallbackFontPath: json['FallbackFontPath'] as String?, + enableFallbackFont: json['EnableFallbackFont'] as bool?, + enableAudioVbr: json['EnableAudioVbr'] as bool?, + downMixAudioBoost: (json['DownMixAudioBoost'] as num?)?.toDouble(), + downMixStereoAlgorithm: downMixStereoAlgorithmsNullableFromJson( + json['DownMixStereoAlgorithm']), + maxMuxingQueueSize: (json['MaxMuxingQueueSize'] as num?)?.toInt(), + enableThrottling: json['EnableThrottling'] as bool?, + throttleDelaySeconds: (json['ThrottleDelaySeconds'] as num?)?.toInt(), + enableSegmentDeletion: json['EnableSegmentDeletion'] as bool?, + segmentKeepSeconds: (json['SegmentKeepSeconds'] as num?)?.toInt(), + hardwareAccelerationType: json['HardwareAccelerationType'] as String?, + encoderAppPath: json['EncoderAppPath'] as String?, + encoderAppPathDisplay: json['EncoderAppPathDisplay'] as String?, + vaapiDevice: json['VaapiDevice'] as String?, + enableTonemapping: json['EnableTonemapping'] as bool?, + enableVppTonemapping: json['EnableVppTonemapping'] as bool?, + enableVideoToolboxTonemapping: + json['EnableVideoToolboxTonemapping'] as bool?, + tonemappingAlgorithm: json['TonemappingAlgorithm'] as String?, + tonemappingMode: json['TonemappingMode'] as String?, + tonemappingRange: json['TonemappingRange'] as String?, + tonemappingDesat: (json['TonemappingDesat'] as num?)?.toDouble(), + tonemappingPeak: (json['TonemappingPeak'] as num?)?.toDouble(), + tonemappingParam: (json['TonemappingParam'] as num?)?.toDouble(), + vppTonemappingBrightness: + (json['VppTonemappingBrightness'] as num?)?.toDouble(), + vppTonemappingContrast: + (json['VppTonemappingContrast'] as num?)?.toDouble(), + h264Crf: (json['H264Crf'] as num?)?.toInt(), + h265Crf: (json['H265Crf'] as num?)?.toInt(), + encoderPreset: json['EncoderPreset'] as String?, + deinterlaceDoubleRate: json['DeinterlaceDoubleRate'] as bool?, + deinterlaceMethod: json['DeinterlaceMethod'] as String?, + enableDecodingColorDepth10Hevc: + json['EnableDecodingColorDepth10Hevc'] as bool?, + enableDecodingColorDepth10Vp9: + json['EnableDecodingColorDepth10Vp9'] as bool?, + enableEnhancedNvdecDecoder: json['EnableEnhancedNvdecDecoder'] as bool?, + preferSystemNativeHwDecoder: json['PreferSystemNativeHwDecoder'] as bool?, + enableIntelLowPowerH264HwEncoder: + json['EnableIntelLowPowerH264HwEncoder'] as bool?, + enableIntelLowPowerHevcHwEncoder: + json['EnableIntelLowPowerHevcHwEncoder'] as bool?, + enableHardwareEncoding: json['EnableHardwareEncoding'] as bool?, + allowHevcEncoding: json['AllowHevcEncoding'] as bool?, + allowAv1Encoding: json['AllowAv1Encoding'] as bool?, + enableSubtitleExtraction: json['EnableSubtitleExtraction'] as bool?, + hardwareDecodingCodecs: (json['HardwareDecodingCodecs'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + allowOnDemandMetadataBasedKeyframeExtractionForExtensions: + (json['AllowOnDemandMetadataBasedKeyframeExtractionForExtensions'] + as List?) + ?.map((e) => e as String) + .toList() ?? + [], + ); + +Map _$EncodingOptionsToJson(EncodingOptions instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('EncodingThreadCount', instance.encodingThreadCount); + writeNotNull('TranscodingTempPath', instance.transcodingTempPath); + writeNotNull('FallbackFontPath', instance.fallbackFontPath); + writeNotNull('EnableFallbackFont', instance.enableFallbackFont); + writeNotNull('EnableAudioVbr', instance.enableAudioVbr); + writeNotNull('DownMixAudioBoost', instance.downMixAudioBoost); + writeNotNull('DownMixStereoAlgorithm', + downMixStereoAlgorithmsNullableToJson(instance.downMixStereoAlgorithm)); + writeNotNull('MaxMuxingQueueSize', instance.maxMuxingQueueSize); + writeNotNull('EnableThrottling', instance.enableThrottling); + writeNotNull('ThrottleDelaySeconds', instance.throttleDelaySeconds); + writeNotNull('EnableSegmentDeletion', instance.enableSegmentDeletion); + writeNotNull('SegmentKeepSeconds', instance.segmentKeepSeconds); + writeNotNull('HardwareAccelerationType', instance.hardwareAccelerationType); + writeNotNull('EncoderAppPath', instance.encoderAppPath); + writeNotNull('EncoderAppPathDisplay', instance.encoderAppPathDisplay); + writeNotNull('VaapiDevice', instance.vaapiDevice); + writeNotNull('EnableTonemapping', instance.enableTonemapping); + writeNotNull('EnableVppTonemapping', instance.enableVppTonemapping); + writeNotNull( + 'EnableVideoToolboxTonemapping', instance.enableVideoToolboxTonemapping); + writeNotNull('TonemappingAlgorithm', instance.tonemappingAlgorithm); + writeNotNull('TonemappingMode', instance.tonemappingMode); + writeNotNull('TonemappingRange', instance.tonemappingRange); + writeNotNull('TonemappingDesat', instance.tonemappingDesat); + writeNotNull('TonemappingPeak', instance.tonemappingPeak); + writeNotNull('TonemappingParam', instance.tonemappingParam); + writeNotNull('VppTonemappingBrightness', instance.vppTonemappingBrightness); + writeNotNull('VppTonemappingContrast', instance.vppTonemappingContrast); + writeNotNull('H264Crf', instance.h264Crf); + writeNotNull('H265Crf', instance.h265Crf); + writeNotNull('EncoderPreset', instance.encoderPreset); + writeNotNull('DeinterlaceDoubleRate', instance.deinterlaceDoubleRate); + writeNotNull('DeinterlaceMethod', instance.deinterlaceMethod); + writeNotNull('EnableDecodingColorDepth10Hevc', + instance.enableDecodingColorDepth10Hevc); + writeNotNull( + 'EnableDecodingColorDepth10Vp9', instance.enableDecodingColorDepth10Vp9); + writeNotNull( + 'EnableEnhancedNvdecDecoder', instance.enableEnhancedNvdecDecoder); + writeNotNull( + 'PreferSystemNativeHwDecoder', instance.preferSystemNativeHwDecoder); + writeNotNull('EnableIntelLowPowerH264HwEncoder', + instance.enableIntelLowPowerH264HwEncoder); + writeNotNull('EnableIntelLowPowerHevcHwEncoder', + instance.enableIntelLowPowerHevcHwEncoder); + writeNotNull('EnableHardwareEncoding', instance.enableHardwareEncoding); + writeNotNull('AllowHevcEncoding', instance.allowHevcEncoding); + writeNotNull('AllowAv1Encoding', instance.allowAv1Encoding); + writeNotNull('EnableSubtitleExtraction', instance.enableSubtitleExtraction); + writeNotNull('HardwareDecodingCodecs', instance.hardwareDecodingCodecs); + writeNotNull('AllowOnDemandMetadataBasedKeyframeExtractionForExtensions', + instance.allowOnDemandMetadataBasedKeyframeExtractionForExtensions); + return val; +} + +EndPointInfo _$EndPointInfoFromJson(Map json) => EndPointInfo( + isLocal: json['IsLocal'] as bool?, + isInNetwork: json['IsInNetwork'] as bool?, + ); + +Map _$EndPointInfoToJson(EndPointInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('IsLocal', instance.isLocal); + writeNotNull('IsInNetwork', instance.isInNetwork); + return val; +} + +EpisodeVisualization _$EpisodeVisualizationFromJson( + Map json) => + EpisodeVisualization( + id: json['Id'] as String?, + name: json['Name'] as String?, + ); + +Map _$EpisodeVisualizationToJson( + EpisodeVisualization instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Id', instance.id); + writeNotNull('Name', instance.name); + return val; +} + +ExternalIdInfo _$ExternalIdInfoFromJson(Map json) => + ExternalIdInfo( + name: json['Name'] as String?, + key: json['Key'] as String?, + type: externalIdMediaTypeNullableFromJson(json['Type']), + urlFormatString: json['UrlFormatString'] as String?, + ); + +Map _$ExternalIdInfoToJson(ExternalIdInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('Key', instance.key); + writeNotNull('Type', externalIdMediaTypeNullableToJson(instance.type)); + writeNotNull('UrlFormatString', instance.urlFormatString); + return val; +} + +ExternalUrl _$ExternalUrlFromJson(Map json) => ExternalUrl( + name: json['Name'] as String?, + url: json['Url'] as String?, + ); + +Map _$ExternalUrlToJson(ExternalUrl instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('Url', instance.url); + return val; +} + +FileSystemEntryInfo _$FileSystemEntryInfoFromJson(Map json) => + FileSystemEntryInfo( + name: json['Name'] as String?, + path: json['Path'] as String?, + type: fileSystemEntryTypeNullableFromJson(json['Type']), + ); + +Map _$FileSystemEntryInfoToJson(FileSystemEntryInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('Path', instance.path); + writeNotNull('Type', fileSystemEntryTypeNullableToJson(instance.type)); + return val; +} + +FontFile _$FontFileFromJson(Map json) => FontFile( + name: json['Name'] as String?, + size: (json['Size'] as num?)?.toInt(), + dateCreated: json['DateCreated'] == null + ? null + : DateTime.parse(json['DateCreated'] as String), + dateModified: json['DateModified'] == null + ? null + : DateTime.parse(json['DateModified'] as String), + ); + +Map _$FontFileToJson(FontFile instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('Size', instance.size); + writeNotNull('DateCreated', instance.dateCreated?.toIso8601String()); + writeNotNull('DateModified', instance.dateModified?.toIso8601String()); + return val; +} + +ForceKeepAliveMessage _$ForceKeepAliveMessageFromJson( + Map json) => + ForceKeepAliveMessage( + data: (json['Data'] as num?)?.toInt(), + messageId: json['MessageId'] as String?, + messageType: + ForceKeepAliveMessage.sessionMessageTypeMessageTypeNullableFromJson( + json['MessageType']), + ); + +Map _$ForceKeepAliveMessageToJson( + ForceKeepAliveMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Data', instance.data); + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +ForgotPasswordDto _$ForgotPasswordDtoFromJson(Map json) => + ForgotPasswordDto( + enteredUsername: json['EnteredUsername'] as String, + ); + +Map _$ForgotPasswordDtoToJson(ForgotPasswordDto instance) => + { + 'EnteredUsername': instance.enteredUsername, + }; + +ForgotPasswordPinDto _$ForgotPasswordPinDtoFromJson( + Map json) => + ForgotPasswordPinDto( + pin: json['Pin'] as String, + ); + +Map _$ForgotPasswordPinDtoToJson( + ForgotPasswordPinDto instance) => + { + 'Pin': instance.pin, + }; + +ForgotPasswordResult _$ForgotPasswordResultFromJson( + Map json) => + ForgotPasswordResult( + action: forgotPasswordActionNullableFromJson(json['Action']), + pinFile: json['PinFile'] as String?, + pinExpirationDate: json['PinExpirationDate'] == null + ? null + : DateTime.parse(json['PinExpirationDate'] as String), + ); + +Map _$ForgotPasswordResultToJson( + ForgotPasswordResult instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Action', forgotPasswordActionNullableToJson(instance.action)); + writeNotNull('PinFile', instance.pinFile); + writeNotNull( + 'PinExpirationDate', instance.pinExpirationDate?.toIso8601String()); + return val; +} + +GeneralCommand _$GeneralCommandFromJson(Map json) => + GeneralCommand( + name: generalCommandTypeNullableFromJson(json['Name']), + controllingUserId: json['ControllingUserId'] as String?, + arguments: json['Arguments'] as Map?, + ); + +Map _$GeneralCommandToJson(GeneralCommand instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', generalCommandTypeNullableToJson(instance.name)); + writeNotNull('ControllingUserId', instance.controllingUserId); + writeNotNull('Arguments', instance.arguments); + return val; +} + +GeneralCommandMessage _$GeneralCommandMessageFromJson( + Map json) => + GeneralCommandMessage( + data: json['Data'] == null + ? null + : GeneralCommand.fromJson(json['Data'] as Map), + messageId: json['MessageId'] as String?, + messageType: + GeneralCommandMessage.sessionMessageTypeMessageTypeNullableFromJson( + json['MessageType']), + ); + +Map _$GeneralCommandMessageToJson( + GeneralCommandMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Data', instance.data?.toJson()); + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +GetProgramsDto _$GetProgramsDtoFromJson(Map json) => + GetProgramsDto( + channelIds: (json['ChannelIds'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + userId: json['UserId'] as String?, + minStartDate: json['MinStartDate'] == null + ? null + : DateTime.parse(json['MinStartDate'] as String), + hasAired: json['HasAired'] as bool?, + isAiring: json['IsAiring'] as bool?, + maxStartDate: json['MaxStartDate'] == null + ? null + : DateTime.parse(json['MaxStartDate'] as String), + minEndDate: json['MinEndDate'] == null + ? null + : DateTime.parse(json['MinEndDate'] as String), + maxEndDate: json['MaxEndDate'] == null + ? null + : DateTime.parse(json['MaxEndDate'] as String), + isMovie: json['IsMovie'] as bool?, + isSeries: json['IsSeries'] as bool?, + isNews: json['IsNews'] as bool?, + isKids: json['IsKids'] as bool?, + isSports: json['IsSports'] as bool?, + startIndex: (json['StartIndex'] as num?)?.toInt(), + limit: (json['Limit'] as num?)?.toInt(), + sortBy: itemSortByListFromJson(json['SortBy'] as List?), + sortOrder: sortOrderListFromJson(json['SortOrder'] as List?), + genres: (json['Genres'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + genreIds: (json['GenreIds'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + enableImages: json['EnableImages'] as bool?, + enableTotalRecordCount: json['EnableTotalRecordCount'] as bool?, + imageTypeLimit: (json['ImageTypeLimit'] as num?)?.toInt(), + enableImageTypes: + imageTypeListFromJson(json['EnableImageTypes'] as List?), + enableUserData: json['EnableUserData'] as bool?, + seriesTimerId: json['SeriesTimerId'] as String?, + librarySeriesId: json['LibrarySeriesId'] as String?, + fields: itemFieldsListFromJson(json['Fields'] as List?), + ); + +Map _$GetProgramsDtoToJson(GetProgramsDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('ChannelIds', instance.channelIds); + writeNotNull('UserId', instance.userId); + writeNotNull('MinStartDate', instance.minStartDate?.toIso8601String()); + writeNotNull('HasAired', instance.hasAired); + writeNotNull('IsAiring', instance.isAiring); + writeNotNull('MaxStartDate', instance.maxStartDate?.toIso8601String()); + writeNotNull('MinEndDate', instance.minEndDate?.toIso8601String()); + writeNotNull('MaxEndDate', instance.maxEndDate?.toIso8601String()); + writeNotNull('IsMovie', instance.isMovie); + writeNotNull('IsSeries', instance.isSeries); + writeNotNull('IsNews', instance.isNews); + writeNotNull('IsKids', instance.isKids); + writeNotNull('IsSports', instance.isSports); + writeNotNull('StartIndex', instance.startIndex); + writeNotNull('Limit', instance.limit); + val['SortBy'] = itemSortByListToJson(instance.sortBy); + val['SortOrder'] = sortOrderListToJson(instance.sortOrder); + writeNotNull('Genres', instance.genres); + writeNotNull('GenreIds', instance.genreIds); + writeNotNull('EnableImages', instance.enableImages); + writeNotNull('EnableTotalRecordCount', instance.enableTotalRecordCount); + writeNotNull('ImageTypeLimit', instance.imageTypeLimit); + val['EnableImageTypes'] = imageTypeListToJson(instance.enableImageTypes); + writeNotNull('EnableUserData', instance.enableUserData); + writeNotNull('SeriesTimerId', instance.seriesTimerId); + writeNotNull('LibrarySeriesId', instance.librarySeriesId); + val['Fields'] = itemFieldsListToJson(instance.fields); + return val; +} + +GroupInfoDto _$GroupInfoDtoFromJson(Map json) => GroupInfoDto( + groupId: json['GroupId'] as String?, + groupName: json['GroupName'] as String?, + state: groupStateTypeNullableFromJson(json['State']), + participants: (json['Participants'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + lastUpdatedAt: json['LastUpdatedAt'] == null + ? null + : DateTime.parse(json['LastUpdatedAt'] as String), + ); + +Map _$GroupInfoDtoToJson(GroupInfoDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('GroupId', instance.groupId); + writeNotNull('GroupName', instance.groupName); + writeNotNull('State', groupStateTypeNullableToJson(instance.state)); + writeNotNull('Participants', instance.participants); + writeNotNull('LastUpdatedAt', instance.lastUpdatedAt?.toIso8601String()); + return val; +} + +GroupInfoDtoGroupUpdate _$GroupInfoDtoGroupUpdateFromJson( + Map json) => + GroupInfoDtoGroupUpdate( + groupId: json['GroupId'] as String?, + type: groupUpdateTypeNullableFromJson(json['Type']), + data: json['Data'] == null + ? null + : GroupInfoDto.fromJson(json['Data'] as Map), + ); + +Map _$GroupInfoDtoGroupUpdateToJson( + GroupInfoDtoGroupUpdate instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('GroupId', instance.groupId); + writeNotNull('Type', groupUpdateTypeNullableToJson(instance.type)); + writeNotNull('Data', instance.data?.toJson()); + return val; +} + +GroupStateUpdate _$GroupStateUpdateFromJson(Map json) => + GroupStateUpdate( + state: groupStateTypeNullableFromJson(json['State']), + reason: playbackRequestTypeNullableFromJson(json['Reason']), + ); + +Map _$GroupStateUpdateToJson(GroupStateUpdate instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('State', groupStateTypeNullableToJson(instance.state)); + writeNotNull('Reason', playbackRequestTypeNullableToJson(instance.reason)); + return val; +} + +GroupStateUpdateGroupUpdate _$GroupStateUpdateGroupUpdateFromJson( + Map json) => + GroupStateUpdateGroupUpdate( + groupId: json['GroupId'] as String?, + type: groupUpdateTypeNullableFromJson(json['Type']), + data: json['Data'] == null + ? null + : GroupStateUpdate.fromJson(json['Data'] as Map), + ); + +Map _$GroupStateUpdateGroupUpdateToJson( + GroupStateUpdateGroupUpdate instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('GroupId', instance.groupId); + writeNotNull('Type', groupUpdateTypeNullableToJson(instance.type)); + writeNotNull('Data', instance.data?.toJson()); + return val; +} + +GroupUpdate _$GroupUpdateFromJson(Map json) => GroupUpdate( + groupId: json['GroupId'] as String?, + type: groupUpdateTypeNullableFromJson(json['Type']), + ); + +Map _$GroupUpdateToJson(GroupUpdate instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('GroupId', instance.groupId); + writeNotNull('Type', groupUpdateTypeNullableToJson(instance.type)); + return val; +} + +GuideInfo _$GuideInfoFromJson(Map json) => GuideInfo( + startDate: json['StartDate'] == null + ? null + : DateTime.parse(json['StartDate'] as String), + endDate: json['EndDate'] == null + ? null + : DateTime.parse(json['EndDate'] as String), + ); + +Map _$GuideInfoToJson(GuideInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('StartDate', instance.startDate?.toIso8601String()); + writeNotNull('EndDate', instance.endDate?.toIso8601String()); + return val; +} + +IgnoreWaitRequestDto _$IgnoreWaitRequestDtoFromJson( + Map json) => + IgnoreWaitRequestDto( + ignoreWait: json['IgnoreWait'] as bool?, + ); + +Map _$IgnoreWaitRequestDtoToJson( + IgnoreWaitRequestDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('IgnoreWait', instance.ignoreWait); + return val; +} + +ImageInfo _$ImageInfoFromJson(Map json) => ImageInfo( + imageType: imageTypeNullableFromJson(json['ImageType']), + imageIndex: (json['ImageIndex'] as num?)?.toInt(), + imageTag: json['ImageTag'] as String?, + path: json['Path'] as String?, + blurHash: json['BlurHash'] as String?, + height: (json['Height'] as num?)?.toInt(), + width: (json['Width'] as num?)?.toInt(), + size: (json['Size'] as num?)?.toInt(), + ); + +Map _$ImageInfoToJson(ImageInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('ImageType', imageTypeNullableToJson(instance.imageType)); + writeNotNull('ImageIndex', instance.imageIndex); + writeNotNull('ImageTag', instance.imageTag); + writeNotNull('Path', instance.path); + writeNotNull('BlurHash', instance.blurHash); + writeNotNull('Height', instance.height); + writeNotNull('Width', instance.width); + writeNotNull('Size', instance.size); + return val; +} + +ImageOption _$ImageOptionFromJson(Map json) => ImageOption( + type: imageTypeNullableFromJson(json['Type']), + limit: (json['Limit'] as num?)?.toInt(), + minWidth: (json['MinWidth'] as num?)?.toInt(), + ); + +Map _$ImageOptionToJson(ImageOption instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Type', imageTypeNullableToJson(instance.type)); + writeNotNull('Limit', instance.limit); + writeNotNull('MinWidth', instance.minWidth); + return val; +} + +ImageProviderInfo _$ImageProviderInfoFromJson(Map json) => + ImageProviderInfo( + name: json['Name'] as String?, + supportedImages: imageTypeListFromJson(json['SupportedImages'] as List?), + ); + +Map _$ImageProviderInfoToJson(ImageProviderInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + val['SupportedImages'] = imageTypeListToJson(instance.supportedImages); + return val; +} + +InboundKeepAliveMessage _$InboundKeepAliveMessageFromJson( + Map json) => + InboundKeepAliveMessage( + messageType: + InboundKeepAliveMessage.sessionMessageTypeMessageTypeNullableFromJson( + json['MessageType']), + ); + +Map _$InboundKeepAliveMessageToJson( + InboundKeepAliveMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +InboundWebSocketMessage _$InboundWebSocketMessageFromJson( + Map json) => + InboundWebSocketMessage(); + +Map _$InboundWebSocketMessageToJson( + InboundWebSocketMessage instance) => + {}; + +InstallationInfo _$InstallationInfoFromJson(Map json) => + InstallationInfo( + guid: json['Guid'] as String?, + name: json['Name'] as String?, + version: json['Version'] as String?, + changelog: json['Changelog'] as String?, + sourceUrl: json['SourceUrl'] as String?, + checksum: json['Checksum'] as String?, + packageInfo: json['PackageInfo'] == null + ? null + : PackageInfo.fromJson(json['PackageInfo'] as Map), + ); + +Map _$InstallationInfoToJson(InstallationInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Guid', instance.guid); + writeNotNull('Name', instance.name); + writeNotNull('Version', instance.version); + writeNotNull('Changelog', instance.changelog); + writeNotNull('SourceUrl', instance.sourceUrl); + writeNotNull('Checksum', instance.checksum); + writeNotNull('PackageInfo', instance.packageInfo?.toJson()); + return val; +} + +Intro _$IntroFromJson(Map json) => Intro( + episodeId: json['EpisodeId'] as String?, + valid: json['Valid'] as bool?, + introStart: (json['IntroStart'] as num?)?.toDouble(), + introEnd: (json['IntroEnd'] as num?)?.toDouble(), + showSkipPromptAt: (json['ShowSkipPromptAt'] as num?)?.toDouble(), + hideSkipPromptAt: (json['HideSkipPromptAt'] as num?)?.toDouble(), + ); + +Map _$IntroToJson(Intro instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('EpisodeId', instance.episodeId); + writeNotNull('Valid', instance.valid); + writeNotNull('IntroStart', instance.introStart); + writeNotNull('IntroEnd', instance.introEnd); + writeNotNull('ShowSkipPromptAt', instance.showSkipPromptAt); + writeNotNull('HideSkipPromptAt', instance.hideSkipPromptAt); + return val; +} + +IntroWithMetadata _$IntroWithMetadataFromJson(Map json) => + IntroWithMetadata( + episodeId: json['EpisodeId'] as String?, + valid: json['Valid'] as bool?, + introStart: (json['IntroStart'] as num?)?.toDouble(), + introEnd: (json['IntroEnd'] as num?)?.toDouble(), + showSkipPromptAt: (json['ShowSkipPromptAt'] as num?)?.toDouble(), + hideSkipPromptAt: (json['HideSkipPromptAt'] as num?)?.toDouble(), + series: json['Series'] as String?, + season: (json['Season'] as num?)?.toInt(), + title: json['Title'] as String?, + ); + +Map _$IntroWithMetadataToJson(IntroWithMetadata instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('EpisodeId', instance.episodeId); + writeNotNull('Valid', instance.valid); + writeNotNull('IntroStart', instance.introStart); + writeNotNull('IntroEnd', instance.introEnd); + writeNotNull('ShowSkipPromptAt', instance.showSkipPromptAt); + writeNotNull('HideSkipPromptAt', instance.hideSkipPromptAt); + writeNotNull('Series', instance.series); + writeNotNull('Season', instance.season); + writeNotNull('Title', instance.title); + return val; +} + +IPlugin _$IPluginFromJson(Map json) => IPlugin( + name: json['Name'] as String?, + description: json['Description'] as String?, + id: json['Id'] as String?, + version: json['Version'] as String?, + assemblyFilePath: json['AssemblyFilePath'] as String?, + canUninstall: json['CanUninstall'] as bool?, + dataFolderPath: json['DataFolderPath'] as String?, + ); + +Map _$IPluginToJson(IPlugin instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('Description', instance.description); + writeNotNull('Id', instance.id); + writeNotNull('Version', instance.version); + writeNotNull('AssemblyFilePath', instance.assemblyFilePath); + writeNotNull('CanUninstall', instance.canUninstall); + writeNotNull('DataFolderPath', instance.dataFolderPath); + return val; +} + +ItemCounts _$ItemCountsFromJson(Map json) => ItemCounts( + movieCount: (json['MovieCount'] as num?)?.toInt(), + seriesCount: (json['SeriesCount'] as num?)?.toInt(), + episodeCount: (json['EpisodeCount'] as num?)?.toInt(), + artistCount: (json['ArtistCount'] as num?)?.toInt(), + programCount: (json['ProgramCount'] as num?)?.toInt(), + trailerCount: (json['TrailerCount'] as num?)?.toInt(), + songCount: (json['SongCount'] as num?)?.toInt(), + albumCount: (json['AlbumCount'] as num?)?.toInt(), + musicVideoCount: (json['MusicVideoCount'] as num?)?.toInt(), + boxSetCount: (json['BoxSetCount'] as num?)?.toInt(), + bookCount: (json['BookCount'] as num?)?.toInt(), + itemCount: (json['ItemCount'] as num?)?.toInt(), + ); + +Map _$ItemCountsToJson(ItemCounts instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('MovieCount', instance.movieCount); + writeNotNull('SeriesCount', instance.seriesCount); + writeNotNull('EpisodeCount', instance.episodeCount); + writeNotNull('ArtistCount', instance.artistCount); + writeNotNull('ProgramCount', instance.programCount); + writeNotNull('TrailerCount', instance.trailerCount); + writeNotNull('SongCount', instance.songCount); + writeNotNull('AlbumCount', instance.albumCount); + writeNotNull('MusicVideoCount', instance.musicVideoCount); + writeNotNull('BoxSetCount', instance.boxSetCount); + writeNotNull('BookCount', instance.bookCount); + writeNotNull('ItemCount', instance.itemCount); + return val; +} + +Items _$ItemsFromJson(Map json) => Items( + movies: (json['movies'] as num?)?.toInt(), + episodes: (json['episodes'] as num?)?.toInt(), + ); + +Map _$ItemsToJson(Items instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('movies', instance.movies); + writeNotNull('episodes', instance.episodes); + return val; +} + +JoinGroupRequestDto _$JoinGroupRequestDtoFromJson(Map json) => + JoinGroupRequestDto( + groupId: json['GroupId'] as String?, + ); + +Map _$JoinGroupRequestDtoToJson(JoinGroupRequestDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('GroupId', instance.groupId); + return val; +} + +LibraryChangedMessage _$LibraryChangedMessageFromJson( + Map json) => + LibraryChangedMessage( + data: json['Data'] == null + ? null + : LibraryUpdateInfo.fromJson(json['Data'] as Map), + messageId: json['MessageId'] as String?, + messageType: + LibraryChangedMessage.sessionMessageTypeMessageTypeNullableFromJson( + json['MessageType']), + ); + +Map _$LibraryChangedMessageToJson( + LibraryChangedMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Data', instance.data?.toJson()); + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +LibraryOptionInfoDto _$LibraryOptionInfoDtoFromJson( + Map json) => + LibraryOptionInfoDto( + name: json['Name'] as String?, + defaultEnabled: json['DefaultEnabled'] as bool?, + ); + +Map _$LibraryOptionInfoDtoToJson( + LibraryOptionInfoDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('DefaultEnabled', instance.defaultEnabled); + return val; +} + +LibraryOptions _$LibraryOptionsFromJson(Map json) => + LibraryOptions( + enabled: json['Enabled'] as bool?, + enablePhotos: json['EnablePhotos'] as bool?, + enableRealtimeMonitor: json['EnableRealtimeMonitor'] as bool?, + enableLUFSScan: json['EnableLUFSScan'] as bool?, + enableChapterImageExtraction: + json['EnableChapterImageExtraction'] as bool?, + extractChapterImagesDuringLibraryScan: + json['ExtractChapterImagesDuringLibraryScan'] as bool?, + enableTrickplayImageExtraction: + json['EnableTrickplayImageExtraction'] as bool?, + extractTrickplayImagesDuringLibraryScan: + json['ExtractTrickplayImagesDuringLibraryScan'] as bool?, + pathInfos: (json['PathInfos'] as List?) + ?.map((e) => MediaPathInfo.fromJson(e as Map)) + .toList() ?? + [], + saveLocalMetadata: json['SaveLocalMetadata'] as bool?, + enableInternetProviders: json['EnableInternetProviders'] as bool?, + enableAutomaticSeriesGrouping: + json['EnableAutomaticSeriesGrouping'] as bool?, + enableEmbeddedTitles: json['EnableEmbeddedTitles'] as bool?, + enableEmbeddedExtrasTitles: json['EnableEmbeddedExtrasTitles'] as bool?, + enableEmbeddedEpisodeInfos: json['EnableEmbeddedEpisodeInfos'] as bool?, + automaticRefreshIntervalDays: + (json['AutomaticRefreshIntervalDays'] as num?)?.toInt(), + preferredMetadataLanguage: json['PreferredMetadataLanguage'] as String?, + metadataCountryCode: json['MetadataCountryCode'] as String?, + seasonZeroDisplayName: json['SeasonZeroDisplayName'] as String?, + metadataSavers: (json['MetadataSavers'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + disabledLocalMetadataReaders: + (json['DisabledLocalMetadataReaders'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + localMetadataReaderOrder: + (json['LocalMetadataReaderOrder'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + disabledSubtitleFetchers: + (json['DisabledSubtitleFetchers'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + subtitleFetcherOrder: (json['SubtitleFetcherOrder'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + skipSubtitlesIfEmbeddedSubtitlesPresent: + json['SkipSubtitlesIfEmbeddedSubtitlesPresent'] as bool?, + skipSubtitlesIfAudioTrackMatches: + json['SkipSubtitlesIfAudioTrackMatches'] as bool?, + subtitleDownloadLanguages: + (json['SubtitleDownloadLanguages'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + requirePerfectSubtitleMatch: json['RequirePerfectSubtitleMatch'] as bool?, + saveSubtitlesWithMedia: json['SaveSubtitlesWithMedia'] as bool?, + saveLyricsWithMedia: json['SaveLyricsWithMedia'] as bool? ?? false, + automaticallyAddToCollection: + json['AutomaticallyAddToCollection'] as bool?, + allowEmbeddedSubtitles: embeddedSubtitleOptionsNullableFromJson( + json['AllowEmbeddedSubtitles']), + typeOptions: (json['TypeOptions'] as List?) + ?.map((e) => TypeOptions.fromJson(e as Map)) + .toList() ?? + [], + ); + +Map _$LibraryOptionsToJson(LibraryOptions instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Enabled', instance.enabled); + writeNotNull('EnablePhotos', instance.enablePhotos); + writeNotNull('EnableRealtimeMonitor', instance.enableRealtimeMonitor); + writeNotNull('EnableLUFSScan', instance.enableLUFSScan); + writeNotNull( + 'EnableChapterImageExtraction', instance.enableChapterImageExtraction); + writeNotNull('ExtractChapterImagesDuringLibraryScan', + instance.extractChapterImagesDuringLibraryScan); + writeNotNull('EnableTrickplayImageExtraction', + instance.enableTrickplayImageExtraction); + writeNotNull('ExtractTrickplayImagesDuringLibraryScan', + instance.extractTrickplayImagesDuringLibraryScan); + writeNotNull( + 'PathInfos', instance.pathInfos?.map((e) => e.toJson()).toList()); + writeNotNull('SaveLocalMetadata', instance.saveLocalMetadata); + writeNotNull('EnableInternetProviders', instance.enableInternetProviders); + writeNotNull( + 'EnableAutomaticSeriesGrouping', instance.enableAutomaticSeriesGrouping); + writeNotNull('EnableEmbeddedTitles', instance.enableEmbeddedTitles); + writeNotNull( + 'EnableEmbeddedExtrasTitles', instance.enableEmbeddedExtrasTitles); + writeNotNull( + 'EnableEmbeddedEpisodeInfos', instance.enableEmbeddedEpisodeInfos); + writeNotNull( + 'AutomaticRefreshIntervalDays', instance.automaticRefreshIntervalDays); + writeNotNull('PreferredMetadataLanguage', instance.preferredMetadataLanguage); + writeNotNull('MetadataCountryCode', instance.metadataCountryCode); + writeNotNull('SeasonZeroDisplayName', instance.seasonZeroDisplayName); + writeNotNull('MetadataSavers', instance.metadataSavers); + writeNotNull( + 'DisabledLocalMetadataReaders', instance.disabledLocalMetadataReaders); + writeNotNull('LocalMetadataReaderOrder', instance.localMetadataReaderOrder); + writeNotNull('DisabledSubtitleFetchers', instance.disabledSubtitleFetchers); + writeNotNull('SubtitleFetcherOrder', instance.subtitleFetcherOrder); + writeNotNull('SkipSubtitlesIfEmbeddedSubtitlesPresent', + instance.skipSubtitlesIfEmbeddedSubtitlesPresent); + writeNotNull('SkipSubtitlesIfAudioTrackMatches', + instance.skipSubtitlesIfAudioTrackMatches); + writeNotNull('SubtitleDownloadLanguages', instance.subtitleDownloadLanguages); + writeNotNull( + 'RequirePerfectSubtitleMatch', instance.requirePerfectSubtitleMatch); + writeNotNull('SaveSubtitlesWithMedia', instance.saveSubtitlesWithMedia); + writeNotNull('SaveLyricsWithMedia', instance.saveLyricsWithMedia); + writeNotNull( + 'AutomaticallyAddToCollection', instance.automaticallyAddToCollection); + writeNotNull('AllowEmbeddedSubtitles', + embeddedSubtitleOptionsNullableToJson(instance.allowEmbeddedSubtitles)); + writeNotNull( + 'TypeOptions', instance.typeOptions?.map((e) => e.toJson()).toList()); + return val; +} + +LibraryOptionsResultDto _$LibraryOptionsResultDtoFromJson( + Map json) => + LibraryOptionsResultDto( + metadataSavers: (json['MetadataSavers'] as List?) + ?.map((e) => + LibraryOptionInfoDto.fromJson(e as Map)) + .toList() ?? + [], + metadataReaders: (json['MetadataReaders'] as List?) + ?.map((e) => + LibraryOptionInfoDto.fromJson(e as Map)) + .toList() ?? + [], + subtitleFetchers: (json['SubtitleFetchers'] as List?) + ?.map((e) => + LibraryOptionInfoDto.fromJson(e as Map)) + .toList() ?? + [], + typeOptions: (json['TypeOptions'] as List?) + ?.map((e) => + LibraryTypeOptionsDto.fromJson(e as Map)) + .toList() ?? + [], + ); + +Map _$LibraryOptionsResultDtoToJson( + LibraryOptionsResultDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('MetadataSavers', + instance.metadataSavers?.map((e) => e.toJson()).toList()); + writeNotNull('MetadataReaders', + instance.metadataReaders?.map((e) => e.toJson()).toList()); + writeNotNull('SubtitleFetchers', + instance.subtitleFetchers?.map((e) => e.toJson()).toList()); + writeNotNull( + 'TypeOptions', instance.typeOptions?.map((e) => e.toJson()).toList()); + return val; +} + +LibraryTypeOptionsDto _$LibraryTypeOptionsDtoFromJson( + Map json) => + LibraryTypeOptionsDto( + type: json['Type'] as String?, + metadataFetchers: (json['MetadataFetchers'] as List?) + ?.map((e) => + LibraryOptionInfoDto.fromJson(e as Map)) + .toList() ?? + [], + imageFetchers: (json['ImageFetchers'] as List?) + ?.map((e) => + LibraryOptionInfoDto.fromJson(e as Map)) + .toList() ?? + [], + supportedImageTypes: + imageTypeListFromJson(json['SupportedImageTypes'] as List?), + defaultImageOptions: (json['DefaultImageOptions'] as List?) + ?.map((e) => ImageOption.fromJson(e as Map)) + .toList() ?? + [], + ); + +Map _$LibraryTypeOptionsDtoToJson( + LibraryTypeOptionsDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Type', instance.type); + writeNotNull('MetadataFetchers', + instance.metadataFetchers?.map((e) => e.toJson()).toList()); + writeNotNull( + 'ImageFetchers', instance.imageFetchers?.map((e) => e.toJson()).toList()); + val['SupportedImageTypes'] = + imageTypeListToJson(instance.supportedImageTypes); + writeNotNull('DefaultImageOptions', + instance.defaultImageOptions?.map((e) => e.toJson()).toList()); + return val; +} + +LibraryUpdateInfo _$LibraryUpdateInfoFromJson(Map json) => + LibraryUpdateInfo( + foldersAddedTo: (json['FoldersAddedTo'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + foldersRemovedFrom: (json['FoldersRemovedFrom'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + itemsAdded: (json['ItemsAdded'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + itemsRemoved: (json['ItemsRemoved'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + itemsUpdated: (json['ItemsUpdated'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + collectionFolders: (json['CollectionFolders'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + isEmpty: json['IsEmpty'] as bool?, + ); + +Map _$LibraryUpdateInfoToJson(LibraryUpdateInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('FoldersAddedTo', instance.foldersAddedTo); + writeNotNull('FoldersRemovedFrom', instance.foldersRemovedFrom); + writeNotNull('ItemsAdded', instance.itemsAdded); + writeNotNull('ItemsRemoved', instance.itemsRemoved); + writeNotNull('ItemsUpdated', instance.itemsUpdated); + writeNotNull('CollectionFolders', instance.collectionFolders); + writeNotNull('IsEmpty', instance.isEmpty); + return val; +} + +ListingsProviderInfo _$ListingsProviderInfoFromJson( + Map json) => + ListingsProviderInfo( + id: json['Id'] as String?, + type: json['Type'] as String?, + username: json['Username'] as String?, + password: json['Password'] as String?, + listingsId: json['ListingsId'] as String?, + zipCode: json['ZipCode'] as String?, + country: json['Country'] as String?, + path: json['Path'] as String?, + enabledTuners: (json['EnabledTuners'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + enableAllTuners: json['EnableAllTuners'] as bool?, + newsCategories: (json['NewsCategories'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + sportsCategories: (json['SportsCategories'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + kidsCategories: (json['KidsCategories'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + movieCategories: (json['MovieCategories'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + channelMappings: (json['ChannelMappings'] as List?) + ?.map((e) => NameValuePair.fromJson(e as Map)) + .toList() ?? + [], + moviePrefix: json['MoviePrefix'] as String?, + preferredLanguage: json['PreferredLanguage'] as String?, + userAgent: json['UserAgent'] as String?, + ); + +Map _$ListingsProviderInfoToJson( + ListingsProviderInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Id', instance.id); + writeNotNull('Type', instance.type); + writeNotNull('Username', instance.username); + writeNotNull('Password', instance.password); + writeNotNull('ListingsId', instance.listingsId); + writeNotNull('ZipCode', instance.zipCode); + writeNotNull('Country', instance.country); + writeNotNull('Path', instance.path); + writeNotNull('EnabledTuners', instance.enabledTuners); + writeNotNull('EnableAllTuners', instance.enableAllTuners); + writeNotNull('NewsCategories', instance.newsCategories); + writeNotNull('SportsCategories', instance.sportsCategories); + writeNotNull('KidsCategories', instance.kidsCategories); + writeNotNull('MovieCategories', instance.movieCategories); + writeNotNull('ChannelMappings', + instance.channelMappings?.map((e) => e.toJson()).toList()); + writeNotNull('MoviePrefix', instance.moviePrefix); + writeNotNull('PreferredLanguage', instance.preferredLanguage); + writeNotNull('UserAgent', instance.userAgent); + return val; +} + +LiveStreamResponse _$LiveStreamResponseFromJson(Map json) => + LiveStreamResponse( + mediaSource: json['MediaSource'] == null + ? null + : MediaSourceInfo.fromJson( + json['MediaSource'] as Map), + ); + +Map _$LiveStreamResponseToJson(LiveStreamResponse instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('MediaSource', instance.mediaSource?.toJson()); + return val; +} + +LiveTvInfo _$LiveTvInfoFromJson(Map json) => LiveTvInfo( + services: (json['Services'] as List?) + ?.map( + (e) => LiveTvServiceInfo.fromJson(e as Map)) + .toList() ?? + [], + isEnabled: json['IsEnabled'] as bool?, + enabledUsers: (json['EnabledUsers'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + ); + +Map _$LiveTvInfoToJson(LiveTvInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Services', instance.services?.map((e) => e.toJson()).toList()); + writeNotNull('IsEnabled', instance.isEnabled); + writeNotNull('EnabledUsers', instance.enabledUsers); + return val; +} + +LiveTvOptions _$LiveTvOptionsFromJson(Map json) => + LiveTvOptions( + guideDays: (json['GuideDays'] as num?)?.toInt(), + recordingPath: json['RecordingPath'] as String?, + movieRecordingPath: json['MovieRecordingPath'] as String?, + seriesRecordingPath: json['SeriesRecordingPath'] as String?, + enableRecordingSubfolders: json['EnableRecordingSubfolders'] as bool?, + enableOriginalAudioWithEncodedRecordings: + json['EnableOriginalAudioWithEncodedRecordings'] as bool?, + tunerHosts: (json['TunerHosts'] as List?) + ?.map((e) => TunerHostInfo.fromJson(e as Map)) + .toList() ?? + [], + listingProviders: (json['ListingProviders'] as List?) + ?.map((e) => + ListingsProviderInfo.fromJson(e as Map)) + .toList() ?? + [], + prePaddingSeconds: (json['PrePaddingSeconds'] as num?)?.toInt(), + postPaddingSeconds: (json['PostPaddingSeconds'] as num?)?.toInt(), + mediaLocationsCreated: (json['MediaLocationsCreated'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + recordingPostProcessor: json['RecordingPostProcessor'] as String?, + recordingPostProcessorArguments: + json['RecordingPostProcessorArguments'] as String?, + saveRecordingNFO: json['SaveRecordingNFO'] as bool?, + saveRecordingImages: json['SaveRecordingImages'] as bool?, + ); + +Map _$LiveTvOptionsToJson(LiveTvOptions instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('GuideDays', instance.guideDays); + writeNotNull('RecordingPath', instance.recordingPath); + writeNotNull('MovieRecordingPath', instance.movieRecordingPath); + writeNotNull('SeriesRecordingPath', instance.seriesRecordingPath); + writeNotNull('EnableRecordingSubfolders', instance.enableRecordingSubfolders); + writeNotNull('EnableOriginalAudioWithEncodedRecordings', + instance.enableOriginalAudioWithEncodedRecordings); + writeNotNull( + 'TunerHosts', instance.tunerHosts?.map((e) => e.toJson()).toList()); + writeNotNull('ListingProviders', + instance.listingProviders?.map((e) => e.toJson()).toList()); + writeNotNull('PrePaddingSeconds', instance.prePaddingSeconds); + writeNotNull('PostPaddingSeconds', instance.postPaddingSeconds); + writeNotNull('MediaLocationsCreated', instance.mediaLocationsCreated); + writeNotNull('RecordingPostProcessor', instance.recordingPostProcessor); + writeNotNull('RecordingPostProcessorArguments', + instance.recordingPostProcessorArguments); + writeNotNull('SaveRecordingNFO', instance.saveRecordingNFO); + writeNotNull('SaveRecordingImages', instance.saveRecordingImages); + return val; +} + +LiveTvServiceInfo _$LiveTvServiceInfoFromJson(Map json) => + LiveTvServiceInfo( + name: json['Name'] as String?, + homePageUrl: json['HomePageUrl'] as String?, + status: liveTvServiceStatusNullableFromJson(json['Status']), + statusMessage: json['StatusMessage'] as String?, + version: json['Version'] as String?, + hasUpdateAvailable: json['HasUpdateAvailable'] as bool?, + isVisible: json['IsVisible'] as bool?, + tuners: (json['Tuners'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + ); + +Map _$LiveTvServiceInfoToJson(LiveTvServiceInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('HomePageUrl', instance.homePageUrl); + writeNotNull('Status', liveTvServiceStatusNullableToJson(instance.status)); + writeNotNull('StatusMessage', instance.statusMessage); + writeNotNull('Version', instance.version); + writeNotNull('HasUpdateAvailable', instance.hasUpdateAvailable); + writeNotNull('IsVisible', instance.isVisible); + writeNotNull('Tuners', instance.tuners); + return val; +} + +LocalizationOption _$LocalizationOptionFromJson(Map json) => + LocalizationOption( + name: json['Name'] as String?, + $Value: json['Value'] as String?, + ); + +Map _$LocalizationOptionToJson(LocalizationOption instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('Value', instance.$Value); + return val; +} + +LogFile _$LogFileFromJson(Map json) => LogFile( + dateCreated: json['DateCreated'] == null + ? null + : DateTime.parse(json['DateCreated'] as String), + dateModified: json['DateModified'] == null + ? null + : DateTime.parse(json['DateModified'] as String), + size: (json['Size'] as num?)?.toInt(), + name: json['Name'] as String?, + ); + +Map _$LogFileToJson(LogFile instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('DateCreated', instance.dateCreated?.toIso8601String()); + writeNotNull('DateModified', instance.dateModified?.toIso8601String()); + writeNotNull('Size', instance.size); + writeNotNull('Name', instance.name); + return val; +} + +LyricDto _$LyricDtoFromJson(Map json) => LyricDto( + metadata: json['Metadata'] == null + ? null + : LyricMetadata.fromJson(json['Metadata'] as Map), + lyrics: (json['Lyrics'] as List?) + ?.map((e) => LyricLine.fromJson(e as Map)) + .toList() ?? + [], + ); + +Map _$LyricDtoToJson(LyricDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Metadata', instance.metadata?.toJson()); + writeNotNull('Lyrics', instance.lyrics?.map((e) => e.toJson()).toList()); + return val; +} + +LyricLine _$LyricLineFromJson(Map json) => LyricLine( + text: json['Text'] as String?, + start: (json['Start'] as num?)?.toInt(), + ); + +Map _$LyricLineToJson(LyricLine instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Text', instance.text); + writeNotNull('Start', instance.start); + return val; +} + +LyricMetadata _$LyricMetadataFromJson(Map json) => + LyricMetadata( + artist: json['Artist'] as String?, + album: json['Album'] as String?, + title: json['Title'] as String?, + author: json['Author'] as String?, + length: (json['Length'] as num?)?.toInt(), + by: json['By'] as String?, + offset: (json['Offset'] as num?)?.toInt(), + creator: json['Creator'] as String?, + version: json['Version'] as String?, + isSynced: json['IsSynced'] as bool?, + ); + +Map _$LyricMetadataToJson(LyricMetadata instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Artist', instance.artist); + writeNotNull('Album', instance.album); + writeNotNull('Title', instance.title); + writeNotNull('Author', instance.author); + writeNotNull('Length', instance.length); + writeNotNull('By', instance.by); + writeNotNull('Offset', instance.offset); + writeNotNull('Creator', instance.creator); + writeNotNull('Version', instance.version); + writeNotNull('IsSynced', instance.isSynced); + return val; +} + +MediaAttachment _$MediaAttachmentFromJson(Map json) => + MediaAttachment( + codec: json['Codec'] as String?, + codecTag: json['CodecTag'] as String?, + comment: json['Comment'] as String?, + index: (json['Index'] as num?)?.toInt(), + fileName: json['FileName'] as String?, + mimeType: json['MimeType'] as String?, + deliveryUrl: json['DeliveryUrl'] as String?, + ); + +Map _$MediaAttachmentToJson(MediaAttachment instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Codec', instance.codec); + writeNotNull('CodecTag', instance.codecTag); + writeNotNull('Comment', instance.comment); + writeNotNull('Index', instance.index); + writeNotNull('FileName', instance.fileName); + writeNotNull('MimeType', instance.mimeType); + writeNotNull('DeliveryUrl', instance.deliveryUrl); + return val; +} + +MediaPathDto _$MediaPathDtoFromJson(Map json) => MediaPathDto( + name: json['Name'] as String, + path: json['Path'] as String?, + pathInfo: json['PathInfo'] == null + ? null + : MediaPathInfo.fromJson(json['PathInfo'] as Map), + ); + +Map _$MediaPathDtoToJson(MediaPathDto instance) { + final val = { + 'Name': instance.name, + }; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Path', instance.path); + writeNotNull('PathInfo', instance.pathInfo?.toJson()); + return val; +} + +MediaPathInfo _$MediaPathInfoFromJson(Map json) => + MediaPathInfo( + path: json['Path'] as String?, + networkPath: json['NetworkPath'] as String?, + ); + +Map _$MediaPathInfoToJson(MediaPathInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Path', instance.path); + writeNotNull('NetworkPath', instance.networkPath); + return val; +} + +MediaSourceInfo _$MediaSourceInfoFromJson(Map json) => + MediaSourceInfo( + protocol: mediaProtocolNullableFromJson(json['Protocol']), + id: json['Id'] as String?, + path: json['Path'] as String?, + encoderPath: json['EncoderPath'] as String?, + encoderProtocol: mediaProtocolNullableFromJson(json['EncoderProtocol']), + type: mediaSourceTypeNullableFromJson(json['Type']), + container: json['Container'] as String?, + size: (json['Size'] as num?)?.toInt(), + name: json['Name'] as String?, + isRemote: json['IsRemote'] as bool?, + eTag: json['ETag'] as String?, + runTimeTicks: (json['RunTimeTicks'] as num?)?.toInt(), + readAtNativeFramerate: json['ReadAtNativeFramerate'] as bool?, + ignoreDts: json['IgnoreDts'] as bool?, + ignoreIndex: json['IgnoreIndex'] as bool?, + genPtsInput: json['GenPtsInput'] as bool?, + supportsTranscoding: json['SupportsTranscoding'] as bool?, + supportsDirectStream: json['SupportsDirectStream'] as bool?, + supportsDirectPlay: json['SupportsDirectPlay'] as bool?, + isInfiniteStream: json['IsInfiniteStream'] as bool?, + requiresOpening: json['RequiresOpening'] as bool?, + openToken: json['OpenToken'] as String?, + requiresClosing: json['RequiresClosing'] as bool?, + liveStreamId: json['LiveStreamId'] as String?, + bufferMs: (json['BufferMs'] as num?)?.toInt(), + requiresLooping: json['RequiresLooping'] as bool?, + supportsProbing: json['SupportsProbing'] as bool?, + videoType: videoTypeNullableFromJson(json['VideoType']), + isoType: isoTypeNullableFromJson(json['IsoType']), + video3DFormat: video3DFormatNullableFromJson(json['Video3DFormat']), + mediaStreams: (json['MediaStreams'] as List?) + ?.map((e) => MediaStream.fromJson(e as Map)) + .toList() ?? + [], + mediaAttachments: (json['MediaAttachments'] as List?) + ?.map((e) => MediaAttachment.fromJson(e as Map)) + .toList() ?? + [], + formats: (json['Formats'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + bitrate: (json['Bitrate'] as num?)?.toInt(), + timestamp: transportStreamTimestampNullableFromJson(json['Timestamp']), + requiredHttpHeaders: json['RequiredHttpHeaders'] as Map?, + transcodingUrl: json['TranscodingUrl'] as String?, + transcodingSubProtocol: + mediaStreamProtocolNullableFromJson(json['TranscodingSubProtocol']), + transcodingContainer: json['TranscodingContainer'] as String?, + analyzeDurationMs: (json['AnalyzeDurationMs'] as num?)?.toInt(), + defaultAudioStreamIndex: + (json['DefaultAudioStreamIndex'] as num?)?.toInt(), + defaultSubtitleStreamIndex: + (json['DefaultSubtitleStreamIndex'] as num?)?.toInt(), + ); + +Map _$MediaSourceInfoToJson(MediaSourceInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Protocol', mediaProtocolNullableToJson(instance.protocol)); + writeNotNull('Id', instance.id); + writeNotNull('Path', instance.path); + writeNotNull('EncoderPath', instance.encoderPath); + writeNotNull( + 'EncoderProtocol', mediaProtocolNullableToJson(instance.encoderProtocol)); + writeNotNull('Type', mediaSourceTypeNullableToJson(instance.type)); + writeNotNull('Container', instance.container); + writeNotNull('Size', instance.size); + writeNotNull('Name', instance.name); + writeNotNull('IsRemote', instance.isRemote); + writeNotNull('ETag', instance.eTag); + writeNotNull('RunTimeTicks', instance.runTimeTicks); + writeNotNull('ReadAtNativeFramerate', instance.readAtNativeFramerate); + writeNotNull('IgnoreDts', instance.ignoreDts); + writeNotNull('IgnoreIndex', instance.ignoreIndex); + writeNotNull('GenPtsInput', instance.genPtsInput); + writeNotNull('SupportsTranscoding', instance.supportsTranscoding); + writeNotNull('SupportsDirectStream', instance.supportsDirectStream); + writeNotNull('SupportsDirectPlay', instance.supportsDirectPlay); + writeNotNull('IsInfiniteStream', instance.isInfiniteStream); + writeNotNull('RequiresOpening', instance.requiresOpening); + writeNotNull('OpenToken', instance.openToken); + writeNotNull('RequiresClosing', instance.requiresClosing); + writeNotNull('LiveStreamId', instance.liveStreamId); + writeNotNull('BufferMs', instance.bufferMs); + writeNotNull('RequiresLooping', instance.requiresLooping); + writeNotNull('SupportsProbing', instance.supportsProbing); + writeNotNull('VideoType', videoTypeNullableToJson(instance.videoType)); + writeNotNull('IsoType', isoTypeNullableToJson(instance.isoType)); + writeNotNull( + 'Video3DFormat', video3DFormatNullableToJson(instance.video3DFormat)); + writeNotNull( + 'MediaStreams', instance.mediaStreams?.map((e) => e.toJson()).toList()); + writeNotNull('MediaAttachments', + instance.mediaAttachments?.map((e) => e.toJson()).toList()); + writeNotNull('Formats', instance.formats); + writeNotNull('Bitrate', instance.bitrate); + writeNotNull( + 'Timestamp', transportStreamTimestampNullableToJson(instance.timestamp)); + writeNotNull('RequiredHttpHeaders', instance.requiredHttpHeaders); + writeNotNull('TranscodingUrl', instance.transcodingUrl); + writeNotNull('TranscodingSubProtocol', + mediaStreamProtocolNullableToJson(instance.transcodingSubProtocol)); + writeNotNull('TranscodingContainer', instance.transcodingContainer); + writeNotNull('AnalyzeDurationMs', instance.analyzeDurationMs); + writeNotNull('DefaultAudioStreamIndex', instance.defaultAudioStreamIndex); + writeNotNull( + 'DefaultSubtitleStreamIndex', instance.defaultSubtitleStreamIndex); + return val; +} + +MediaStream _$MediaStreamFromJson(Map json) => MediaStream( + codec: json['Codec'] as String?, + codecTag: json['CodecTag'] as String?, + language: json['Language'] as String?, + colorRange: json['ColorRange'] as String?, + colorSpace: json['ColorSpace'] as String?, + colorTransfer: json['ColorTransfer'] as String?, + colorPrimaries: json['ColorPrimaries'] as String?, + dvVersionMajor: (json['DvVersionMajor'] as num?)?.toInt(), + dvVersionMinor: (json['DvVersionMinor'] as num?)?.toInt(), + dvProfile: (json['DvProfile'] as num?)?.toInt(), + dvLevel: (json['DvLevel'] as num?)?.toInt(), + rpuPresentFlag: (json['RpuPresentFlag'] as num?)?.toInt(), + elPresentFlag: (json['ElPresentFlag'] as num?)?.toInt(), + blPresentFlag: (json['BlPresentFlag'] as num?)?.toInt(), + dvBlSignalCompatibilityId: + (json['DvBlSignalCompatibilityId'] as num?)?.toInt(), + comment: json['Comment'] as String?, + timeBase: json['TimeBase'] as String?, + codecTimeBase: json['CodecTimeBase'] as String?, + title: json['Title'] as String?, + videoRange: videoRangeNullableFromJson(json['VideoRange']), + videoRangeType: videoRangeTypeNullableFromJson(json['VideoRangeType']), + videoDoViTitle: json['VideoDoViTitle'] as String?, + audioSpatialFormat: + MediaStream.audioSpatialFormatAudioSpatialFormatNullableFromJson( + json['AudioSpatialFormat']), + localizedUndefined: json['LocalizedUndefined'] as String?, + localizedDefault: json['LocalizedDefault'] as String?, + localizedForced: json['LocalizedForced'] as String?, + localizedExternal: json['LocalizedExternal'] as String?, + localizedHearingImpaired: json['LocalizedHearingImpaired'] as String?, + displayTitle: json['DisplayTitle'] as String?, + nalLengthSize: json['NalLengthSize'] as String?, + isInterlaced: json['IsInterlaced'] as bool?, + isAVC: json['IsAVC'] as bool?, + channelLayout: json['ChannelLayout'] as String?, + bitRate: (json['BitRate'] as num?)?.toInt(), + bitDepth: (json['BitDepth'] as num?)?.toInt(), + refFrames: (json['RefFrames'] as num?)?.toInt(), + packetLength: (json['PacketLength'] as num?)?.toInt(), + channels: (json['Channels'] as num?)?.toInt(), + sampleRate: (json['SampleRate'] as num?)?.toInt(), + isDefault: json['IsDefault'] as bool?, + isForced: json['IsForced'] as bool?, + isHearingImpaired: json['IsHearingImpaired'] as bool?, + height: (json['Height'] as num?)?.toInt(), + width: (json['Width'] as num?)?.toInt(), + averageFrameRate: (json['AverageFrameRate'] as num?)?.toDouble(), + realFrameRate: (json['RealFrameRate'] as num?)?.toDouble(), + profile: json['Profile'] as String?, + type: mediaStreamTypeNullableFromJson(json['Type']), + aspectRatio: json['AspectRatio'] as String?, + index: (json['Index'] as num?)?.toInt(), + score: (json['Score'] as num?)?.toInt(), + isExternal: json['IsExternal'] as bool?, + deliveryMethod: + subtitleDeliveryMethodNullableFromJson(json['DeliveryMethod']), + deliveryUrl: json['DeliveryUrl'] as String?, + isExternalUrl: json['IsExternalUrl'] as bool?, + isTextSubtitleStream: json['IsTextSubtitleStream'] as bool?, + supportsExternalStream: json['SupportsExternalStream'] as bool?, + path: json['Path'] as String?, + pixelFormat: json['PixelFormat'] as String?, + level: (json['Level'] as num?)?.toDouble(), + isAnamorphic: json['IsAnamorphic'] as bool?, + ); + +Map _$MediaStreamToJson(MediaStream instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Codec', instance.codec); + writeNotNull('CodecTag', instance.codecTag); + writeNotNull('Language', instance.language); + writeNotNull('ColorRange', instance.colorRange); + writeNotNull('ColorSpace', instance.colorSpace); + writeNotNull('ColorTransfer', instance.colorTransfer); + writeNotNull('ColorPrimaries', instance.colorPrimaries); + writeNotNull('DvVersionMajor', instance.dvVersionMajor); + writeNotNull('DvVersionMinor', instance.dvVersionMinor); + writeNotNull('DvProfile', instance.dvProfile); + writeNotNull('DvLevel', instance.dvLevel); + writeNotNull('RpuPresentFlag', instance.rpuPresentFlag); + writeNotNull('ElPresentFlag', instance.elPresentFlag); + writeNotNull('BlPresentFlag', instance.blPresentFlag); + writeNotNull('DvBlSignalCompatibilityId', instance.dvBlSignalCompatibilityId); + writeNotNull('Comment', instance.comment); + writeNotNull('TimeBase', instance.timeBase); + writeNotNull('CodecTimeBase', instance.codecTimeBase); + writeNotNull('Title', instance.title); + writeNotNull('VideoRange', videoRangeNullableToJson(instance.videoRange)); + writeNotNull( + 'VideoRangeType', videoRangeTypeNullableToJson(instance.videoRangeType)); + writeNotNull('VideoDoViTitle', instance.videoDoViTitle); + writeNotNull('AudioSpatialFormat', + audioSpatialFormatNullableToJson(instance.audioSpatialFormat)); + writeNotNull('LocalizedUndefined', instance.localizedUndefined); + writeNotNull('LocalizedDefault', instance.localizedDefault); + writeNotNull('LocalizedForced', instance.localizedForced); + writeNotNull('LocalizedExternal', instance.localizedExternal); + writeNotNull('LocalizedHearingImpaired', instance.localizedHearingImpaired); + writeNotNull('DisplayTitle', instance.displayTitle); + writeNotNull('NalLengthSize', instance.nalLengthSize); + writeNotNull('IsInterlaced', instance.isInterlaced); + writeNotNull('IsAVC', instance.isAVC); + writeNotNull('ChannelLayout', instance.channelLayout); + writeNotNull('BitRate', instance.bitRate); + writeNotNull('BitDepth', instance.bitDepth); + writeNotNull('RefFrames', instance.refFrames); + writeNotNull('PacketLength', instance.packetLength); + writeNotNull('Channels', instance.channels); + writeNotNull('SampleRate', instance.sampleRate); + writeNotNull('IsDefault', instance.isDefault); + writeNotNull('IsForced', instance.isForced); + writeNotNull('IsHearingImpaired', instance.isHearingImpaired); + writeNotNull('Height', instance.height); + writeNotNull('Width', instance.width); + writeNotNull('AverageFrameRate', instance.averageFrameRate); + writeNotNull('RealFrameRate', instance.realFrameRate); + writeNotNull('Profile', instance.profile); + writeNotNull('Type', mediaStreamTypeNullableToJson(instance.type)); + writeNotNull('AspectRatio', instance.aspectRatio); + writeNotNull('Index', instance.index); + writeNotNull('Score', instance.score); + writeNotNull('IsExternal', instance.isExternal); + writeNotNull('DeliveryMethod', + subtitleDeliveryMethodNullableToJson(instance.deliveryMethod)); + writeNotNull('DeliveryUrl', instance.deliveryUrl); + writeNotNull('IsExternalUrl', instance.isExternalUrl); + writeNotNull('IsTextSubtitleStream', instance.isTextSubtitleStream); + writeNotNull('SupportsExternalStream', instance.supportsExternalStream); + writeNotNull('Path', instance.path); + writeNotNull('PixelFormat', instance.pixelFormat); + writeNotNull('Level', instance.level); + writeNotNull('IsAnamorphic', instance.isAnamorphic); + return val; +} + +MediaUpdateInfoDto _$MediaUpdateInfoDtoFromJson(Map json) => + MediaUpdateInfoDto( + updates: (json['Updates'] as List?) + ?.map((e) => + MediaUpdateInfoPathDto.fromJson(e as Map)) + .toList() ?? + [], + ); + +Map _$MediaUpdateInfoDtoToJson(MediaUpdateInfoDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Updates', instance.updates?.map((e) => e.toJson()).toList()); + return val; +} + +MediaUpdateInfoPathDto _$MediaUpdateInfoPathDtoFromJson( + Map json) => + MediaUpdateInfoPathDto( + path: json['Path'] as String?, + updateType: json['UpdateType'] as String?, + ); + +Map _$MediaUpdateInfoPathDtoToJson( + MediaUpdateInfoPathDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Path', instance.path); + writeNotNull('UpdateType', instance.updateType); + return val; +} + +MediaUrl _$MediaUrlFromJson(Map json) => MediaUrl( + url: json['Url'] as String?, + name: json['Name'] as String?, + ); + +Map _$MediaUrlToJson(MediaUrl instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Url', instance.url); + writeNotNull('Name', instance.name); + return val; +} + +MessageCommand _$MessageCommandFromJson(Map json) => + MessageCommand( + header: json['Header'] as String?, + text: json['Text'] as String, + timeoutMs: (json['TimeoutMs'] as num?)?.toInt(), + ); + +Map _$MessageCommandToJson(MessageCommand instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Header', instance.header); + val['Text'] = instance.text; + writeNotNull('TimeoutMs', instance.timeoutMs); + return val; +} + +MetadataConfiguration _$MetadataConfigurationFromJson( + Map json) => + MetadataConfiguration( + useFileCreationTimeForDateAdded: + json['UseFileCreationTimeForDateAdded'] as bool?, + ); + +Map _$MetadataConfigurationToJson( + MetadataConfiguration instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('UseFileCreationTimeForDateAdded', + instance.useFileCreationTimeForDateAdded); + return val; +} + +MetadataEditorInfo _$MetadataEditorInfoFromJson(Map json) => + MetadataEditorInfo( + parentalRatingOptions: (json['ParentalRatingOptions'] as List?) + ?.map((e) => ParentalRating.fromJson(e as Map)) + .toList() ?? + [], + countries: (json['Countries'] as List?) + ?.map((e) => CountryInfo.fromJson(e as Map)) + .toList() ?? + [], + cultures: (json['Cultures'] as List?) + ?.map((e) => CultureDto.fromJson(e as Map)) + .toList() ?? + [], + externalIdInfos: (json['ExternalIdInfos'] as List?) + ?.map((e) => ExternalIdInfo.fromJson(e as Map)) + .toList() ?? + [], + contentType: collectionTypeNullableFromJson(json['ContentType']), + contentTypeOptions: (json['ContentTypeOptions'] as List?) + ?.map((e) => NameValuePair.fromJson(e as Map)) + .toList() ?? + [], + ); + +Map _$MetadataEditorInfoToJson(MetadataEditorInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('ParentalRatingOptions', + instance.parentalRatingOptions?.map((e) => e.toJson()).toList()); + writeNotNull( + 'Countries', instance.countries?.map((e) => e.toJson()).toList()); + writeNotNull('Cultures', instance.cultures?.map((e) => e.toJson()).toList()); + writeNotNull('ExternalIdInfos', + instance.externalIdInfos?.map((e) => e.toJson()).toList()); + writeNotNull( + 'ContentType', collectionTypeNullableToJson(instance.contentType)); + writeNotNull('ContentTypeOptions', + instance.contentTypeOptions?.map((e) => e.toJson()).toList()); + return val; +} + +MetadataOptions _$MetadataOptionsFromJson(Map json) => + MetadataOptions( + itemType: json['ItemType'] as String?, + disabledMetadataSavers: (json['DisabledMetadataSavers'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + localMetadataReaderOrder: + (json['LocalMetadataReaderOrder'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + disabledMetadataFetchers: + (json['DisabledMetadataFetchers'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + metadataFetcherOrder: (json['MetadataFetcherOrder'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + disabledImageFetchers: (json['DisabledImageFetchers'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + imageFetcherOrder: (json['ImageFetcherOrder'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + ); + +Map _$MetadataOptionsToJson(MetadataOptions instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('ItemType', instance.itemType); + writeNotNull('DisabledMetadataSavers', instance.disabledMetadataSavers); + writeNotNull('LocalMetadataReaderOrder', instance.localMetadataReaderOrder); + writeNotNull('DisabledMetadataFetchers', instance.disabledMetadataFetchers); + writeNotNull('MetadataFetcherOrder', instance.metadataFetcherOrder); + writeNotNull('DisabledImageFetchers', instance.disabledImageFetchers); + writeNotNull('ImageFetcherOrder', instance.imageFetcherOrder); + return val; +} + +MovePlaylistItemRequestDto _$MovePlaylistItemRequestDtoFromJson( + Map json) => + MovePlaylistItemRequestDto( + playlistItemId: json['PlaylistItemId'] as String?, + newIndex: (json['NewIndex'] as num?)?.toInt(), + ); + +Map _$MovePlaylistItemRequestDtoToJson( + MovePlaylistItemRequestDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('PlaylistItemId', instance.playlistItemId); + writeNotNull('NewIndex', instance.newIndex); + return val; +} + +MovieInfo _$MovieInfoFromJson(Map json) => MovieInfo( + name: json['Name'] as String?, + originalTitle: json['OriginalTitle'] as String?, + path: json['Path'] as String?, + metadataLanguage: json['MetadataLanguage'] as String?, + metadataCountryCode: json['MetadataCountryCode'] as String?, + providerIds: json['ProviderIds'] as Map?, + year: (json['Year'] as num?)?.toInt(), + indexNumber: (json['IndexNumber'] as num?)?.toInt(), + parentIndexNumber: (json['ParentIndexNumber'] as num?)?.toInt(), + premiereDate: json['PremiereDate'] == null + ? null + : DateTime.parse(json['PremiereDate'] as String), + isAutomated: json['IsAutomated'] as bool?, + ); + +Map _$MovieInfoToJson(MovieInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('OriginalTitle', instance.originalTitle); + writeNotNull('Path', instance.path); + writeNotNull('MetadataLanguage', instance.metadataLanguage); + writeNotNull('MetadataCountryCode', instance.metadataCountryCode); + writeNotNull('ProviderIds', instance.providerIds); + writeNotNull('Year', instance.year); + writeNotNull('IndexNumber', instance.indexNumber); + writeNotNull('ParentIndexNumber', instance.parentIndexNumber); + writeNotNull('PremiereDate', instance.premiereDate?.toIso8601String()); + writeNotNull('IsAutomated', instance.isAutomated); + return val; +} + +MovieInfoRemoteSearchQuery _$MovieInfoRemoteSearchQueryFromJson( + Map json) => + MovieInfoRemoteSearchQuery( + searchInfo: json['SearchInfo'] == null + ? null + : MovieInfo.fromJson(json['SearchInfo'] as Map), + itemId: json['ItemId'] as String?, + searchProviderName: json['SearchProviderName'] as String?, + includeDisabledProviders: json['IncludeDisabledProviders'] as bool?, + ); + +Map _$MovieInfoRemoteSearchQueryToJson( + MovieInfoRemoteSearchQuery instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('SearchInfo', instance.searchInfo?.toJson()); + writeNotNull('ItemId', instance.itemId); + writeNotNull('SearchProviderName', instance.searchProviderName); + writeNotNull('IncludeDisabledProviders', instance.includeDisabledProviders); + return val; +} + +MusicVideoInfo _$MusicVideoInfoFromJson(Map json) => + MusicVideoInfo( + name: json['Name'] as String?, + originalTitle: json['OriginalTitle'] as String?, + path: json['Path'] as String?, + metadataLanguage: json['MetadataLanguage'] as String?, + metadataCountryCode: json['MetadataCountryCode'] as String?, + providerIds: json['ProviderIds'] as Map?, + year: (json['Year'] as num?)?.toInt(), + indexNumber: (json['IndexNumber'] as num?)?.toInt(), + parentIndexNumber: (json['ParentIndexNumber'] as num?)?.toInt(), + premiereDate: json['PremiereDate'] == null + ? null + : DateTime.parse(json['PremiereDate'] as String), + isAutomated: json['IsAutomated'] as bool?, + artists: (json['Artists'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + ); + +Map _$MusicVideoInfoToJson(MusicVideoInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('OriginalTitle', instance.originalTitle); + writeNotNull('Path', instance.path); + writeNotNull('MetadataLanguage', instance.metadataLanguage); + writeNotNull('MetadataCountryCode', instance.metadataCountryCode); + writeNotNull('ProviderIds', instance.providerIds); + writeNotNull('Year', instance.year); + writeNotNull('IndexNumber', instance.indexNumber); + writeNotNull('ParentIndexNumber', instance.parentIndexNumber); + writeNotNull('PremiereDate', instance.premiereDate?.toIso8601String()); + writeNotNull('IsAutomated', instance.isAutomated); + writeNotNull('Artists', instance.artists); + return val; +} + +MusicVideoInfoRemoteSearchQuery _$MusicVideoInfoRemoteSearchQueryFromJson( + Map json) => + MusicVideoInfoRemoteSearchQuery( + searchInfo: json['SearchInfo'] == null + ? null + : MusicVideoInfo.fromJson(json['SearchInfo'] as Map), + itemId: json['ItemId'] as String?, + searchProviderName: json['SearchProviderName'] as String?, + includeDisabledProviders: json['IncludeDisabledProviders'] as bool?, + ); + +Map _$MusicVideoInfoRemoteSearchQueryToJson( + MusicVideoInfoRemoteSearchQuery instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('SearchInfo', instance.searchInfo?.toJson()); + writeNotNull('ItemId', instance.itemId); + writeNotNull('SearchProviderName', instance.searchProviderName); + writeNotNull('IncludeDisabledProviders', instance.includeDisabledProviders); + return val; +} + +NameGuidPair _$NameGuidPairFromJson(Map json) => NameGuidPair( + name: json['Name'] as String?, + id: json['Id'] as String?, + ); + +Map _$NameGuidPairToJson(NameGuidPair instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('Id', instance.id); + return val; +} + +NameIdPair _$NameIdPairFromJson(Map json) => NameIdPair( + name: json['Name'] as String?, + id: json['Id'] as String?, + ); + +Map _$NameIdPairToJson(NameIdPair instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('Id', instance.id); + return val; +} + +NameValuePair _$NameValuePairFromJson(Map json) => + NameValuePair( + name: json['Name'] as String?, + $Value: json['Value'] as String?, + ); + +Map _$NameValuePairToJson(NameValuePair instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('Value', instance.$Value); + return val; +} + +NetworkConfiguration _$NetworkConfigurationFromJson( + Map json) => + NetworkConfiguration( + baseUrl: json['BaseUrl'] as String?, + enableHttps: json['EnableHttps'] as bool?, + requireHttps: json['RequireHttps'] as bool?, + certificatePath: json['CertificatePath'] as String?, + certificatePassword: json['CertificatePassword'] as String?, + internalHttpPort: (json['InternalHttpPort'] as num?)?.toInt(), + internalHttpsPort: (json['InternalHttpsPort'] as num?)?.toInt(), + publicHttpPort: (json['PublicHttpPort'] as num?)?.toInt(), + publicHttpsPort: (json['PublicHttpsPort'] as num?)?.toInt(), + autoDiscovery: json['AutoDiscovery'] as bool?, + enableUPnP: json['EnableUPnP'] as bool?, + enableIPv4: json['EnableIPv4'] as bool?, + enableIPv6: json['EnableIPv6'] as bool?, + enableRemoteAccess: json['EnableRemoteAccess'] as bool?, + localNetworkSubnets: (json['LocalNetworkSubnets'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + localNetworkAddresses: (json['LocalNetworkAddresses'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + knownProxies: (json['KnownProxies'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + ignoreVirtualInterfaces: json['IgnoreVirtualInterfaces'] as bool?, + virtualInterfaceNames: (json['VirtualInterfaceNames'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + enablePublishedServerUriByRequest: + json['EnablePublishedServerUriByRequest'] as bool?, + publishedServerUriBySubnet: + (json['PublishedServerUriBySubnet'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + remoteIPFilter: (json['RemoteIPFilter'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + isRemoteIPFilterBlacklist: json['IsRemoteIPFilterBlacklist'] as bool?, + ); + +Map _$NetworkConfigurationToJson( + NetworkConfiguration instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('BaseUrl', instance.baseUrl); + writeNotNull('EnableHttps', instance.enableHttps); + writeNotNull('RequireHttps', instance.requireHttps); + writeNotNull('CertificatePath', instance.certificatePath); + writeNotNull('CertificatePassword', instance.certificatePassword); + writeNotNull('InternalHttpPort', instance.internalHttpPort); + writeNotNull('InternalHttpsPort', instance.internalHttpsPort); + writeNotNull('PublicHttpPort', instance.publicHttpPort); + writeNotNull('PublicHttpsPort', instance.publicHttpsPort); + writeNotNull('AutoDiscovery', instance.autoDiscovery); + writeNotNull('EnableUPnP', instance.enableUPnP); + writeNotNull('EnableIPv4', instance.enableIPv4); + writeNotNull('EnableIPv6', instance.enableIPv6); + writeNotNull('EnableRemoteAccess', instance.enableRemoteAccess); + writeNotNull('LocalNetworkSubnets', instance.localNetworkSubnets); + writeNotNull('LocalNetworkAddresses', instance.localNetworkAddresses); + writeNotNull('KnownProxies', instance.knownProxies); + writeNotNull('IgnoreVirtualInterfaces', instance.ignoreVirtualInterfaces); + writeNotNull('VirtualInterfaceNames', instance.virtualInterfaceNames); + writeNotNull('EnablePublishedServerUriByRequest', + instance.enablePublishedServerUriByRequest); + writeNotNull( + 'PublishedServerUriBySubnet', instance.publishedServerUriBySubnet); + writeNotNull('RemoteIPFilter', instance.remoteIPFilter); + writeNotNull('IsRemoteIPFilterBlacklist', instance.isRemoteIPFilterBlacklist); + return val; +} + +NewGroupRequestDto _$NewGroupRequestDtoFromJson(Map json) => + NewGroupRequestDto( + groupName: json['GroupName'] as String?, + ); + +Map _$NewGroupRequestDtoToJson(NewGroupRequestDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('GroupName', instance.groupName); + return val; +} + +NextItemRequestDto _$NextItemRequestDtoFromJson(Map json) => + NextItemRequestDto( + playlistItemId: json['PlaylistItemId'] as String?, + ); + +Map _$NextItemRequestDtoToJson(NextItemRequestDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('PlaylistItemId', instance.playlistItemId); + return val; +} + +NotFoundObjects _$NotFoundObjectsFromJson(Map json) => + NotFoundObjects( + movies: (json['movies'] as List?) + ?.map((e) => TraktMovie.fromJson(e as Map)) + .toList() ?? + [], + shows: (json['shows'] as List?) + ?.map((e) => TraktShow.fromJson(e as Map)) + .toList() ?? + [], + episodes: (json['episodes'] as List?) + ?.map((e) => TraktEpisode.fromJson(e as Map)) + .toList() ?? + [], + seasons: (json['seasons'] as List?) + ?.map((e) => TraktSeason.fromJson(e as Map)) + .toList() ?? + [], + people: (json['people'] as List?) + ?.map((e) => TraktPerson.fromJson(e as Map)) + .toList() ?? + [], + ); + +Map _$NotFoundObjectsToJson(NotFoundObjects instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('movies', instance.movies?.map((e) => e.toJson()).toList()); + writeNotNull('shows', instance.shows?.map((e) => e.toJson()).toList()); + writeNotNull('episodes', instance.episodes?.map((e) => e.toJson()).toList()); + writeNotNull('seasons', instance.seasons?.map((e) => e.toJson()).toList()); + writeNotNull('people', instance.people?.map((e) => e.toJson()).toList()); + return val; +} + +OpenLiveStreamDto _$OpenLiveStreamDtoFromJson(Map json) => + OpenLiveStreamDto( + openToken: json['OpenToken'] as String?, + userId: json['UserId'] as String?, + playSessionId: json['PlaySessionId'] as String?, + maxStreamingBitrate: (json['MaxStreamingBitrate'] as num?)?.toInt(), + startTimeTicks: (json['StartTimeTicks'] as num?)?.toInt(), + audioStreamIndex: (json['AudioStreamIndex'] as num?)?.toInt(), + subtitleStreamIndex: (json['SubtitleStreamIndex'] as num?)?.toInt(), + maxAudioChannels: (json['MaxAudioChannels'] as num?)?.toInt(), + itemId: json['ItemId'] as String?, + enableDirectPlay: json['EnableDirectPlay'] as bool?, + enableDirectStream: json['EnableDirectStream'] as bool?, + deviceProfile: json['DeviceProfile'] == null + ? null + : DeviceProfile.fromJson( + json['DeviceProfile'] as Map), + directPlayProtocols: + mediaProtocolListFromJson(json['DirectPlayProtocols'] as List?), + ); + +Map _$OpenLiveStreamDtoToJson(OpenLiveStreamDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('OpenToken', instance.openToken); + writeNotNull('UserId', instance.userId); + writeNotNull('PlaySessionId', instance.playSessionId); + writeNotNull('MaxStreamingBitrate', instance.maxStreamingBitrate); + writeNotNull('StartTimeTicks', instance.startTimeTicks); + writeNotNull('AudioStreamIndex', instance.audioStreamIndex); + writeNotNull('SubtitleStreamIndex', instance.subtitleStreamIndex); + writeNotNull('MaxAudioChannels', instance.maxAudioChannels); + writeNotNull('ItemId', instance.itemId); + writeNotNull('EnableDirectPlay', instance.enableDirectPlay); + writeNotNull('EnableDirectStream', instance.enableDirectStream); + writeNotNull('DeviceProfile', instance.deviceProfile?.toJson()); + val['DirectPlayProtocols'] = + mediaProtocolListToJson(instance.directPlayProtocols); + return val; +} + +OutboundKeepAliveMessage _$OutboundKeepAliveMessageFromJson( + Map json) => + OutboundKeepAliveMessage( + messageId: json['MessageId'] as String?, + messageType: OutboundKeepAliveMessage + .sessionMessageTypeMessageTypeNullableFromJson(json['MessageType']), + ); + +Map _$OutboundKeepAliveMessageToJson( + OutboundKeepAliveMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +OutboundWebSocketMessage _$OutboundWebSocketMessageFromJson( + Map json) => + OutboundWebSocketMessage(); + +Map _$OutboundWebSocketMessageToJson( + OutboundWebSocketMessage instance) => + {}; + +PackageInfo _$PackageInfoFromJson(Map json) => PackageInfo( + name: json['name'] as String?, + description: json['description'] as String?, + overview: json['overview'] as String?, + owner: json['owner'] as String?, + category: json['category'] as String?, + guid: json['guid'] as String?, + versions: (json['versions'] as List?) + ?.map((e) => VersionInfo.fromJson(e as Map)) + .toList() ?? + [], + imageUrl: json['imageUrl'] as String?, + ); + +Map _$PackageInfoToJson(PackageInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('name', instance.name); + writeNotNull('description', instance.description); + writeNotNull('overview', instance.overview); + writeNotNull('owner', instance.owner); + writeNotNull('category', instance.category); + writeNotNull('guid', instance.guid); + writeNotNull('versions', instance.versions?.map((e) => e.toJson()).toList()); + writeNotNull('imageUrl', instance.imageUrl); + return val; +} + +ParentalRating _$ParentalRatingFromJson(Map json) => + ParentalRating( + name: json['Name'] as String?, + $Value: (json['Value'] as num?)?.toInt(), + ); + +Map _$ParentalRatingToJson(ParentalRating instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('Value', instance.$Value); + return val; +} + +PathSubstitution _$PathSubstitutionFromJson(Map json) => + PathSubstitution( + from: json['From'] as String?, + to: json['To'] as String?, + ); + +Map _$PathSubstitutionToJson(PathSubstitution instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('From', instance.from); + writeNotNull('To', instance.to); + return val; +} + +PersonLookupInfo _$PersonLookupInfoFromJson(Map json) => + PersonLookupInfo( + name: json['Name'] as String?, + originalTitle: json['OriginalTitle'] as String?, + path: json['Path'] as String?, + metadataLanguage: json['MetadataLanguage'] as String?, + metadataCountryCode: json['MetadataCountryCode'] as String?, + providerIds: json['ProviderIds'] as Map?, + year: (json['Year'] as num?)?.toInt(), + indexNumber: (json['IndexNumber'] as num?)?.toInt(), + parentIndexNumber: (json['ParentIndexNumber'] as num?)?.toInt(), + premiereDate: json['PremiereDate'] == null + ? null + : DateTime.parse(json['PremiereDate'] as String), + isAutomated: json['IsAutomated'] as bool?, + ); + +Map _$PersonLookupInfoToJson(PersonLookupInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('OriginalTitle', instance.originalTitle); + writeNotNull('Path', instance.path); + writeNotNull('MetadataLanguage', instance.metadataLanguage); + writeNotNull('MetadataCountryCode', instance.metadataCountryCode); + writeNotNull('ProviderIds', instance.providerIds); + writeNotNull('Year', instance.year); + writeNotNull('IndexNumber', instance.indexNumber); + writeNotNull('ParentIndexNumber', instance.parentIndexNumber); + writeNotNull('PremiereDate', instance.premiereDate?.toIso8601String()); + writeNotNull('IsAutomated', instance.isAutomated); + return val; +} + +PersonLookupInfoRemoteSearchQuery _$PersonLookupInfoRemoteSearchQueryFromJson( + Map json) => + PersonLookupInfoRemoteSearchQuery( + searchInfo: json['SearchInfo'] == null + ? null + : PersonLookupInfo.fromJson( + json['SearchInfo'] as Map), + itemId: json['ItemId'] as String?, + searchProviderName: json['SearchProviderName'] as String?, + includeDisabledProviders: json['IncludeDisabledProviders'] as bool?, + ); + +Map _$PersonLookupInfoRemoteSearchQueryToJson( + PersonLookupInfoRemoteSearchQuery instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('SearchInfo', instance.searchInfo?.toJson()); + writeNotNull('ItemId', instance.itemId); + writeNotNull('SearchProviderName', instance.searchProviderName); + writeNotNull('IncludeDisabledProviders', instance.includeDisabledProviders); + return val; +} + +PingRequestDto _$PingRequestDtoFromJson(Map json) => + PingRequestDto( + ping: (json['Ping'] as num?)?.toInt(), + ); + +Map _$PingRequestDtoToJson(PingRequestDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Ping', instance.ping); + return val; +} + +PinRedeemResult _$PinRedeemResultFromJson(Map json) => + PinRedeemResult( + success: json['Success'] as bool?, + usersReset: (json['UsersReset'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + ); + +Map _$PinRedeemResultToJson(PinRedeemResult instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Success', instance.success); + writeNotNull('UsersReset', instance.usersReset); + return val; +} + +PlaybackInfoDto _$PlaybackInfoDtoFromJson(Map json) => + PlaybackInfoDto( + userId: json['UserId'] as String?, + maxStreamingBitrate: (json['MaxStreamingBitrate'] as num?)?.toInt(), + startTimeTicks: (json['StartTimeTicks'] as num?)?.toInt(), + audioStreamIndex: (json['AudioStreamIndex'] as num?)?.toInt(), + subtitleStreamIndex: (json['SubtitleStreamIndex'] as num?)?.toInt(), + maxAudioChannels: (json['MaxAudioChannels'] as num?)?.toInt(), + mediaSourceId: json['MediaSourceId'] as String?, + liveStreamId: json['LiveStreamId'] as String?, + deviceProfile: json['DeviceProfile'] == null + ? null + : DeviceProfile.fromJson( + json['DeviceProfile'] as Map), + enableDirectPlay: json['EnableDirectPlay'] as bool?, + enableDirectStream: json['EnableDirectStream'] as bool?, + enableTranscoding: json['EnableTranscoding'] as bool?, + allowVideoStreamCopy: json['AllowVideoStreamCopy'] as bool?, + allowAudioStreamCopy: json['AllowAudioStreamCopy'] as bool?, + autoOpenLiveStream: json['AutoOpenLiveStream'] as bool?, + ); + +Map _$PlaybackInfoDtoToJson(PlaybackInfoDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('UserId', instance.userId); + writeNotNull('MaxStreamingBitrate', instance.maxStreamingBitrate); + writeNotNull('StartTimeTicks', instance.startTimeTicks); + writeNotNull('AudioStreamIndex', instance.audioStreamIndex); + writeNotNull('SubtitleStreamIndex', instance.subtitleStreamIndex); + writeNotNull('MaxAudioChannels', instance.maxAudioChannels); + writeNotNull('MediaSourceId', instance.mediaSourceId); + writeNotNull('LiveStreamId', instance.liveStreamId); + writeNotNull('DeviceProfile', instance.deviceProfile?.toJson()); + writeNotNull('EnableDirectPlay', instance.enableDirectPlay); + writeNotNull('EnableDirectStream', instance.enableDirectStream); + writeNotNull('EnableTranscoding', instance.enableTranscoding); + writeNotNull('AllowVideoStreamCopy', instance.allowVideoStreamCopy); + writeNotNull('AllowAudioStreamCopy', instance.allowAudioStreamCopy); + writeNotNull('AutoOpenLiveStream', instance.autoOpenLiveStream); + return val; +} + +PlaybackInfoResponse _$PlaybackInfoResponseFromJson( + Map json) => + PlaybackInfoResponse( + mediaSources: (json['MediaSources'] as List?) + ?.map((e) => MediaSourceInfo.fromJson(e as Map)) + .toList() ?? + [], + playSessionId: json['PlaySessionId'] as String?, + errorCode: playbackErrorCodeNullableFromJson(json['ErrorCode']), + ); + +Map _$PlaybackInfoResponseToJson( + PlaybackInfoResponse instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull( + 'MediaSources', instance.mediaSources?.map((e) => e.toJson()).toList()); + writeNotNull('PlaySessionId', instance.playSessionId); + writeNotNull( + 'ErrorCode', playbackErrorCodeNullableToJson(instance.errorCode)); + return val; +} + +PlaybackProgressInfo _$PlaybackProgressInfoFromJson( + Map json) => + PlaybackProgressInfo( + canSeek: json['CanSeek'] as bool?, + item: json['Item'] == null + ? null + : BaseItemDto.fromJson(json['Item'] as Map), + itemId: json['ItemId'] as String?, + sessionId: json['SessionId'] as String?, + mediaSourceId: json['MediaSourceId'] as String?, + audioStreamIndex: (json['AudioStreamIndex'] as num?)?.toInt(), + subtitleStreamIndex: (json['SubtitleStreamIndex'] as num?)?.toInt(), + isPaused: json['IsPaused'] as bool?, + isMuted: json['IsMuted'] as bool?, + positionTicks: (json['PositionTicks'] as num?)?.toInt(), + playbackStartTimeTicks: (json['PlaybackStartTimeTicks'] as num?)?.toInt(), + volumeLevel: (json['VolumeLevel'] as num?)?.toInt(), + brightness: (json['Brightness'] as num?)?.toInt(), + aspectRatio: json['AspectRatio'] as String?, + playMethod: playMethodNullableFromJson(json['PlayMethod']), + liveStreamId: json['LiveStreamId'] as String?, + playSessionId: json['PlaySessionId'] as String?, + repeatMode: repeatModeNullableFromJson(json['RepeatMode']), + playbackOrder: playbackOrderNullableFromJson(json['PlaybackOrder']), + nowPlayingQueue: (json['NowPlayingQueue'] as List?) + ?.map((e) => QueueItem.fromJson(e as Map)) + .toList() ?? + [], + playlistItemId: json['PlaylistItemId'] as String?, + ); + +Map _$PlaybackProgressInfoToJson( + PlaybackProgressInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('CanSeek', instance.canSeek); + writeNotNull('Item', instance.item?.toJson()); + writeNotNull('ItemId', instance.itemId); + writeNotNull('SessionId', instance.sessionId); + writeNotNull('MediaSourceId', instance.mediaSourceId); + writeNotNull('AudioStreamIndex', instance.audioStreamIndex); + writeNotNull('SubtitleStreamIndex', instance.subtitleStreamIndex); + writeNotNull('IsPaused', instance.isPaused); + writeNotNull('IsMuted', instance.isMuted); + writeNotNull('PositionTicks', instance.positionTicks); + writeNotNull('PlaybackStartTimeTicks', instance.playbackStartTimeTicks); + writeNotNull('VolumeLevel', instance.volumeLevel); + writeNotNull('Brightness', instance.brightness); + writeNotNull('AspectRatio', instance.aspectRatio); + writeNotNull('PlayMethod', playMethodNullableToJson(instance.playMethod)); + writeNotNull('LiveStreamId', instance.liveStreamId); + writeNotNull('PlaySessionId', instance.playSessionId); + writeNotNull('RepeatMode', repeatModeNullableToJson(instance.repeatMode)); + writeNotNull( + 'PlaybackOrder', playbackOrderNullableToJson(instance.playbackOrder)); + writeNotNull('NowPlayingQueue', + instance.nowPlayingQueue?.map((e) => e.toJson()).toList()); + writeNotNull('PlaylistItemId', instance.playlistItemId); + return val; +} + +PlaybackStartInfo _$PlaybackStartInfoFromJson(Map json) => + PlaybackStartInfo( + canSeek: json['CanSeek'] as bool?, + item: json['Item'] == null + ? null + : BaseItemDto.fromJson(json['Item'] as Map), + itemId: json['ItemId'] as String?, + sessionId: json['SessionId'] as String?, + mediaSourceId: json['MediaSourceId'] as String?, + audioStreamIndex: (json['AudioStreamIndex'] as num?)?.toInt(), + subtitleStreamIndex: (json['SubtitleStreamIndex'] as num?)?.toInt(), + isPaused: json['IsPaused'] as bool?, + isMuted: json['IsMuted'] as bool?, + positionTicks: (json['PositionTicks'] as num?)?.toInt(), + playbackStartTimeTicks: (json['PlaybackStartTimeTicks'] as num?)?.toInt(), + volumeLevel: (json['VolumeLevel'] as num?)?.toInt(), + brightness: (json['Brightness'] as num?)?.toInt(), + aspectRatio: json['AspectRatio'] as String?, + playMethod: playMethodNullableFromJson(json['PlayMethod']), + liveStreamId: json['LiveStreamId'] as String?, + playSessionId: json['PlaySessionId'] as String?, + repeatMode: repeatModeNullableFromJson(json['RepeatMode']), + playbackOrder: playbackOrderNullableFromJson(json['PlaybackOrder']), + nowPlayingQueue: (json['NowPlayingQueue'] as List?) + ?.map((e) => QueueItem.fromJson(e as Map)) + .toList() ?? + [], + playlistItemId: json['PlaylistItemId'] as String?, + ); + +Map _$PlaybackStartInfoToJson(PlaybackStartInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('CanSeek', instance.canSeek); + writeNotNull('Item', instance.item?.toJson()); + writeNotNull('ItemId', instance.itemId); + writeNotNull('SessionId', instance.sessionId); + writeNotNull('MediaSourceId', instance.mediaSourceId); + writeNotNull('AudioStreamIndex', instance.audioStreamIndex); + writeNotNull('SubtitleStreamIndex', instance.subtitleStreamIndex); + writeNotNull('IsPaused', instance.isPaused); + writeNotNull('IsMuted', instance.isMuted); + writeNotNull('PositionTicks', instance.positionTicks); + writeNotNull('PlaybackStartTimeTicks', instance.playbackStartTimeTicks); + writeNotNull('VolumeLevel', instance.volumeLevel); + writeNotNull('Brightness', instance.brightness); + writeNotNull('AspectRatio', instance.aspectRatio); + writeNotNull('PlayMethod', playMethodNullableToJson(instance.playMethod)); + writeNotNull('LiveStreamId', instance.liveStreamId); + writeNotNull('PlaySessionId', instance.playSessionId); + writeNotNull('RepeatMode', repeatModeNullableToJson(instance.repeatMode)); + writeNotNull( + 'PlaybackOrder', playbackOrderNullableToJson(instance.playbackOrder)); + writeNotNull('NowPlayingQueue', + instance.nowPlayingQueue?.map((e) => e.toJson()).toList()); + writeNotNull('PlaylistItemId', instance.playlistItemId); + return val; +} + +PlaybackStopInfo _$PlaybackStopInfoFromJson(Map json) => + PlaybackStopInfo( + item: json['Item'] == null + ? null + : BaseItemDto.fromJson(json['Item'] as Map), + itemId: json['ItemId'] as String?, + sessionId: json['SessionId'] as String?, + mediaSourceId: json['MediaSourceId'] as String?, + positionTicks: (json['PositionTicks'] as num?)?.toInt(), + liveStreamId: json['LiveStreamId'] as String?, + playSessionId: json['PlaySessionId'] as String?, + failed: json['Failed'] as bool?, + nextMediaType: json['NextMediaType'] as String?, + playlistItemId: json['PlaylistItemId'] as String?, + nowPlayingQueue: (json['NowPlayingQueue'] as List?) + ?.map((e) => QueueItem.fromJson(e as Map)) + .toList() ?? + [], + ); + +Map _$PlaybackStopInfoToJson(PlaybackStopInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Item', instance.item?.toJson()); + writeNotNull('ItemId', instance.itemId); + writeNotNull('SessionId', instance.sessionId); + writeNotNull('MediaSourceId', instance.mediaSourceId); + writeNotNull('PositionTicks', instance.positionTicks); + writeNotNull('LiveStreamId', instance.liveStreamId); + writeNotNull('PlaySessionId', instance.playSessionId); + writeNotNull('Failed', instance.failed); + writeNotNull('NextMediaType', instance.nextMediaType); + writeNotNull('PlaylistItemId', instance.playlistItemId); + writeNotNull('NowPlayingQueue', + instance.nowPlayingQueue?.map((e) => e.toJson()).toList()); + return val; +} + +PlayerStateInfo _$PlayerStateInfoFromJson(Map json) => + PlayerStateInfo( + positionTicks: (json['PositionTicks'] as num?)?.toInt(), + canSeek: json['CanSeek'] as bool?, + isPaused: json['IsPaused'] as bool?, + isMuted: json['IsMuted'] as bool?, + volumeLevel: (json['VolumeLevel'] as num?)?.toInt(), + audioStreamIndex: (json['AudioStreamIndex'] as num?)?.toInt(), + subtitleStreamIndex: (json['SubtitleStreamIndex'] as num?)?.toInt(), + mediaSourceId: json['MediaSourceId'] as String?, + playMethod: playMethodNullableFromJson(json['PlayMethod']), + repeatMode: repeatModeNullableFromJson(json['RepeatMode']), + playbackOrder: playbackOrderNullableFromJson(json['PlaybackOrder']), + liveStreamId: json['LiveStreamId'] as String?, + ); + +Map _$PlayerStateInfoToJson(PlayerStateInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('PositionTicks', instance.positionTicks); + writeNotNull('CanSeek', instance.canSeek); + writeNotNull('IsPaused', instance.isPaused); + writeNotNull('IsMuted', instance.isMuted); + writeNotNull('VolumeLevel', instance.volumeLevel); + writeNotNull('AudioStreamIndex', instance.audioStreamIndex); + writeNotNull('SubtitleStreamIndex', instance.subtitleStreamIndex); + writeNotNull('MediaSourceId', instance.mediaSourceId); + writeNotNull('PlayMethod', playMethodNullableToJson(instance.playMethod)); + writeNotNull('RepeatMode', repeatModeNullableToJson(instance.repeatMode)); + writeNotNull( + 'PlaybackOrder', playbackOrderNullableToJson(instance.playbackOrder)); + writeNotNull('LiveStreamId', instance.liveStreamId); + return val; +} + +PlaylistCreationResult _$PlaylistCreationResultFromJson( + Map json) => + PlaylistCreationResult( + id: json['Id'] as String?, + ); + +Map _$PlaylistCreationResultToJson( + PlaylistCreationResult instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Id', instance.id); + return val; +} + +PlaylistUserPermissions _$PlaylistUserPermissionsFromJson( + Map json) => + PlaylistUserPermissions( + userId: json['UserId'] as String?, + canEdit: json['CanEdit'] as bool?, + ); + +Map _$PlaylistUserPermissionsToJson( + PlaylistUserPermissions instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('UserId', instance.userId); + writeNotNull('CanEdit', instance.canEdit); + return val; +} + +PlayMessage _$PlayMessageFromJson(Map json) => PlayMessage( + data: json['Data'] == null + ? null + : PlayRequest.fromJson(json['Data'] as Map), + messageId: json['MessageId'] as String?, + messageType: PlayMessage.sessionMessageTypeMessageTypeNullableFromJson( + json['MessageType']), + ); + +Map _$PlayMessageToJson(PlayMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Data', instance.data?.toJson()); + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +PlayQueueUpdate _$PlayQueueUpdateFromJson(Map json) => + PlayQueueUpdate( + reason: playQueueUpdateReasonNullableFromJson(json['Reason']), + lastUpdate: json['LastUpdate'] == null + ? null + : DateTime.parse(json['LastUpdate'] as String), + playlist: (json['Playlist'] as List?) + ?.map( + (e) => SyncPlayQueueItem.fromJson(e as Map)) + .toList() ?? + [], + playingItemIndex: (json['PlayingItemIndex'] as num?)?.toInt(), + startPositionTicks: (json['StartPositionTicks'] as num?)?.toInt(), + isPlaying: json['IsPlaying'] as bool?, + shuffleMode: groupShuffleModeNullableFromJson(json['ShuffleMode']), + repeatMode: groupRepeatModeNullableFromJson(json['RepeatMode']), + ); + +Map _$PlayQueueUpdateToJson(PlayQueueUpdate instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Reason', playQueueUpdateReasonNullableToJson(instance.reason)); + writeNotNull('LastUpdate', instance.lastUpdate?.toIso8601String()); + writeNotNull('Playlist', instance.playlist?.map((e) => e.toJson()).toList()); + writeNotNull('PlayingItemIndex', instance.playingItemIndex); + writeNotNull('StartPositionTicks', instance.startPositionTicks); + writeNotNull('IsPlaying', instance.isPlaying); + writeNotNull( + 'ShuffleMode', groupShuffleModeNullableToJson(instance.shuffleMode)); + writeNotNull( + 'RepeatMode', groupRepeatModeNullableToJson(instance.repeatMode)); + return val; +} + +PlayQueueUpdateGroupUpdate _$PlayQueueUpdateGroupUpdateFromJson( + Map json) => + PlayQueueUpdateGroupUpdate( + groupId: json['GroupId'] as String?, + type: groupUpdateTypeNullableFromJson(json['Type']), + data: json['Data'] == null + ? null + : PlayQueueUpdate.fromJson(json['Data'] as Map), + ); + +Map _$PlayQueueUpdateGroupUpdateToJson( + PlayQueueUpdateGroupUpdate instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('GroupId', instance.groupId); + writeNotNull('Type', groupUpdateTypeNullableToJson(instance.type)); + writeNotNull('Data', instance.data?.toJson()); + return val; +} + +PlayRequest _$PlayRequestFromJson(Map json) => PlayRequest( + itemIds: (json['ItemIds'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + startPositionTicks: (json['StartPositionTicks'] as num?)?.toInt(), + playCommand: playCommandNullableFromJson(json['PlayCommand']), + controllingUserId: json['ControllingUserId'] as String?, + subtitleStreamIndex: (json['SubtitleStreamIndex'] as num?)?.toInt(), + audioStreamIndex: (json['AudioStreamIndex'] as num?)?.toInt(), + mediaSourceId: json['MediaSourceId'] as String?, + startIndex: (json['StartIndex'] as num?)?.toInt(), + ); + +Map _$PlayRequestToJson(PlayRequest instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('ItemIds', instance.itemIds); + writeNotNull('StartPositionTicks', instance.startPositionTicks); + writeNotNull('PlayCommand', playCommandNullableToJson(instance.playCommand)); + writeNotNull('ControllingUserId', instance.controllingUserId); + writeNotNull('SubtitleStreamIndex', instance.subtitleStreamIndex); + writeNotNull('AudioStreamIndex', instance.audioStreamIndex); + writeNotNull('MediaSourceId', instance.mediaSourceId); + writeNotNull('StartIndex', instance.startIndex); + return val; +} + +PlayRequestDto _$PlayRequestDtoFromJson(Map json) => + PlayRequestDto( + playingQueue: (json['PlayingQueue'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + playingItemPosition: (json['PlayingItemPosition'] as num?)?.toInt(), + startPositionTicks: (json['StartPositionTicks'] as num?)?.toInt(), + ); + +Map _$PlayRequestDtoToJson(PlayRequestDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('PlayingQueue', instance.playingQueue); + writeNotNull('PlayingItemPosition', instance.playingItemPosition); + writeNotNull('StartPositionTicks', instance.startPositionTicks); + return val; +} + +PlaystateMessage _$PlaystateMessageFromJson(Map json) => + PlaystateMessage( + data: json['Data'] == null + ? null + : PlaystateRequest.fromJson(json['Data'] as Map), + messageId: json['MessageId'] as String?, + messageType: + PlaystateMessage.sessionMessageTypeMessageTypeNullableFromJson( + json['MessageType']), + ); + +Map _$PlaystateMessageToJson(PlaystateMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Data', instance.data?.toJson()); + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +PlaystateRequest _$PlaystateRequestFromJson(Map json) => + PlaystateRequest( + command: playstateCommandNullableFromJson(json['Command']), + seekPositionTicks: (json['SeekPositionTicks'] as num?)?.toInt(), + controllingUserId: json['ControllingUserId'] as String?, + ); + +Map _$PlaystateRequestToJson(PlaystateRequest instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Command', playstateCommandNullableToJson(instance.command)); + writeNotNull('SeekPositionTicks', instance.seekPositionTicks); + writeNotNull('ControllingUserId', instance.controllingUserId); + return val; +} + +PluginInfo _$PluginInfoFromJson(Map json) => PluginInfo( + name: json['Name'] as String?, + version: json['Version'] as String?, + configurationFileName: json['ConfigurationFileName'] as String?, + description: json['Description'] as String?, + id: json['Id'] as String?, + canUninstall: json['CanUninstall'] as bool?, + hasImage: json['HasImage'] as bool?, + status: pluginStatusNullableFromJson(json['Status']), + ); + +Map _$PluginInfoToJson(PluginInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('Version', instance.version); + writeNotNull('ConfigurationFileName', instance.configurationFileName); + writeNotNull('Description', instance.description); + writeNotNull('Id', instance.id); + writeNotNull('CanUninstall', instance.canUninstall); + writeNotNull('HasImage', instance.hasImage); + writeNotNull('Status', pluginStatusNullableToJson(instance.status)); + return val; +} + +PluginInstallationCancelledMessage _$PluginInstallationCancelledMessageFromJson( + Map json) => + PluginInstallationCancelledMessage( + data: json['Data'] == null + ? null + : InstallationInfo.fromJson(json['Data'] as Map), + messageId: json['MessageId'] as String?, + messageType: PluginInstallationCancelledMessage + .sessionMessageTypeMessageTypeNullableFromJson(json['MessageType']), + ); + +Map _$PluginInstallationCancelledMessageToJson( + PluginInstallationCancelledMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Data', instance.data?.toJson()); + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +PluginInstallationCompletedMessage _$PluginInstallationCompletedMessageFromJson( + Map json) => + PluginInstallationCompletedMessage( + data: json['Data'] == null + ? null + : InstallationInfo.fromJson(json['Data'] as Map), + messageId: json['MessageId'] as String?, + messageType: PluginInstallationCompletedMessage + .sessionMessageTypeMessageTypeNullableFromJson(json['MessageType']), + ); + +Map _$PluginInstallationCompletedMessageToJson( + PluginInstallationCompletedMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Data', instance.data?.toJson()); + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +PluginInstallationFailedMessage _$PluginInstallationFailedMessageFromJson( + Map json) => + PluginInstallationFailedMessage( + data: json['Data'] == null + ? null + : InstallationInfo.fromJson(json['Data'] as Map), + messageId: json['MessageId'] as String?, + messageType: PluginInstallationFailedMessage + .sessionMessageTypeMessageTypeNullableFromJson(json['MessageType']), + ); + +Map _$PluginInstallationFailedMessageToJson( + PluginInstallationFailedMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Data', instance.data?.toJson()); + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +PluginInstallingMessage _$PluginInstallingMessageFromJson( + Map json) => + PluginInstallingMessage( + data: json['Data'] == null + ? null + : InstallationInfo.fromJson(json['Data'] as Map), + messageId: json['MessageId'] as String?, + messageType: + PluginInstallingMessage.sessionMessageTypeMessageTypeNullableFromJson( + json['MessageType']), + ); + +Map _$PluginInstallingMessageToJson( + PluginInstallingMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Data', instance.data?.toJson()); + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +PluginUninstalledMessage _$PluginUninstalledMessageFromJson( + Map json) => + PluginUninstalledMessage( + data: json['Data'] == null + ? null + : PluginInfo.fromJson(json['Data'] as Map), + messageId: json['MessageId'] as String?, + messageType: PluginUninstalledMessage + .sessionMessageTypeMessageTypeNullableFromJson(json['MessageType']), + ); + +Map _$PluginUninstalledMessageToJson( + PluginUninstalledMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Data', instance.data?.toJson()); + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +PreviousItemRequestDto _$PreviousItemRequestDtoFromJson( + Map json) => + PreviousItemRequestDto( + playlistItemId: json['PlaylistItemId'] as String?, + ); + +Map _$PreviousItemRequestDtoToJson( + PreviousItemRequestDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('PlaylistItemId', instance.playlistItemId); + return val; +} + +ProblemDetails _$ProblemDetailsFromJson(Map json) => + ProblemDetails( + type: json['type'] as String?, + title: json['title'] as String?, + status: (json['status'] as num?)?.toInt(), + detail: json['detail'] as String?, + instance: json['instance'] as String?, + ); + +Map _$ProblemDetailsToJson(ProblemDetails instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('type', instance.type); + writeNotNull('title', instance.title); + writeNotNull('status', instance.status); + writeNotNull('detail', instance.detail); + writeNotNull('instance', instance.instance); + return val; +} + +ProfileCondition _$ProfileConditionFromJson(Map json) => + ProfileCondition( + condition: profileConditionTypeNullableFromJson(json['Condition']), + property: profileConditionValueNullableFromJson(json['Property']), + $Value: json['Value'] as String?, + isRequired: json['IsRequired'] as bool?, + ); + +Map _$ProfileConditionToJson(ProfileCondition instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull( + 'Condition', profileConditionTypeNullableToJson(instance.condition)); + writeNotNull( + 'Property', profileConditionValueNullableToJson(instance.property)); + writeNotNull('Value', instance.$Value); + writeNotNull('IsRequired', instance.isRequired); + return val; +} + +PublicSystemInfo _$PublicSystemInfoFromJson(Map json) => + PublicSystemInfo( + localAddress: json['LocalAddress'] as String?, + serverName: json['ServerName'] as String?, + version: json['Version'] as String?, + productName: json['ProductName'] as String?, + operatingSystem: json['OperatingSystem'] as String?, + id: json['Id'] as String?, + startupWizardCompleted: json['StartupWizardCompleted'] as bool?, + ); + +Map _$PublicSystemInfoToJson(PublicSystemInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('LocalAddress', instance.localAddress); + writeNotNull('ServerName', instance.serverName); + writeNotNull('Version', instance.version); + writeNotNull('ProductName', instance.productName); + writeNotNull('OperatingSystem', instance.operatingSystem); + writeNotNull('Id', instance.id); + writeNotNull('StartupWizardCompleted', instance.startupWizardCompleted); + return val; +} + +QueryFilters _$QueryFiltersFromJson(Map json) => QueryFilters( + genres: (json['Genres'] as List?) + ?.map((e) => NameGuidPair.fromJson(e as Map)) + .toList() ?? + [], + tags: + (json['Tags'] as List?)?.map((e) => e as String).toList() ?? + [], + ); + +Map _$QueryFiltersToJson(QueryFilters instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Genres', instance.genres?.map((e) => e.toJson()).toList()); + writeNotNull('Tags', instance.tags); + return val; +} + +QueryFiltersLegacy _$QueryFiltersLegacyFromJson(Map json) => + QueryFiltersLegacy( + genres: (json['Genres'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + tags: + (json['Tags'] as List?)?.map((e) => e as String).toList() ?? + [], + officialRatings: (json['OfficialRatings'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + years: (json['Years'] as List?) + ?.map((e) => (e as num).toInt()) + .toList() ?? + [], + ); + +Map _$QueryFiltersLegacyToJson(QueryFiltersLegacy instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Genres', instance.genres); + writeNotNull('Tags', instance.tags); + writeNotNull('OfficialRatings', instance.officialRatings); + writeNotNull('Years', instance.years); + return val; +} + +QueueItem _$QueueItemFromJson(Map json) => QueueItem( + id: json['Id'] as String?, + playlistItemId: json['PlaylistItemId'] as String?, + ); + +Map _$QueueItemToJson(QueueItem instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Id', instance.id); + writeNotNull('PlaylistItemId', instance.playlistItemId); + return val; +} + +QueueRequestDto _$QueueRequestDtoFromJson(Map json) => + QueueRequestDto( + itemIds: (json['ItemIds'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + mode: groupQueueModeNullableFromJson(json['Mode']), + ); + +Map _$QueueRequestDtoToJson(QueueRequestDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('ItemIds', instance.itemIds); + writeNotNull('Mode', groupQueueModeNullableToJson(instance.mode)); + return val; +} + +QuickConnectDto _$QuickConnectDtoFromJson(Map json) => + QuickConnectDto( + secret: json['Secret'] as String, + ); + +Map _$QuickConnectDtoToJson(QuickConnectDto instance) => + { + 'Secret': instance.secret, + }; + +QuickConnectResult _$QuickConnectResultFromJson(Map json) => + QuickConnectResult( + authenticated: json['Authenticated'] as bool?, + secret: json['Secret'] as String?, + code: json['Code'] as String?, + deviceId: json['DeviceId'] as String?, + deviceName: json['DeviceName'] as String?, + appName: json['AppName'] as String?, + appVersion: json['AppVersion'] as String?, + dateAdded: json['DateAdded'] == null + ? null + : DateTime.parse(json['DateAdded'] as String), + ); + +Map _$QuickConnectResultToJson(QuickConnectResult instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Authenticated', instance.authenticated); + writeNotNull('Secret', instance.secret); + writeNotNull('Code', instance.code); + writeNotNull('DeviceId', instance.deviceId); + writeNotNull('DeviceName', instance.deviceName); + writeNotNull('AppName', instance.appName); + writeNotNull('AppVersion', instance.appVersion); + writeNotNull('DateAdded', instance.dateAdded?.toIso8601String()); + return val; +} + +ReadyRequestDto _$ReadyRequestDtoFromJson(Map json) => + ReadyRequestDto( + when: + json['When'] == null ? null : DateTime.parse(json['When'] as String), + positionTicks: (json['PositionTicks'] as num?)?.toInt(), + isPlaying: json['IsPlaying'] as bool?, + playlistItemId: json['PlaylistItemId'] as String?, + ); + +Map _$ReadyRequestDtoToJson(ReadyRequestDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('When', instance.when?.toIso8601String()); + writeNotNull('PositionTicks', instance.positionTicks); + writeNotNull('IsPlaying', instance.isPlaying); + writeNotNull('PlaylistItemId', instance.playlistItemId); + return val; +} + +RecommendationDto _$RecommendationDtoFromJson(Map json) => + RecommendationDto( + items: (json['Items'] as List?) + ?.map((e) => BaseItemDto.fromJson(e as Map)) + .toList() ?? + [], + recommendationType: + recommendationTypeNullableFromJson(json['RecommendationType']), + baselineItemName: json['BaselineItemName'] as String?, + categoryId: json['CategoryId'] as String?, + ); + +Map _$RecommendationDtoToJson(RecommendationDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Items', instance.items?.map((e) => e.toJson()).toList()); + writeNotNull('RecommendationType', + recommendationTypeNullableToJson(instance.recommendationType)); + writeNotNull('BaselineItemName', instance.baselineItemName); + writeNotNull('CategoryId', instance.categoryId); + return val; +} + +RefreshProgressMessage _$RefreshProgressMessageFromJson( + Map json) => + RefreshProgressMessage( + data: json['Data'] as Map?, + messageId: json['MessageId'] as String?, + messageType: + RefreshProgressMessage.sessionMessageTypeMessageTypeNullableFromJson( + json['MessageType']), + ); + +Map _$RefreshProgressMessageToJson( + RefreshProgressMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Data', instance.data); + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +RemoteImageInfo _$RemoteImageInfoFromJson(Map json) => + RemoteImageInfo( + providerName: json['ProviderName'] as String?, + url: json['Url'] as String?, + thumbnailUrl: json['ThumbnailUrl'] as String?, + height: (json['Height'] as num?)?.toInt(), + width: (json['Width'] as num?)?.toInt(), + communityRating: (json['CommunityRating'] as num?)?.toDouble(), + voteCount: (json['VoteCount'] as num?)?.toInt(), + language: json['Language'] as String?, + type: imageTypeNullableFromJson(json['Type']), + ratingType: ratingTypeNullableFromJson(json['RatingType']), + ); + +Map _$RemoteImageInfoToJson(RemoteImageInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('ProviderName', instance.providerName); + writeNotNull('Url', instance.url); + writeNotNull('ThumbnailUrl', instance.thumbnailUrl); + writeNotNull('Height', instance.height); + writeNotNull('Width', instance.width); + writeNotNull('CommunityRating', instance.communityRating); + writeNotNull('VoteCount', instance.voteCount); + writeNotNull('Language', instance.language); + writeNotNull('Type', imageTypeNullableToJson(instance.type)); + writeNotNull('RatingType', ratingTypeNullableToJson(instance.ratingType)); + return val; +} + +RemoteImageResult _$RemoteImageResultFromJson(Map json) => + RemoteImageResult( + images: (json['Images'] as List?) + ?.map((e) => RemoteImageInfo.fromJson(e as Map)) + .toList() ?? + [], + totalRecordCount: (json['TotalRecordCount'] as num?)?.toInt(), + providers: (json['Providers'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + ); + +Map _$RemoteImageResultToJson(RemoteImageResult instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Images', instance.images?.map((e) => e.toJson()).toList()); + writeNotNull('TotalRecordCount', instance.totalRecordCount); + writeNotNull('Providers', instance.providers); + return val; +} + +RemoteLyricInfoDto _$RemoteLyricInfoDtoFromJson(Map json) => + RemoteLyricInfoDto( + id: json['Id'] as String?, + providerName: json['ProviderName'] as String?, + lyrics: json['Lyrics'] == null + ? null + : LyricDto.fromJson(json['Lyrics'] as Map), + ); + +Map _$RemoteLyricInfoDtoToJson(RemoteLyricInfoDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Id', instance.id); + writeNotNull('ProviderName', instance.providerName); + writeNotNull('Lyrics', instance.lyrics?.toJson()); + return val; +} + +RemoteSearchResult _$RemoteSearchResultFromJson(Map json) => + RemoteSearchResult( + name: json['Name'] as String?, + providerIds: json['ProviderIds'] as Map?, + productionYear: (json['ProductionYear'] as num?)?.toInt(), + indexNumber: (json['IndexNumber'] as num?)?.toInt(), + indexNumberEnd: (json['IndexNumberEnd'] as num?)?.toInt(), + parentIndexNumber: (json['ParentIndexNumber'] as num?)?.toInt(), + premiereDate: json['PremiereDate'] == null + ? null + : DateTime.parse(json['PremiereDate'] as String), + imageUrl: json['ImageUrl'] as String?, + searchProviderName: json['SearchProviderName'] as String?, + overview: json['Overview'] as String?, + albumArtist: json['AlbumArtist'] == null + ? null + : RemoteSearchResult.fromJson( + json['AlbumArtist'] as Map), + artists: (json['Artists'] as List?) + ?.map( + (e) => RemoteSearchResult.fromJson(e as Map)) + .toList() ?? + [], + ); + +Map _$RemoteSearchResultToJson(RemoteSearchResult instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('ProviderIds', instance.providerIds); + writeNotNull('ProductionYear', instance.productionYear); + writeNotNull('IndexNumber', instance.indexNumber); + writeNotNull('IndexNumberEnd', instance.indexNumberEnd); + writeNotNull('ParentIndexNumber', instance.parentIndexNumber); + writeNotNull('PremiereDate', instance.premiereDate?.toIso8601String()); + writeNotNull('ImageUrl', instance.imageUrl); + writeNotNull('SearchProviderName', instance.searchProviderName); + writeNotNull('Overview', instance.overview); + writeNotNull('AlbumArtist', instance.albumArtist?.toJson()); + writeNotNull('Artists', instance.artists?.map((e) => e.toJson()).toList()); + return val; +} + +RemoteSubtitleInfo _$RemoteSubtitleInfoFromJson(Map json) => + RemoteSubtitleInfo( + threeLetterISOLanguageName: json['ThreeLetterISOLanguageName'] as String?, + id: json['Id'] as String?, + providerName: json['ProviderName'] as String?, + name: json['Name'] as String?, + format: json['Format'] as String?, + author: json['Author'] as String?, + comment: json['Comment'] as String?, + dateCreated: json['DateCreated'] == null + ? null + : DateTime.parse(json['DateCreated'] as String), + communityRating: (json['CommunityRating'] as num?)?.toDouble(), + frameRate: (json['FrameRate'] as num?)?.toDouble(), + downloadCount: (json['DownloadCount'] as num?)?.toInt(), + isHashMatch: json['IsHashMatch'] as bool?, + aiTranslated: json['AiTranslated'] as bool?, + machineTranslated: json['MachineTranslated'] as bool?, + forced: json['Forced'] as bool?, + hearingImpaired: json['HearingImpaired'] as bool?, + ); + +Map _$RemoteSubtitleInfoToJson(RemoteSubtitleInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull( + 'ThreeLetterISOLanguageName', instance.threeLetterISOLanguageName); + writeNotNull('Id', instance.id); + writeNotNull('ProviderName', instance.providerName); + writeNotNull('Name', instance.name); + writeNotNull('Format', instance.format); + writeNotNull('Author', instance.author); + writeNotNull('Comment', instance.comment); + writeNotNull('DateCreated', instance.dateCreated?.toIso8601String()); + writeNotNull('CommunityRating', instance.communityRating); + writeNotNull('FrameRate', instance.frameRate); + writeNotNull('DownloadCount', instance.downloadCount); + writeNotNull('IsHashMatch', instance.isHashMatch); + writeNotNull('AiTranslated', instance.aiTranslated); + writeNotNull('MachineTranslated', instance.machineTranslated); + writeNotNull('Forced', instance.forced); + writeNotNull('HearingImpaired', instance.hearingImpaired); + return val; +} + +RemoveFromPlaylistRequestDto _$RemoveFromPlaylistRequestDtoFromJson( + Map json) => + RemoveFromPlaylistRequestDto( + playlistItemIds: (json['PlaylistItemIds'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + clearPlaylist: json['ClearPlaylist'] as bool?, + clearPlayingItem: json['ClearPlayingItem'] as bool?, + ); + +Map _$RemoveFromPlaylistRequestDtoToJson( + RemoveFromPlaylistRequestDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('PlaylistItemIds', instance.playlistItemIds); + writeNotNull('ClearPlaylist', instance.clearPlaylist); + writeNotNull('ClearPlayingItem', instance.clearPlayingItem); + return val; +} + +ReportPlaybackOptions _$ReportPlaybackOptionsFromJson( + Map json) => + ReportPlaybackOptions( + maxDataAge: (json['MaxDataAge'] as num?)?.toInt(), + backupPath: json['BackupPath'] as String?, + maxBackupFiles: (json['MaxBackupFiles'] as num?)?.toInt(), + ); + +Map _$ReportPlaybackOptionsToJson( + ReportPlaybackOptions instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('MaxDataAge', instance.maxDataAge); + writeNotNull('BackupPath', instance.backupPath); + writeNotNull('MaxBackupFiles', instance.maxBackupFiles); + return val; +} + +RepositoryInfo _$RepositoryInfoFromJson(Map json) => + RepositoryInfo( + name: json['Name'] as String?, + url: json['Url'] as String?, + enabled: json['Enabled'] as bool?, + ); + +Map _$RepositoryInfoToJson(RepositoryInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('Url', instance.url); + writeNotNull('Enabled', instance.enabled); + return val; +} + +RestartRequiredMessage _$RestartRequiredMessageFromJson( + Map json) => + RestartRequiredMessage( + messageId: json['MessageId'] as String?, + messageType: + RestartRequiredMessage.sessionMessageTypeMessageTypeNullableFromJson( + json['MessageType']), + ); + +Map _$RestartRequiredMessageToJson( + RestartRequiredMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +ScheduledTaskEndedMessage _$ScheduledTaskEndedMessageFromJson( + Map json) => + ScheduledTaskEndedMessage( + data: json['Data'] == null + ? null + : TaskResult.fromJson(json['Data'] as Map), + messageId: json['MessageId'] as String?, + messageType: ScheduledTaskEndedMessage + .sessionMessageTypeMessageTypeNullableFromJson(json['MessageType']), + ); + +Map _$ScheduledTaskEndedMessageToJson( + ScheduledTaskEndedMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Data', instance.data?.toJson()); + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +ScheduledTasksInfoMessage _$ScheduledTasksInfoMessageFromJson( + Map json) => + ScheduledTasksInfoMessage( + data: (json['Data'] as List?) + ?.map((e) => TaskInfo.fromJson(e as Map)) + .toList() ?? + [], + messageId: json['MessageId'] as String?, + messageType: ScheduledTasksInfoMessage + .sessionMessageTypeMessageTypeNullableFromJson(json['MessageType']), + ); + +Map _$ScheduledTasksInfoMessageToJson( + ScheduledTasksInfoMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Data', instance.data?.map((e) => e.toJson()).toList()); + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +ScheduledTasksInfoStartMessage _$ScheduledTasksInfoStartMessageFromJson( + Map json) => + ScheduledTasksInfoStartMessage( + data: json['Data'] as String?, + messageType: ScheduledTasksInfoStartMessage + .sessionMessageTypeMessageTypeNullableFromJson(json['MessageType']), + ); + +Map _$ScheduledTasksInfoStartMessageToJson( + ScheduledTasksInfoStartMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Data', instance.data); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +ScheduledTasksInfoStopMessage _$ScheduledTasksInfoStopMessageFromJson( + Map json) => + ScheduledTasksInfoStopMessage( + messageType: ScheduledTasksInfoStopMessage + .sessionMessageTypeMessageTypeNullableFromJson(json['MessageType']), + ); + +Map _$ScheduledTasksInfoStopMessageToJson( + ScheduledTasksInfoStopMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +SearchHint _$SearchHintFromJson(Map json) => SearchHint( + itemId: json['ItemId'] as String?, + id: json['Id'] as String?, + name: json['Name'] as String?, + matchedTerm: json['MatchedTerm'] as String?, + indexNumber: (json['IndexNumber'] as num?)?.toInt(), + productionYear: (json['ProductionYear'] as num?)?.toInt(), + parentIndexNumber: (json['ParentIndexNumber'] as num?)?.toInt(), + primaryImageTag: json['PrimaryImageTag'] as String?, + thumbImageTag: json['ThumbImageTag'] as String?, + thumbImageItemId: json['ThumbImageItemId'] as String?, + backdropImageTag: json['BackdropImageTag'] as String?, + backdropImageItemId: json['BackdropImageItemId'] as String?, + type: baseItemKindNullableFromJson(json['Type']), + isFolder: json['IsFolder'] as bool?, + runTimeTicks: (json['RunTimeTicks'] as num?)?.toInt(), + mediaType: mediaTypeNullableFromJson(json['MediaType']), + startDate: json['StartDate'] == null + ? null + : DateTime.parse(json['StartDate'] as String), + endDate: json['EndDate'] == null + ? null + : DateTime.parse(json['EndDate'] as String), + series: json['Series'] as String?, + status: json['Status'] as String?, + album: json['Album'] as String?, + albumId: json['AlbumId'] as String?, + albumArtist: json['AlbumArtist'] as String?, + artists: (json['Artists'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + songCount: (json['SongCount'] as num?)?.toInt(), + episodeCount: (json['EpisodeCount'] as num?)?.toInt(), + channelId: json['ChannelId'] as String?, + channelName: json['ChannelName'] as String?, + primaryImageAspectRatio: + (json['PrimaryImageAspectRatio'] as num?)?.toDouble(), + ); + +Map _$SearchHintToJson(SearchHint instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('ItemId', instance.itemId); + writeNotNull('Id', instance.id); + writeNotNull('Name', instance.name); + writeNotNull('MatchedTerm', instance.matchedTerm); + writeNotNull('IndexNumber', instance.indexNumber); + writeNotNull('ProductionYear', instance.productionYear); + writeNotNull('ParentIndexNumber', instance.parentIndexNumber); + writeNotNull('PrimaryImageTag', instance.primaryImageTag); + writeNotNull('ThumbImageTag', instance.thumbImageTag); + writeNotNull('ThumbImageItemId', instance.thumbImageItemId); + writeNotNull('BackdropImageTag', instance.backdropImageTag); + writeNotNull('BackdropImageItemId', instance.backdropImageItemId); + writeNotNull('Type', baseItemKindNullableToJson(instance.type)); + writeNotNull('IsFolder', instance.isFolder); + writeNotNull('RunTimeTicks', instance.runTimeTicks); + writeNotNull('MediaType', mediaTypeNullableToJson(instance.mediaType)); + writeNotNull('StartDate', instance.startDate?.toIso8601String()); + writeNotNull('EndDate', instance.endDate?.toIso8601String()); + writeNotNull('Series', instance.series); + writeNotNull('Status', instance.status); + writeNotNull('Album', instance.album); + writeNotNull('AlbumId', instance.albumId); + writeNotNull('AlbumArtist', instance.albumArtist); + writeNotNull('Artists', instance.artists); + writeNotNull('SongCount', instance.songCount); + writeNotNull('EpisodeCount', instance.episodeCount); + writeNotNull('ChannelId', instance.channelId); + writeNotNull('ChannelName', instance.channelName); + writeNotNull('PrimaryImageAspectRatio', instance.primaryImageAspectRatio); + return val; +} + +SearchHintResult _$SearchHintResultFromJson(Map json) => + SearchHintResult( + searchHints: (json['SearchHints'] as List?) + ?.map((e) => SearchHint.fromJson(e as Map)) + .toList() ?? + [], + totalRecordCount: (json['TotalRecordCount'] as num?)?.toInt(), + ); + +Map _$SearchHintResultToJson(SearchHintResult instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull( + 'SearchHints', instance.searchHints?.map((e) => e.toJson()).toList()); + writeNotNull('TotalRecordCount', instance.totalRecordCount); + return val; +} + +SeekRequestDto _$SeekRequestDtoFromJson(Map json) => + SeekRequestDto( + positionTicks: (json['PositionTicks'] as num?)?.toInt(), + ); + +Map _$SeekRequestDtoToJson(SeekRequestDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('PositionTicks', instance.positionTicks); + return val; +} + +SendCommand _$SendCommandFromJson(Map json) => SendCommand( + groupId: json['GroupId'] as String?, + playlistItemId: json['PlaylistItemId'] as String?, + when: + json['When'] == null ? null : DateTime.parse(json['When'] as String), + positionTicks: (json['PositionTicks'] as num?)?.toInt(), + command: sendCommandTypeNullableFromJson(json['Command']), + emittedAt: json['EmittedAt'] == null + ? null + : DateTime.parse(json['EmittedAt'] as String), + ); + +Map _$SendCommandToJson(SendCommand instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('GroupId', instance.groupId); + writeNotNull('PlaylistItemId', instance.playlistItemId); + writeNotNull('When', instance.when?.toIso8601String()); + writeNotNull('PositionTicks', instance.positionTicks); + writeNotNull('Command', sendCommandTypeNullableToJson(instance.command)); + writeNotNull('EmittedAt', instance.emittedAt?.toIso8601String()); + return val; +} + +SeriesInfo _$SeriesInfoFromJson(Map json) => SeriesInfo( + name: json['Name'] as String?, + originalTitle: json['OriginalTitle'] as String?, + path: json['Path'] as String?, + metadataLanguage: json['MetadataLanguage'] as String?, + metadataCountryCode: json['MetadataCountryCode'] as String?, + providerIds: json['ProviderIds'] as Map?, + year: (json['Year'] as num?)?.toInt(), + indexNumber: (json['IndexNumber'] as num?)?.toInt(), + parentIndexNumber: (json['ParentIndexNumber'] as num?)?.toInt(), + premiereDate: json['PremiereDate'] == null + ? null + : DateTime.parse(json['PremiereDate'] as String), + isAutomated: json['IsAutomated'] as bool?, + ); + +Map _$SeriesInfoToJson(SeriesInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('OriginalTitle', instance.originalTitle); + writeNotNull('Path', instance.path); + writeNotNull('MetadataLanguage', instance.metadataLanguage); + writeNotNull('MetadataCountryCode', instance.metadataCountryCode); + writeNotNull('ProviderIds', instance.providerIds); + writeNotNull('Year', instance.year); + writeNotNull('IndexNumber', instance.indexNumber); + writeNotNull('ParentIndexNumber', instance.parentIndexNumber); + writeNotNull('PremiereDate', instance.premiereDate?.toIso8601String()); + writeNotNull('IsAutomated', instance.isAutomated); + return val; +} + +SeriesInfoRemoteSearchQuery _$SeriesInfoRemoteSearchQueryFromJson( + Map json) => + SeriesInfoRemoteSearchQuery( + searchInfo: json['SearchInfo'] == null + ? null + : SeriesInfo.fromJson(json['SearchInfo'] as Map), + itemId: json['ItemId'] as String?, + searchProviderName: json['SearchProviderName'] as String?, + includeDisabledProviders: json['IncludeDisabledProviders'] as bool?, + ); + +Map _$SeriesInfoRemoteSearchQueryToJson( + SeriesInfoRemoteSearchQuery instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('SearchInfo', instance.searchInfo?.toJson()); + writeNotNull('ItemId', instance.itemId); + writeNotNull('SearchProviderName', instance.searchProviderName); + writeNotNull('IncludeDisabledProviders', instance.includeDisabledProviders); + return val; +} + +SeriesTimerCancelledMessage _$SeriesTimerCancelledMessageFromJson( + Map json) => + SeriesTimerCancelledMessage( + data: json['Data'] == null + ? null + : TimerEventInfo.fromJson(json['Data'] as Map), + messageId: json['MessageId'] as String?, + messageType: SeriesTimerCancelledMessage + .sessionMessageTypeMessageTypeNullableFromJson(json['MessageType']), + ); + +Map _$SeriesTimerCancelledMessageToJson( + SeriesTimerCancelledMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Data', instance.data?.toJson()); + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +SeriesTimerCreatedMessage _$SeriesTimerCreatedMessageFromJson( + Map json) => + SeriesTimerCreatedMessage( + data: json['Data'] == null + ? null + : TimerEventInfo.fromJson(json['Data'] as Map), + messageId: json['MessageId'] as String?, + messageType: SeriesTimerCreatedMessage + .sessionMessageTypeMessageTypeNullableFromJson(json['MessageType']), + ); + +Map _$SeriesTimerCreatedMessageToJson( + SeriesTimerCreatedMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Data', instance.data?.toJson()); + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +SeriesTimerInfoDto _$SeriesTimerInfoDtoFromJson(Map json) => + SeriesTimerInfoDto( + id: json['Id'] as String?, + type: json['Type'] as String?, + serverId: json['ServerId'] as String?, + externalId: json['ExternalId'] as String?, + channelId: json['ChannelId'] as String?, + externalChannelId: json['ExternalChannelId'] as String?, + channelName: json['ChannelName'] as String?, + channelPrimaryImageTag: json['ChannelPrimaryImageTag'] as String?, + programId: json['ProgramId'] as String?, + externalProgramId: json['ExternalProgramId'] as String?, + name: json['Name'] as String?, + overview: json['Overview'] as String?, + startDate: json['StartDate'] == null + ? null + : DateTime.parse(json['StartDate'] as String), + endDate: json['EndDate'] == null + ? null + : DateTime.parse(json['EndDate'] as String), + serviceName: json['ServiceName'] as String?, + priority: (json['Priority'] as num?)?.toInt(), + prePaddingSeconds: (json['PrePaddingSeconds'] as num?)?.toInt(), + postPaddingSeconds: (json['PostPaddingSeconds'] as num?)?.toInt(), + isPrePaddingRequired: json['IsPrePaddingRequired'] as bool?, + parentBackdropItemId: json['ParentBackdropItemId'] as String?, + parentBackdropImageTags: + (json['ParentBackdropImageTags'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + isPostPaddingRequired: json['IsPostPaddingRequired'] as bool?, + keepUntil: keepUntilNullableFromJson(json['KeepUntil']), + recordAnyTime: json['RecordAnyTime'] as bool?, + skipEpisodesInLibrary: json['SkipEpisodesInLibrary'] as bool?, + recordAnyChannel: json['RecordAnyChannel'] as bool?, + keepUpTo: (json['KeepUpTo'] as num?)?.toInt(), + recordNewOnly: json['RecordNewOnly'] as bool?, + days: dayOfWeekListFromJson(json['Days'] as List?), + dayPattern: dayPatternNullableFromJson(json['DayPattern']), + imageTags: json['ImageTags'] as Map?, + parentThumbItemId: json['ParentThumbItemId'] as String?, + parentThumbImageTag: json['ParentThumbImageTag'] as String?, + parentPrimaryImageItemId: json['ParentPrimaryImageItemId'] as String?, + parentPrimaryImageTag: json['ParentPrimaryImageTag'] as String?, + ); + +Map _$SeriesTimerInfoDtoToJson(SeriesTimerInfoDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Id', instance.id); + writeNotNull('Type', instance.type); + writeNotNull('ServerId', instance.serverId); + writeNotNull('ExternalId', instance.externalId); + writeNotNull('ChannelId', instance.channelId); + writeNotNull('ExternalChannelId', instance.externalChannelId); + writeNotNull('ChannelName', instance.channelName); + writeNotNull('ChannelPrimaryImageTag', instance.channelPrimaryImageTag); + writeNotNull('ProgramId', instance.programId); + writeNotNull('ExternalProgramId', instance.externalProgramId); + writeNotNull('Name', instance.name); + writeNotNull('Overview', instance.overview); + writeNotNull('StartDate', instance.startDate?.toIso8601String()); + writeNotNull('EndDate', instance.endDate?.toIso8601String()); + writeNotNull('ServiceName', instance.serviceName); + writeNotNull('Priority', instance.priority); + writeNotNull('PrePaddingSeconds', instance.prePaddingSeconds); + writeNotNull('PostPaddingSeconds', instance.postPaddingSeconds); + writeNotNull('IsPrePaddingRequired', instance.isPrePaddingRequired); + writeNotNull('ParentBackdropItemId', instance.parentBackdropItemId); + writeNotNull('ParentBackdropImageTags', instance.parentBackdropImageTags); + writeNotNull('IsPostPaddingRequired', instance.isPostPaddingRequired); + writeNotNull('KeepUntil', keepUntilNullableToJson(instance.keepUntil)); + writeNotNull('RecordAnyTime', instance.recordAnyTime); + writeNotNull('SkipEpisodesInLibrary', instance.skipEpisodesInLibrary); + writeNotNull('RecordAnyChannel', instance.recordAnyChannel); + writeNotNull('KeepUpTo', instance.keepUpTo); + writeNotNull('RecordNewOnly', instance.recordNewOnly); + val['Days'] = dayOfWeekListToJson(instance.days); + writeNotNull('DayPattern', dayPatternNullableToJson(instance.dayPattern)); + writeNotNull('ImageTags', instance.imageTags); + writeNotNull('ParentThumbItemId', instance.parentThumbItemId); + writeNotNull('ParentThumbImageTag', instance.parentThumbImageTag); + writeNotNull('ParentPrimaryImageItemId', instance.parentPrimaryImageItemId); + writeNotNull('ParentPrimaryImageTag', instance.parentPrimaryImageTag); + return val; +} + +SeriesTimerInfoDtoQueryResult _$SeriesTimerInfoDtoQueryResultFromJson( + Map json) => + SeriesTimerInfoDtoQueryResult( + items: (json['Items'] as List?) + ?.map( + (e) => SeriesTimerInfoDto.fromJson(e as Map)) + .toList() ?? + [], + totalRecordCount: (json['TotalRecordCount'] as num?)?.toInt(), + startIndex: (json['StartIndex'] as num?)?.toInt(), + ); + +Map _$SeriesTimerInfoDtoQueryResultToJson( + SeriesTimerInfoDtoQueryResult instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Items', instance.items?.map((e) => e.toJson()).toList()); + writeNotNull('TotalRecordCount', instance.totalRecordCount); + writeNotNull('StartIndex', instance.startIndex); + return val; +} + +ServerConfiguration _$ServerConfigurationFromJson(Map json) => + ServerConfiguration( + logFileRetentionDays: (json['LogFileRetentionDays'] as num?)?.toInt(), + isStartupWizardCompleted: json['IsStartupWizardCompleted'] as bool?, + cachePath: json['CachePath'] as String?, + previousVersion: json['PreviousVersion'] as String?, + previousVersionStr: json['PreviousVersionStr'] as String?, + enableMetrics: json['EnableMetrics'] as bool?, + enableNormalizedItemByNameIds: + json['EnableNormalizedItemByNameIds'] as bool?, + isPortAuthorized: json['IsPortAuthorized'] as bool?, + quickConnectAvailable: json['QuickConnectAvailable'] as bool?, + enableCaseSensitiveItemIds: json['EnableCaseSensitiveItemIds'] as bool?, + disableLiveTvChannelUserDataName: + json['DisableLiveTvChannelUserDataName'] as bool?, + metadataPath: json['MetadataPath'] as String?, + metadataNetworkPath: json['MetadataNetworkPath'] as String?, + preferredMetadataLanguage: json['PreferredMetadataLanguage'] as String?, + metadataCountryCode: json['MetadataCountryCode'] as String?, + sortReplaceCharacters: (json['SortReplaceCharacters'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + sortRemoveCharacters: (json['SortRemoveCharacters'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + sortRemoveWords: (json['SortRemoveWords'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + minResumePct: (json['MinResumePct'] as num?)?.toInt(), + maxResumePct: (json['MaxResumePct'] as num?)?.toInt(), + minResumeDurationSeconds: + (json['MinResumeDurationSeconds'] as num?)?.toInt(), + minAudiobookResume: (json['MinAudiobookResume'] as num?)?.toInt(), + maxAudiobookResume: (json['MaxAudiobookResume'] as num?)?.toInt(), + inactiveSessionThreshold: + (json['InactiveSessionThreshold'] as num?)?.toInt(), + libraryMonitorDelay: (json['LibraryMonitorDelay'] as num?)?.toInt(), + libraryUpdateDuration: (json['LibraryUpdateDuration'] as num?)?.toInt(), + imageSavingConvention: + imageSavingConventionNullableFromJson(json['ImageSavingConvention']), + metadataOptions: (json['MetadataOptions'] as List?) + ?.map((e) => MetadataOptions.fromJson(e as Map)) + .toList() ?? + [], + skipDeserializationForBasicTypes: + json['SkipDeserializationForBasicTypes'] as bool?, + serverName: json['ServerName'] as String?, + uICulture: json['UICulture'] as String?, + saveMetadataHidden: json['SaveMetadataHidden'] as bool?, + contentTypes: (json['ContentTypes'] as List?) + ?.map((e) => NameValuePair.fromJson(e as Map)) + .toList() ?? + [], + remoteClientBitrateLimit: + (json['RemoteClientBitrateLimit'] as num?)?.toInt(), + enableFolderView: json['EnableFolderView'] as bool?, + enableGroupingIntoCollections: + json['EnableGroupingIntoCollections'] as bool?, + displaySpecialsWithinSeasons: + json['DisplaySpecialsWithinSeasons'] as bool?, + codecsUsed: (json['CodecsUsed'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + pluginRepositories: (json['PluginRepositories'] as List?) + ?.map((e) => RepositoryInfo.fromJson(e as Map)) + .toList() ?? + [], + enableExternalContentInSuggestions: + json['EnableExternalContentInSuggestions'] as bool?, + imageExtractionTimeoutMs: + (json['ImageExtractionTimeoutMs'] as num?)?.toInt(), + pathSubstitutions: (json['PathSubstitutions'] as List?) + ?.map((e) => PathSubstitution.fromJson(e as Map)) + .toList() ?? + [], + enableSlowResponseWarning: json['EnableSlowResponseWarning'] as bool?, + slowResponseThresholdMs: + (json['SlowResponseThresholdMs'] as num?)?.toInt(), + corsHosts: (json['CorsHosts'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + activityLogRetentionDays: + (json['ActivityLogRetentionDays'] as num?)?.toInt(), + libraryScanFanoutConcurrency: + (json['LibraryScanFanoutConcurrency'] as num?)?.toInt(), + libraryMetadataRefreshConcurrency: + (json['LibraryMetadataRefreshConcurrency'] as num?)?.toInt(), + removeOldPlugins: json['RemoveOldPlugins'] as bool?, + allowClientLogUpload: json['AllowClientLogUpload'] as bool?, + dummyChapterDuration: (json['DummyChapterDuration'] as num?)?.toInt(), + chapterImageResolution: + imageResolutionNullableFromJson(json['ChapterImageResolution']), + parallelImageEncodingLimit: + (json['ParallelImageEncodingLimit'] as num?)?.toInt(), + castReceiverApplications: (json['CastReceiverApplications'] + as List?) + ?.map((e) => + CastReceiverApplication.fromJson(e as Map)) + .toList() ?? + [], + trickplayOptions: json['TrickplayOptions'] == null + ? null + : TrickplayOptions.fromJson( + json['TrickplayOptions'] as Map), + ); + +Map _$ServerConfigurationToJson(ServerConfiguration instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('LogFileRetentionDays', instance.logFileRetentionDays); + writeNotNull('IsStartupWizardCompleted', instance.isStartupWizardCompleted); + writeNotNull('CachePath', instance.cachePath); + writeNotNull('PreviousVersion', instance.previousVersion); + writeNotNull('PreviousVersionStr', instance.previousVersionStr); + writeNotNull('EnableMetrics', instance.enableMetrics); + writeNotNull( + 'EnableNormalizedItemByNameIds', instance.enableNormalizedItemByNameIds); + writeNotNull('IsPortAuthorized', instance.isPortAuthorized); + writeNotNull('QuickConnectAvailable', instance.quickConnectAvailable); + writeNotNull( + 'EnableCaseSensitiveItemIds', instance.enableCaseSensitiveItemIds); + writeNotNull('DisableLiveTvChannelUserDataName', + instance.disableLiveTvChannelUserDataName); + writeNotNull('MetadataPath', instance.metadataPath); + writeNotNull('MetadataNetworkPath', instance.metadataNetworkPath); + writeNotNull('PreferredMetadataLanguage', instance.preferredMetadataLanguage); + writeNotNull('MetadataCountryCode', instance.metadataCountryCode); + writeNotNull('SortReplaceCharacters', instance.sortReplaceCharacters); + writeNotNull('SortRemoveCharacters', instance.sortRemoveCharacters); + writeNotNull('SortRemoveWords', instance.sortRemoveWords); + writeNotNull('MinResumePct', instance.minResumePct); + writeNotNull('MaxResumePct', instance.maxResumePct); + writeNotNull('MinResumeDurationSeconds', instance.minResumeDurationSeconds); + writeNotNull('MinAudiobookResume', instance.minAudiobookResume); + writeNotNull('MaxAudiobookResume', instance.maxAudiobookResume); + writeNotNull('InactiveSessionThreshold', instance.inactiveSessionThreshold); + writeNotNull('LibraryMonitorDelay', instance.libraryMonitorDelay); + writeNotNull('LibraryUpdateDuration', instance.libraryUpdateDuration); + writeNotNull('ImageSavingConvention', + imageSavingConventionNullableToJson(instance.imageSavingConvention)); + writeNotNull('MetadataOptions', + instance.metadataOptions?.map((e) => e.toJson()).toList()); + writeNotNull('SkipDeserializationForBasicTypes', + instance.skipDeserializationForBasicTypes); + writeNotNull('ServerName', instance.serverName); + writeNotNull('UICulture', instance.uICulture); + writeNotNull('SaveMetadataHidden', instance.saveMetadataHidden); + writeNotNull( + 'ContentTypes', instance.contentTypes?.map((e) => e.toJson()).toList()); + writeNotNull('RemoteClientBitrateLimit', instance.remoteClientBitrateLimit); + writeNotNull('EnableFolderView', instance.enableFolderView); + writeNotNull( + 'EnableGroupingIntoCollections', instance.enableGroupingIntoCollections); + writeNotNull( + 'DisplaySpecialsWithinSeasons', instance.displaySpecialsWithinSeasons); + writeNotNull('CodecsUsed', instance.codecsUsed); + writeNotNull('PluginRepositories', + instance.pluginRepositories?.map((e) => e.toJson()).toList()); + writeNotNull('EnableExternalContentInSuggestions', + instance.enableExternalContentInSuggestions); + writeNotNull('ImageExtractionTimeoutMs', instance.imageExtractionTimeoutMs); + writeNotNull('PathSubstitutions', + instance.pathSubstitutions?.map((e) => e.toJson()).toList()); + writeNotNull('EnableSlowResponseWarning', instance.enableSlowResponseWarning); + writeNotNull('SlowResponseThresholdMs', instance.slowResponseThresholdMs); + writeNotNull('CorsHosts', instance.corsHosts); + writeNotNull('ActivityLogRetentionDays', instance.activityLogRetentionDays); + writeNotNull( + 'LibraryScanFanoutConcurrency', instance.libraryScanFanoutConcurrency); + writeNotNull('LibraryMetadataRefreshConcurrency', + instance.libraryMetadataRefreshConcurrency); + writeNotNull('RemoveOldPlugins', instance.removeOldPlugins); + writeNotNull('AllowClientLogUpload', instance.allowClientLogUpload); + writeNotNull('DummyChapterDuration', instance.dummyChapterDuration); + writeNotNull('ChapterImageResolution', + imageResolutionNullableToJson(instance.chapterImageResolution)); + writeNotNull( + 'ParallelImageEncodingLimit', instance.parallelImageEncodingLimit); + writeNotNull('CastReceiverApplications', + instance.castReceiverApplications?.map((e) => e.toJson()).toList()); + writeNotNull('TrickplayOptions', instance.trickplayOptions?.toJson()); + return val; +} + +ServerDiscoveryInfo _$ServerDiscoveryInfoFromJson(Map json) => + ServerDiscoveryInfo( + address: json['Address'] as String?, + id: json['Id'] as String?, + name: json['Name'] as String?, + endpointAddress: json['EndpointAddress'] as String?, + ); + +Map _$ServerDiscoveryInfoToJson(ServerDiscoveryInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Address', instance.address); + writeNotNull('Id', instance.id); + writeNotNull('Name', instance.name); + writeNotNull('EndpointAddress', instance.endpointAddress); + return val; +} + +ServerRestartingMessage _$ServerRestartingMessageFromJson( + Map json) => + ServerRestartingMessage( + messageId: json['MessageId'] as String?, + messageType: + ServerRestartingMessage.sessionMessageTypeMessageTypeNullableFromJson( + json['MessageType']), + ); + +Map _$ServerRestartingMessageToJson( + ServerRestartingMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +ServerShuttingDownMessage _$ServerShuttingDownMessageFromJson( + Map json) => + ServerShuttingDownMessage( + messageId: json['MessageId'] as String?, + messageType: ServerShuttingDownMessage + .sessionMessageTypeMessageTypeNullableFromJson(json['MessageType']), + ); + +Map _$ServerShuttingDownMessageToJson( + ServerShuttingDownMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +SessionInfo _$SessionInfoFromJson(Map json) => SessionInfo( + playState: json['PlayState'] == null + ? null + : PlayerStateInfo.fromJson(json['PlayState'] as Map), + additionalUsers: (json['AdditionalUsers'] as List?) + ?.map((e) => SessionUserInfo.fromJson(e as Map)) + .toList() ?? + [], + capabilities: json['Capabilities'] == null + ? null + : ClientCapabilities.fromJson( + json['Capabilities'] as Map), + remoteEndPoint: json['RemoteEndPoint'] as String?, + playableMediaTypes: + mediaTypeListFromJson(json['PlayableMediaTypes'] as List?), + id: json['Id'] as String?, + userId: json['UserId'] as String?, + userName: json['UserName'] as String?, + $Client: json['Client'] as String?, + lastActivityDate: json['LastActivityDate'] == null + ? null + : DateTime.parse(json['LastActivityDate'] as String), + lastPlaybackCheckIn: json['LastPlaybackCheckIn'] == null + ? null + : DateTime.parse(json['LastPlaybackCheckIn'] as String), + lastPausedDate: json['LastPausedDate'] == null + ? null + : DateTime.parse(json['LastPausedDate'] as String), + deviceName: json['DeviceName'] as String?, + deviceType: json['DeviceType'] as String?, + nowPlayingItem: json['NowPlayingItem'] == null + ? null + : BaseItemDto.fromJson( + json['NowPlayingItem'] as Map), + nowViewingItem: json['NowViewingItem'] == null + ? null + : BaseItemDto.fromJson( + json['NowViewingItem'] as Map), + deviceId: json['DeviceId'] as String?, + applicationVersion: json['ApplicationVersion'] as String?, + transcodingInfo: json['TranscodingInfo'] == null + ? null + : TranscodingInfo.fromJson( + json['TranscodingInfo'] as Map), + isActive: json['IsActive'] as bool?, + supportsMediaControl: json['SupportsMediaControl'] as bool?, + supportsRemoteControl: json['SupportsRemoteControl'] as bool?, + nowPlayingQueue: (json['NowPlayingQueue'] as List?) + ?.map((e) => QueueItem.fromJson(e as Map)) + .toList() ?? + [], + nowPlayingQueueFullItems: + (json['NowPlayingQueueFullItems'] as List?) + ?.map((e) => BaseItemDto.fromJson(e as Map)) + .toList() ?? + [], + hasCustomDeviceName: json['HasCustomDeviceName'] as bool?, + playlistItemId: json['PlaylistItemId'] as String?, + serverId: json['ServerId'] as String?, + userPrimaryImageTag: json['UserPrimaryImageTag'] as String?, + supportedCommands: + generalCommandTypeListFromJson(json['SupportedCommands'] as List?), + ); + +Map _$SessionInfoToJson(SessionInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('PlayState', instance.playState?.toJson()); + writeNotNull('AdditionalUsers', + instance.additionalUsers?.map((e) => e.toJson()).toList()); + writeNotNull('Capabilities', instance.capabilities?.toJson()); + writeNotNull('RemoteEndPoint', instance.remoteEndPoint); + val['PlayableMediaTypes'] = mediaTypeListToJson(instance.playableMediaTypes); + writeNotNull('Id', instance.id); + writeNotNull('UserId', instance.userId); + writeNotNull('UserName', instance.userName); + writeNotNull('Client', instance.$Client); + writeNotNull( + 'LastActivityDate', instance.lastActivityDate?.toIso8601String()); + writeNotNull( + 'LastPlaybackCheckIn', instance.lastPlaybackCheckIn?.toIso8601String()); + writeNotNull('LastPausedDate', instance.lastPausedDate?.toIso8601String()); + writeNotNull('DeviceName', instance.deviceName); + writeNotNull('DeviceType', instance.deviceType); + writeNotNull('NowPlayingItem', instance.nowPlayingItem?.toJson()); + writeNotNull('NowViewingItem', instance.nowViewingItem?.toJson()); + writeNotNull('DeviceId', instance.deviceId); + writeNotNull('ApplicationVersion', instance.applicationVersion); + writeNotNull('TranscodingInfo', instance.transcodingInfo?.toJson()); + writeNotNull('IsActive', instance.isActive); + writeNotNull('SupportsMediaControl', instance.supportsMediaControl); + writeNotNull('SupportsRemoteControl', instance.supportsRemoteControl); + writeNotNull('NowPlayingQueue', + instance.nowPlayingQueue?.map((e) => e.toJson()).toList()); + writeNotNull('NowPlayingQueueFullItems', + instance.nowPlayingQueueFullItems?.map((e) => e.toJson()).toList()); + writeNotNull('HasCustomDeviceName', instance.hasCustomDeviceName); + writeNotNull('PlaylistItemId', instance.playlistItemId); + writeNotNull('ServerId', instance.serverId); + writeNotNull('UserPrimaryImageTag', instance.userPrimaryImageTag); + val['SupportedCommands'] = + generalCommandTypeListToJson(instance.supportedCommands); + return val; +} + +SessionsMessage _$SessionsMessageFromJson(Map json) => + SessionsMessage( + data: (json['Data'] as List?) + ?.map((e) => SessionInfo.fromJson(e as Map)) + .toList() ?? + [], + messageId: json['MessageId'] as String?, + messageType: + SessionsMessage.sessionMessageTypeMessageTypeNullableFromJson( + json['MessageType']), + ); + +Map _$SessionsMessageToJson(SessionsMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Data', instance.data?.map((e) => e.toJson()).toList()); + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +SessionsStartMessage _$SessionsStartMessageFromJson( + Map json) => + SessionsStartMessage( + data: json['Data'] as String?, + messageType: + SessionsStartMessage.sessionMessageTypeMessageTypeNullableFromJson( + json['MessageType']), + ); + +Map _$SessionsStartMessageToJson( + SessionsStartMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Data', instance.data); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +SessionsStopMessage _$SessionsStopMessageFromJson(Map json) => + SessionsStopMessage( + messageType: + SessionsStopMessage.sessionMessageTypeMessageTypeNullableFromJson( + json['MessageType']), + ); + +Map _$SessionsStopMessageToJson(SessionsStopMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +SessionUserInfo _$SessionUserInfoFromJson(Map json) => + SessionUserInfo( + userId: json['UserId'] as String?, + userName: json['UserName'] as String?, + ); + +Map _$SessionUserInfoToJson(SessionUserInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('UserId', instance.userId); + writeNotNull('UserName', instance.userName); + return val; +} + +SetChannelMappingDto _$SetChannelMappingDtoFromJson( + Map json) => + SetChannelMappingDto( + providerId: json['ProviderId'] as String, + tunerChannelId: json['TunerChannelId'] as String, + providerChannelId: json['ProviderChannelId'] as String, + ); + +Map _$SetChannelMappingDtoToJson( + SetChannelMappingDto instance) => + { + 'ProviderId': instance.providerId, + 'TunerChannelId': instance.tunerChannelId, + 'ProviderChannelId': instance.providerChannelId, + }; + +SetPlaylistItemRequestDto _$SetPlaylistItemRequestDtoFromJson( + Map json) => + SetPlaylistItemRequestDto( + playlistItemId: json['PlaylistItemId'] as String?, + ); + +Map _$SetPlaylistItemRequestDtoToJson( + SetPlaylistItemRequestDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('PlaylistItemId', instance.playlistItemId); + return val; +} + +SetRepeatModeRequestDto _$SetRepeatModeRequestDtoFromJson( + Map json) => + SetRepeatModeRequestDto( + mode: groupRepeatModeNullableFromJson(json['Mode']), + ); + +Map _$SetRepeatModeRequestDtoToJson( + SetRepeatModeRequestDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Mode', groupRepeatModeNullableToJson(instance.mode)); + return val; +} + +SetShuffleModeRequestDto _$SetShuffleModeRequestDtoFromJson( + Map json) => + SetShuffleModeRequestDto( + mode: groupShuffleModeNullableFromJson(json['Mode']), + ); + +Map _$SetShuffleModeRequestDtoToJson( + SetShuffleModeRequestDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Mode', groupShuffleModeNullableToJson(instance.mode)); + return val; +} + +SongInfo _$SongInfoFromJson(Map json) => SongInfo( + name: json['Name'] as String?, + originalTitle: json['OriginalTitle'] as String?, + path: json['Path'] as String?, + metadataLanguage: json['MetadataLanguage'] as String?, + metadataCountryCode: json['MetadataCountryCode'] as String?, + providerIds: json['ProviderIds'] as Map?, + year: (json['Year'] as num?)?.toInt(), + indexNumber: (json['IndexNumber'] as num?)?.toInt(), + parentIndexNumber: (json['ParentIndexNumber'] as num?)?.toInt(), + premiereDate: json['PremiereDate'] == null + ? null + : DateTime.parse(json['PremiereDate'] as String), + isAutomated: json['IsAutomated'] as bool?, + albumArtists: (json['AlbumArtists'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + album: json['Album'] as String?, + artists: (json['Artists'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + ); + +Map _$SongInfoToJson(SongInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('OriginalTitle', instance.originalTitle); + writeNotNull('Path', instance.path); + writeNotNull('MetadataLanguage', instance.metadataLanguage); + writeNotNull('MetadataCountryCode', instance.metadataCountryCode); + writeNotNull('ProviderIds', instance.providerIds); + writeNotNull('Year', instance.year); + writeNotNull('IndexNumber', instance.indexNumber); + writeNotNull('ParentIndexNumber', instance.parentIndexNumber); + writeNotNull('PremiereDate', instance.premiereDate?.toIso8601String()); + writeNotNull('IsAutomated', instance.isAutomated); + writeNotNull('AlbumArtists', instance.albumArtists); + writeNotNull('Album', instance.album); + writeNotNull('Artists', instance.artists); + return val; +} + +SpecialViewOptionDto _$SpecialViewOptionDtoFromJson( + Map json) => + SpecialViewOptionDto( + name: json['Name'] as String?, + id: json['Id'] as String?, + ); + +Map _$SpecialViewOptionDtoToJson( + SpecialViewOptionDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('Id', instance.id); + return val; +} + +StartupConfigurationDto _$StartupConfigurationDtoFromJson( + Map json) => + StartupConfigurationDto( + uICulture: json['UICulture'] as String?, + metadataCountryCode: json['MetadataCountryCode'] as String?, + preferredMetadataLanguage: json['PreferredMetadataLanguage'] as String?, + ); + +Map _$StartupConfigurationDtoToJson( + StartupConfigurationDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('UICulture', instance.uICulture); + writeNotNull('MetadataCountryCode', instance.metadataCountryCode); + writeNotNull('PreferredMetadataLanguage', instance.preferredMetadataLanguage); + return val; +} + +StartupRemoteAccessDto _$StartupRemoteAccessDtoFromJson( + Map json) => + StartupRemoteAccessDto( + enableRemoteAccess: json['EnableRemoteAccess'] as bool, + enableAutomaticPortMapping: json['EnableAutomaticPortMapping'] as bool, + ); + +Map _$StartupRemoteAccessDtoToJson( + StartupRemoteAccessDto instance) => + { + 'EnableRemoteAccess': instance.enableRemoteAccess, + 'EnableAutomaticPortMapping': instance.enableAutomaticPortMapping, + }; + +StartupUserDto _$StartupUserDtoFromJson(Map json) => + StartupUserDto( + name: json['Name'] as String?, + password: json['Password'] as String?, + ); + +Map _$StartupUserDtoToJson(StartupUserDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('Password', instance.password); + return val; +} + +StringGroupUpdate _$StringGroupUpdateFromJson(Map json) => + StringGroupUpdate( + groupId: json['GroupId'] as String?, + type: groupUpdateTypeNullableFromJson(json['Type']), + data: json['Data'] as String?, + ); + +Map _$StringGroupUpdateToJson(StringGroupUpdate instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('GroupId', instance.groupId); + writeNotNull('Type', groupUpdateTypeNullableToJson(instance.type)); + writeNotNull('Data', instance.data); + return val; +} + +SubtitleOptions _$SubtitleOptionsFromJson(Map json) => + SubtitleOptions( + skipIfEmbeddedSubtitlesPresent: + json['SkipIfEmbeddedSubtitlesPresent'] as bool?, + skipIfAudioTrackMatches: json['SkipIfAudioTrackMatches'] as bool?, + downloadLanguages: (json['DownloadLanguages'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + downloadMovieSubtitles: json['DownloadMovieSubtitles'] as bool?, + downloadEpisodeSubtitles: json['DownloadEpisodeSubtitles'] as bool?, + openSubtitlesUsername: json['OpenSubtitlesUsername'] as String?, + openSubtitlesPasswordHash: json['OpenSubtitlesPasswordHash'] as String?, + isOpenSubtitleVipAccount: json['IsOpenSubtitleVipAccount'] as bool?, + requirePerfectMatch: json['RequirePerfectMatch'] as bool?, + ); + +Map _$SubtitleOptionsToJson(SubtitleOptions instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('SkipIfEmbeddedSubtitlesPresent', + instance.skipIfEmbeddedSubtitlesPresent); + writeNotNull('SkipIfAudioTrackMatches', instance.skipIfAudioTrackMatches); + writeNotNull('DownloadLanguages', instance.downloadLanguages); + writeNotNull('DownloadMovieSubtitles', instance.downloadMovieSubtitles); + writeNotNull('DownloadEpisodeSubtitles', instance.downloadEpisodeSubtitles); + writeNotNull('OpenSubtitlesUsername', instance.openSubtitlesUsername); + writeNotNull('OpenSubtitlesPasswordHash', instance.openSubtitlesPasswordHash); + writeNotNull('IsOpenSubtitleVipAccount', instance.isOpenSubtitleVipAccount); + writeNotNull('RequirePerfectMatch', instance.requirePerfectMatch); + return val; +} + +SubtitleProfile _$SubtitleProfileFromJson(Map json) => + SubtitleProfile( + format: json['Format'] as String?, + method: subtitleDeliveryMethodNullableFromJson(json['Method']), + didlMode: json['DidlMode'] as String?, + language: json['Language'] as String?, + container: json['Container'] as String?, + ); + +Map _$SubtitleProfileToJson(SubtitleProfile instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Format', instance.format); + writeNotNull('Method', subtitleDeliveryMethodNullableToJson(instance.method)); + writeNotNull('DidlMode', instance.didlMode); + writeNotNull('Language', instance.language); + writeNotNull('Container', instance.container); + return val; +} + +SyncPlayCommandMessage _$SyncPlayCommandMessageFromJson( + Map json) => + SyncPlayCommandMessage( + data: json['Data'] == null + ? null + : SendCommand.fromJson(json['Data'] as Map), + messageId: json['MessageId'] as String?, + messageType: + SyncPlayCommandMessage.sessionMessageTypeMessageTypeNullableFromJson( + json['MessageType']), + ); + +Map _$SyncPlayCommandMessageToJson( + SyncPlayCommandMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Data', instance.data?.toJson()); + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +SyncPlayGroupUpdateCommandMessage _$SyncPlayGroupUpdateCommandMessageFromJson( + Map json) => + SyncPlayGroupUpdateCommandMessage( + data: json['Data'] == null + ? null + : GroupUpdate.fromJson(json['Data'] as Map), + messageId: json['MessageId'] as String?, + messageType: SyncPlayGroupUpdateCommandMessage + .sessionMessageTypeMessageTypeNullableFromJson(json['MessageType']), + ); + +Map _$SyncPlayGroupUpdateCommandMessageToJson( + SyncPlayGroupUpdateCommandMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Data', instance.data?.toJson()); + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +SyncPlayQueueItem _$SyncPlayQueueItemFromJson(Map json) => + SyncPlayQueueItem( + itemId: json['ItemId'] as String?, + playlistItemId: json['PlaylistItemId'] as String?, + ); + +Map _$SyncPlayQueueItemToJson(SyncPlayQueueItem instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('ItemId', instance.itemId); + writeNotNull('PlaylistItemId', instance.playlistItemId); + return val; +} + +SystemInfo _$SystemInfoFromJson(Map json) => SystemInfo( + localAddress: json['LocalAddress'] as String?, + serverName: json['ServerName'] as String?, + version: json['Version'] as String?, + productName: json['ProductName'] as String?, + operatingSystem: json['OperatingSystem'] as String?, + id: json['Id'] as String?, + startupWizardCompleted: json['StartupWizardCompleted'] as bool?, + operatingSystemDisplayName: json['OperatingSystemDisplayName'] as String?, + packageName: json['PackageName'] as String?, + hasPendingRestart: json['HasPendingRestart'] as bool?, + isShuttingDown: json['IsShuttingDown'] as bool?, + supportsLibraryMonitor: json['SupportsLibraryMonitor'] as bool?, + webSocketPortNumber: (json['WebSocketPortNumber'] as num?)?.toInt(), + completedInstallations: (json['CompletedInstallations'] as List?) + ?.map((e) => InstallationInfo.fromJson(e as Map)) + .toList() ?? + [], + canSelfRestart: json['CanSelfRestart'] as bool? ?? true, + canLaunchWebBrowser: json['CanLaunchWebBrowser'] as bool? ?? false, + programDataPath: json['ProgramDataPath'] as String?, + webPath: json['WebPath'] as String?, + itemsByNamePath: json['ItemsByNamePath'] as String?, + cachePath: json['CachePath'] as String?, + logPath: json['LogPath'] as String?, + internalMetadataPath: json['InternalMetadataPath'] as String?, + transcodingTempPath: json['TranscodingTempPath'] as String?, + castReceiverApplications: (json['CastReceiverApplications'] + as List?) + ?.map((e) => + CastReceiverApplication.fromJson(e as Map)) + .toList() ?? + [], + hasUpdateAvailable: json['HasUpdateAvailable'] as bool? ?? false, + encoderLocation: json['EncoderLocation'] as String?, + systemArchitecture: json['SystemArchitecture'] as String?, + ); + +Map _$SystemInfoToJson(SystemInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('LocalAddress', instance.localAddress); + writeNotNull('ServerName', instance.serverName); + writeNotNull('Version', instance.version); + writeNotNull('ProductName', instance.productName); + writeNotNull('OperatingSystem', instance.operatingSystem); + writeNotNull('Id', instance.id); + writeNotNull('StartupWizardCompleted', instance.startupWizardCompleted); + writeNotNull( + 'OperatingSystemDisplayName', instance.operatingSystemDisplayName); + writeNotNull('PackageName', instance.packageName); + writeNotNull('HasPendingRestart', instance.hasPendingRestart); + writeNotNull('IsShuttingDown', instance.isShuttingDown); + writeNotNull('SupportsLibraryMonitor', instance.supportsLibraryMonitor); + writeNotNull('WebSocketPortNumber', instance.webSocketPortNumber); + writeNotNull('CompletedInstallations', + instance.completedInstallations?.map((e) => e.toJson()).toList()); + writeNotNull('CanSelfRestart', instance.canSelfRestart); + writeNotNull('CanLaunchWebBrowser', instance.canLaunchWebBrowser); + writeNotNull('ProgramDataPath', instance.programDataPath); + writeNotNull('WebPath', instance.webPath); + writeNotNull('ItemsByNamePath', instance.itemsByNamePath); + writeNotNull('CachePath', instance.cachePath); + writeNotNull('LogPath', instance.logPath); + writeNotNull('InternalMetadataPath', instance.internalMetadataPath); + writeNotNull('TranscodingTempPath', instance.transcodingTempPath); + writeNotNull('CastReceiverApplications', + instance.castReceiverApplications?.map((e) => e.toJson()).toList()); + writeNotNull('HasUpdateAvailable', instance.hasUpdateAvailable); + writeNotNull('EncoderLocation', instance.encoderLocation); + writeNotNull('SystemArchitecture', instance.systemArchitecture); + return val; +} + +TaskInfo _$TaskInfoFromJson(Map json) => TaskInfo( + name: json['Name'] as String?, + state: taskStateNullableFromJson(json['State']), + currentProgressPercentage: + (json['CurrentProgressPercentage'] as num?)?.toDouble(), + id: json['Id'] as String?, + lastExecutionResult: json['LastExecutionResult'] == null + ? null + : TaskResult.fromJson( + json['LastExecutionResult'] as Map), + triggers: (json['Triggers'] as List?) + ?.map((e) => TaskTriggerInfo.fromJson(e as Map)) + .toList() ?? + [], + description: json['Description'] as String?, + category: json['Category'] as String?, + isHidden: json['IsHidden'] as bool?, + key: json['Key'] as String?, + ); + +Map _$TaskInfoToJson(TaskInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('State', taskStateNullableToJson(instance.state)); + writeNotNull('CurrentProgressPercentage', instance.currentProgressPercentage); + writeNotNull('Id', instance.id); + writeNotNull('LastExecutionResult', instance.lastExecutionResult?.toJson()); + writeNotNull('Triggers', instance.triggers?.map((e) => e.toJson()).toList()); + writeNotNull('Description', instance.description); + writeNotNull('Category', instance.category); + writeNotNull('IsHidden', instance.isHidden); + writeNotNull('Key', instance.key); + return val; +} + +TaskResult _$TaskResultFromJson(Map json) => TaskResult( + startTimeUtc: json['StartTimeUtc'] == null + ? null + : DateTime.parse(json['StartTimeUtc'] as String), + endTimeUtc: json['EndTimeUtc'] == null + ? null + : DateTime.parse(json['EndTimeUtc'] as String), + status: taskCompletionStatusNullableFromJson(json['Status']), + name: json['Name'] as String?, + key: json['Key'] as String?, + id: json['Id'] as String?, + errorMessage: json['ErrorMessage'] as String?, + longErrorMessage: json['LongErrorMessage'] as String?, + ); + +Map _$TaskResultToJson(TaskResult instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('StartTimeUtc', instance.startTimeUtc?.toIso8601String()); + writeNotNull('EndTimeUtc', instance.endTimeUtc?.toIso8601String()); + writeNotNull('Status', taskCompletionStatusNullableToJson(instance.status)); + writeNotNull('Name', instance.name); + writeNotNull('Key', instance.key); + writeNotNull('Id', instance.id); + writeNotNull('ErrorMessage', instance.errorMessage); + writeNotNull('LongErrorMessage', instance.longErrorMessage); + return val; +} + +TaskTriggerInfo _$TaskTriggerInfoFromJson(Map json) => + TaskTriggerInfo( + type: json['Type'] as String?, + timeOfDayTicks: (json['TimeOfDayTicks'] as num?)?.toInt(), + intervalTicks: (json['IntervalTicks'] as num?)?.toInt(), + dayOfWeek: dayOfWeekNullableFromJson(json['DayOfWeek']), + maxRuntimeTicks: (json['MaxRuntimeTicks'] as num?)?.toInt(), + ); + +Map _$TaskTriggerInfoToJson(TaskTriggerInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Type', instance.type); + writeNotNull('TimeOfDayTicks', instance.timeOfDayTicks); + writeNotNull('IntervalTicks', instance.intervalTicks); + writeNotNull('DayOfWeek', dayOfWeekNullableToJson(instance.dayOfWeek)); + writeNotNull('MaxRuntimeTicks', instance.maxRuntimeTicks); + return val; +} + +ThemeMediaResult _$ThemeMediaResultFromJson(Map json) => + ThemeMediaResult( + items: (json['Items'] as List?) + ?.map((e) => BaseItemDto.fromJson(e as Map)) + .toList() ?? + [], + totalRecordCount: (json['TotalRecordCount'] as num?)?.toInt(), + startIndex: (json['StartIndex'] as num?)?.toInt(), + ownerId: json['OwnerId'] as String?, + ); + +Map _$ThemeMediaResultToJson(ThemeMediaResult instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Items', instance.items?.map((e) => e.toJson()).toList()); + writeNotNull('TotalRecordCount', instance.totalRecordCount); + writeNotNull('StartIndex', instance.startIndex); + writeNotNull('OwnerId', instance.ownerId); + return val; +} + +TimerCancelledMessage _$TimerCancelledMessageFromJson( + Map json) => + TimerCancelledMessage( + data: json['Data'] == null + ? null + : TimerEventInfo.fromJson(json['Data'] as Map), + messageId: json['MessageId'] as String?, + messageType: + TimerCancelledMessage.sessionMessageTypeMessageTypeNullableFromJson( + json['MessageType']), + ); + +Map _$TimerCancelledMessageToJson( + TimerCancelledMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Data', instance.data?.toJson()); + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +TimerCreatedMessage _$TimerCreatedMessageFromJson(Map json) => + TimerCreatedMessage( + data: json['Data'] == null + ? null + : TimerEventInfo.fromJson(json['Data'] as Map), + messageId: json['MessageId'] as String?, + messageType: + TimerCreatedMessage.sessionMessageTypeMessageTypeNullableFromJson( + json['MessageType']), + ); + +Map _$TimerCreatedMessageToJson(TimerCreatedMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Data', instance.data?.toJson()); + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +TimerEventInfo _$TimerEventInfoFromJson(Map json) => + TimerEventInfo( + id: json['Id'] as String?, + programId: json['ProgramId'] as String?, + ); + +Map _$TimerEventInfoToJson(TimerEventInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Id', instance.id); + writeNotNull('ProgramId', instance.programId); + return val; +} + +TimerInfoDto _$TimerInfoDtoFromJson(Map json) => TimerInfoDto( + id: json['Id'] as String?, + type: json['Type'] as String?, + serverId: json['ServerId'] as String?, + externalId: json['ExternalId'] as String?, + channelId: json['ChannelId'] as String?, + externalChannelId: json['ExternalChannelId'] as String?, + channelName: json['ChannelName'] as String?, + channelPrimaryImageTag: json['ChannelPrimaryImageTag'] as String?, + programId: json['ProgramId'] as String?, + externalProgramId: json['ExternalProgramId'] as String?, + name: json['Name'] as String?, + overview: json['Overview'] as String?, + startDate: json['StartDate'] == null + ? null + : DateTime.parse(json['StartDate'] as String), + endDate: json['EndDate'] == null + ? null + : DateTime.parse(json['EndDate'] as String), + serviceName: json['ServiceName'] as String?, + priority: (json['Priority'] as num?)?.toInt(), + prePaddingSeconds: (json['PrePaddingSeconds'] as num?)?.toInt(), + postPaddingSeconds: (json['PostPaddingSeconds'] as num?)?.toInt(), + isPrePaddingRequired: json['IsPrePaddingRequired'] as bool?, + parentBackdropItemId: json['ParentBackdropItemId'] as String?, + parentBackdropImageTags: + (json['ParentBackdropImageTags'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + isPostPaddingRequired: json['IsPostPaddingRequired'] as bool?, + keepUntil: keepUntilNullableFromJson(json['KeepUntil']), + status: recordingStatusNullableFromJson(json['Status']), + seriesTimerId: json['SeriesTimerId'] as String?, + externalSeriesTimerId: json['ExternalSeriesTimerId'] as String?, + runTimeTicks: (json['RunTimeTicks'] as num?)?.toInt(), + programInfo: json['ProgramInfo'] == null + ? null + : BaseItemDto.fromJson(json['ProgramInfo'] as Map), + ); + +Map _$TimerInfoDtoToJson(TimerInfoDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Id', instance.id); + writeNotNull('Type', instance.type); + writeNotNull('ServerId', instance.serverId); + writeNotNull('ExternalId', instance.externalId); + writeNotNull('ChannelId', instance.channelId); + writeNotNull('ExternalChannelId', instance.externalChannelId); + writeNotNull('ChannelName', instance.channelName); + writeNotNull('ChannelPrimaryImageTag', instance.channelPrimaryImageTag); + writeNotNull('ProgramId', instance.programId); + writeNotNull('ExternalProgramId', instance.externalProgramId); + writeNotNull('Name', instance.name); + writeNotNull('Overview', instance.overview); + writeNotNull('StartDate', instance.startDate?.toIso8601String()); + writeNotNull('EndDate', instance.endDate?.toIso8601String()); + writeNotNull('ServiceName', instance.serviceName); + writeNotNull('Priority', instance.priority); + writeNotNull('PrePaddingSeconds', instance.prePaddingSeconds); + writeNotNull('PostPaddingSeconds', instance.postPaddingSeconds); + writeNotNull('IsPrePaddingRequired', instance.isPrePaddingRequired); + writeNotNull('ParentBackdropItemId', instance.parentBackdropItemId); + writeNotNull('ParentBackdropImageTags', instance.parentBackdropImageTags); + writeNotNull('IsPostPaddingRequired', instance.isPostPaddingRequired); + writeNotNull('KeepUntil', keepUntilNullableToJson(instance.keepUntil)); + writeNotNull('Status', recordingStatusNullableToJson(instance.status)); + writeNotNull('SeriesTimerId', instance.seriesTimerId); + writeNotNull('ExternalSeriesTimerId', instance.externalSeriesTimerId); + writeNotNull('RunTimeTicks', instance.runTimeTicks); + writeNotNull('ProgramInfo', instance.programInfo?.toJson()); + return val; +} + +TimerInfoDtoQueryResult _$TimerInfoDtoQueryResultFromJson( + Map json) => + TimerInfoDtoQueryResult( + items: (json['Items'] as List?) + ?.map((e) => TimerInfoDto.fromJson(e as Map)) + .toList() ?? + [], + totalRecordCount: (json['TotalRecordCount'] as num?)?.toInt(), + startIndex: (json['StartIndex'] as num?)?.toInt(), + ); + +Map _$TimerInfoDtoQueryResultToJson( + TimerInfoDtoQueryResult instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Items', instance.items?.map((e) => e.toJson()).toList()); + writeNotNull('TotalRecordCount', instance.totalRecordCount); + writeNotNull('StartIndex', instance.startIndex); + return val; +} + +TrailerInfo _$TrailerInfoFromJson(Map json) => TrailerInfo( + name: json['Name'] as String?, + originalTitle: json['OriginalTitle'] as String?, + path: json['Path'] as String?, + metadataLanguage: json['MetadataLanguage'] as String?, + metadataCountryCode: json['MetadataCountryCode'] as String?, + providerIds: json['ProviderIds'] as Map?, + year: (json['Year'] as num?)?.toInt(), + indexNumber: (json['IndexNumber'] as num?)?.toInt(), + parentIndexNumber: (json['ParentIndexNumber'] as num?)?.toInt(), + premiereDate: json['PremiereDate'] == null + ? null + : DateTime.parse(json['PremiereDate'] as String), + isAutomated: json['IsAutomated'] as bool?, + ); + +Map _$TrailerInfoToJson(TrailerInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('OriginalTitle', instance.originalTitle); + writeNotNull('Path', instance.path); + writeNotNull('MetadataLanguage', instance.metadataLanguage); + writeNotNull('MetadataCountryCode', instance.metadataCountryCode); + writeNotNull('ProviderIds', instance.providerIds); + writeNotNull('Year', instance.year); + writeNotNull('IndexNumber', instance.indexNumber); + writeNotNull('ParentIndexNumber', instance.parentIndexNumber); + writeNotNull('PremiereDate', instance.premiereDate?.toIso8601String()); + writeNotNull('IsAutomated', instance.isAutomated); + return val; +} + +TrailerInfoRemoteSearchQuery _$TrailerInfoRemoteSearchQueryFromJson( + Map json) => + TrailerInfoRemoteSearchQuery( + searchInfo: json['SearchInfo'] == null + ? null + : TrailerInfo.fromJson(json['SearchInfo'] as Map), + itemId: json['ItemId'] as String?, + searchProviderName: json['SearchProviderName'] as String?, + includeDisabledProviders: json['IncludeDisabledProviders'] as bool?, + ); + +Map _$TrailerInfoRemoteSearchQueryToJson( + TrailerInfoRemoteSearchQuery instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('SearchInfo', instance.searchInfo?.toJson()); + writeNotNull('ItemId', instance.itemId); + writeNotNull('SearchProviderName', instance.searchProviderName); + writeNotNull('IncludeDisabledProviders', instance.includeDisabledProviders); + return val; +} + +TraktEpisode _$TraktEpisodeFromJson(Map json) => TraktEpisode( + season: (json['season'] as num?)?.toInt(), + number: (json['number'] as num?)?.toInt(), + title: json['title'] as String?, + ids: json['ids'] == null + ? null + : TraktEpisodeId.fromJson(json['ids'] as Map), + ); + +Map _$TraktEpisodeToJson(TraktEpisode instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('season', instance.season); + writeNotNull('number', instance.number); + writeNotNull('title', instance.title); + writeNotNull('ids', instance.ids?.toJson()); + return val; +} + +TraktEpisodeId _$TraktEpisodeIdFromJson(Map json) => + TraktEpisodeId( + trakt: (json['trakt'] as num?)?.toInt(), + slug: json['slug'] as String?, + imdb: json['imdb'] as String?, + tmdb: (json['tmdb'] as num?)?.toInt(), + tvdb: json['tvdb'] as String?, + tvrage: json['tvrage'] as String?, + ); + +Map _$TraktEpisodeIdToJson(TraktEpisodeId instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('trakt', instance.trakt); + writeNotNull('slug', instance.slug); + writeNotNull('imdb', instance.imdb); + writeNotNull('tmdb', instance.tmdb); + writeNotNull('tvdb', instance.tvdb); + writeNotNull('tvrage', instance.tvrage); + return val; +} + +TraktMovie _$TraktMovieFromJson(Map json) => TraktMovie( + title: json['title'] as String?, + year: (json['year'] as num?)?.toInt(), + ids: json['ids'] == null + ? null + : TraktMovieId.fromJson(json['ids'] as Map), + ); + +Map _$TraktMovieToJson(TraktMovie instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('title', instance.title); + writeNotNull('year', instance.year); + writeNotNull('ids', instance.ids?.toJson()); + return val; +} + +TraktMovieId _$TraktMovieIdFromJson(Map json) => TraktMovieId( + trakt: (json['trakt'] as num?)?.toInt(), + slug: json['slug'] as String?, + imdb: json['imdb'] as String?, + tmdb: (json['tmdb'] as num?)?.toInt(), + ); + +Map _$TraktMovieIdToJson(TraktMovieId instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('trakt', instance.trakt); + writeNotNull('slug', instance.slug); + writeNotNull('imdb', instance.imdb); + writeNotNull('tmdb', instance.tmdb); + return val; +} + +TraktPerson _$TraktPersonFromJson(Map json) => TraktPerson( + name: json['name'] as String?, + ids: json['ids'] == null + ? null + : TraktPersonId.fromJson(json['ids'] as Map), + ); + +Map _$TraktPersonToJson(TraktPerson instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('name', instance.name); + writeNotNull('ids', instance.ids?.toJson()); + return val; +} + +TraktPersonId _$TraktPersonIdFromJson(Map json) => + TraktPersonId( + trakt: (json['trakt'] as num?)?.toInt(), + slug: json['slug'] as String?, + imdb: json['imdb'] as String?, + tmdb: (json['tmdb'] as num?)?.toInt(), + tvrage: (json['tvrage'] as num?)?.toInt(), + ); + +Map _$TraktPersonIdToJson(TraktPersonId instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('trakt', instance.trakt); + writeNotNull('slug', instance.slug); + writeNotNull('imdb', instance.imdb); + writeNotNull('tmdb', instance.tmdb); + writeNotNull('tvrage', instance.tvrage); + return val; +} + +TraktSeason _$TraktSeasonFromJson(Map json) => TraktSeason( + number: (json['number'] as num?)?.toInt(), + ids: json['ids'] == null + ? null + : TraktSeasonId.fromJson(json['ids'] as Map), + ); + +Map _$TraktSeasonToJson(TraktSeason instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('number', instance.number); + writeNotNull('ids', instance.ids?.toJson()); + return val; +} + +TraktSeasonId _$TraktSeasonIdFromJson(Map json) => + TraktSeasonId( + trakt: (json['trakt'] as num?)?.toInt(), + slug: json['slug'] as String?, + tmdb: (json['tmdb'] as num?)?.toInt(), + tvdb: (json['tvdb'] as num?)?.toInt(), + tvrage: (json['tvrage'] as num?)?.toInt(), + ); + +Map _$TraktSeasonIdToJson(TraktSeasonId instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('trakt', instance.trakt); + writeNotNull('slug', instance.slug); + writeNotNull('tmdb', instance.tmdb); + writeNotNull('tvdb', instance.tvdb); + writeNotNull('tvrage', instance.tvrage); + return val; +} + +TraktShow _$TraktShowFromJson(Map json) => TraktShow( + title: json['title'] as String?, + year: (json['year'] as num?)?.toInt(), + ids: json['ids'] == null + ? null + : TraktShowId.fromJson(json['ids'] as Map), + ); + +Map _$TraktShowToJson(TraktShow instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('title', instance.title); + writeNotNull('year', instance.year); + writeNotNull('ids', instance.ids?.toJson()); + return val; +} + +TraktShowId _$TraktShowIdFromJson(Map json) => TraktShowId( + trakt: (json['trakt'] as num?)?.toInt(), + slug: json['slug'] as String?, + imdb: json['imdb'] as String?, + tmdb: (json['tmdb'] as num?)?.toInt(), + tvdb: json['tvdb'] as String?, + tvrage: json['tvrage'] as String?, + ); + +Map _$TraktShowIdToJson(TraktShowId instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('trakt', instance.trakt); + writeNotNull('slug', instance.slug); + writeNotNull('imdb', instance.imdb); + writeNotNull('tmdb', instance.tmdb); + writeNotNull('tvdb', instance.tvdb); + writeNotNull('tvrage', instance.tvrage); + return val; +} + +TraktSyncResponse _$TraktSyncResponseFromJson(Map json) => + TraktSyncResponse( + added: json['added'] == null + ? null + : Items.fromJson(json['added'] as Map), + deleted: json['deleted'] == null + ? null + : Items.fromJson(json['deleted'] as Map), + updated: json['updated'] == null + ? null + : Items.fromJson(json['updated'] as Map), + notFound: json['not_found'] == null + ? null + : NotFoundObjects.fromJson(json['not_found'] as Map), + ); + +Map _$TraktSyncResponseToJson(TraktSyncResponse instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('added', instance.added?.toJson()); + writeNotNull('deleted', instance.deleted?.toJson()); + writeNotNull('updated', instance.updated?.toJson()); + writeNotNull('not_found', instance.notFound?.toJson()); + return val; +} + +TranscodingInfo _$TranscodingInfoFromJson(Map json) => + TranscodingInfo( + audioCodec: json['AudioCodec'] as String?, + videoCodec: json['VideoCodec'] as String?, + container: json['Container'] as String?, + isVideoDirect: json['IsVideoDirect'] as bool?, + isAudioDirect: json['IsAudioDirect'] as bool?, + bitrate: (json['Bitrate'] as num?)?.toInt(), + framerate: (json['Framerate'] as num?)?.toDouble(), + completionPercentage: (json['CompletionPercentage'] as num?)?.toDouble(), + width: (json['Width'] as num?)?.toInt(), + height: (json['Height'] as num?)?.toInt(), + audioChannels: (json['AudioChannels'] as num?)?.toInt(), + hardwareAccelerationType: hardwareEncodingTypeNullableFromJson( + json['HardwareAccelerationType']), + transcodeReasons: + transcodeReasonListFromJson(json['TranscodeReasons'] as List?), + ); + +Map _$TranscodingInfoToJson(TranscodingInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('AudioCodec', instance.audioCodec); + writeNotNull('VideoCodec', instance.videoCodec); + writeNotNull('Container', instance.container); + writeNotNull('IsVideoDirect', instance.isVideoDirect); + writeNotNull('IsAudioDirect', instance.isAudioDirect); + writeNotNull('Bitrate', instance.bitrate); + writeNotNull('Framerate', instance.framerate); + writeNotNull('CompletionPercentage', instance.completionPercentage); + writeNotNull('Width', instance.width); + writeNotNull('Height', instance.height); + writeNotNull('AudioChannels', instance.audioChannels); + writeNotNull('HardwareAccelerationType', + hardwareEncodingTypeNullableToJson(instance.hardwareAccelerationType)); + val['TranscodeReasons'] = + transcodeReasonListToJson(instance.transcodeReasons); + return val; +} + +TranscodingProfile _$TranscodingProfileFromJson(Map json) => + TranscodingProfile( + container: json['Container'] as String?, + type: dlnaProfileTypeNullableFromJson(json['Type']), + videoCodec: json['VideoCodec'] as String?, + audioCodec: json['AudioCodec'] as String?, + protocol: mediaStreamProtocolNullableFromJson(json['Protocol']), + estimateContentLength: json['EstimateContentLength'] as bool? ?? false, + enableMpegtsM2TsMode: json['EnableMpegtsM2TsMode'] as bool? ?? false, + transcodeSeekInfo: + TranscodingProfile.transcodeSeekInfoTranscodeSeekInfoNullableFromJson( + json['TranscodeSeekInfo']), + copyTimestamps: json['CopyTimestamps'] as bool? ?? false, + context: TranscodingProfile.encodingContextContextNullableFromJson( + json['Context']), + enableSubtitlesInManifest: + json['EnableSubtitlesInManifest'] as bool? ?? false, + maxAudioChannels: json['MaxAudioChannels'] as String?, + minSegments: (json['MinSegments'] as num?)?.toInt(), + segmentLength: (json['SegmentLength'] as num?)?.toInt(), + breakOnNonKeyFrames: json['BreakOnNonKeyFrames'] as bool? ?? false, + conditions: (json['Conditions'] as List?) + ?.map((e) => ProfileCondition.fromJson(e as Map)) + .toList() ?? + [], + ); + +Map _$TranscodingProfileToJson(TranscodingProfile instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Container', instance.container); + writeNotNull('Type', dlnaProfileTypeNullableToJson(instance.type)); + writeNotNull('VideoCodec', instance.videoCodec); + writeNotNull('AudioCodec', instance.audioCodec); + writeNotNull( + 'Protocol', mediaStreamProtocolNullableToJson(instance.protocol)); + writeNotNull('EstimateContentLength', instance.estimateContentLength); + writeNotNull('EnableMpegtsM2TsMode', instance.enableMpegtsM2TsMode); + writeNotNull('TranscodeSeekInfo', + transcodeSeekInfoNullableToJson(instance.transcodeSeekInfo)); + writeNotNull('CopyTimestamps', instance.copyTimestamps); + writeNotNull('Context', encodingContextNullableToJson(instance.context)); + writeNotNull('EnableSubtitlesInManifest', instance.enableSubtitlesInManifest); + writeNotNull('MaxAudioChannels', instance.maxAudioChannels); + writeNotNull('MinSegments', instance.minSegments); + writeNotNull('SegmentLength', instance.segmentLength); + writeNotNull('BreakOnNonKeyFrames', instance.breakOnNonKeyFrames); + writeNotNull( + 'Conditions', instance.conditions?.map((e) => e.toJson()).toList()); + return val; +} + +TrickplayInfo _$TrickplayInfoFromJson(Map json) => + TrickplayInfo( + width: (json['Width'] as num?)?.toInt(), + height: (json['Height'] as num?)?.toInt(), + tileWidth: (json['TileWidth'] as num?)?.toInt(), + tileHeight: (json['TileHeight'] as num?)?.toInt(), + thumbnailCount: (json['ThumbnailCount'] as num?)?.toInt(), + interval: (json['Interval'] as num?)?.toInt(), + bandwidth: (json['Bandwidth'] as num?)?.toInt(), + ); + +Map _$TrickplayInfoToJson(TrickplayInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Width', instance.width); + writeNotNull('Height', instance.height); + writeNotNull('TileWidth', instance.tileWidth); + writeNotNull('TileHeight', instance.tileHeight); + writeNotNull('ThumbnailCount', instance.thumbnailCount); + writeNotNull('Interval', instance.interval); + writeNotNull('Bandwidth', instance.bandwidth); + return val; +} + +TrickplayOptions _$TrickplayOptionsFromJson(Map json) => + TrickplayOptions( + enableHwAcceleration: json['EnableHwAcceleration'] as bool?, + enableHwEncoding: json['EnableHwEncoding'] as bool?, + scanBehavior: trickplayScanBehaviorNullableFromJson(json['ScanBehavior']), + processPriority: + processPriorityClassNullableFromJson(json['ProcessPriority']), + interval: (json['Interval'] as num?)?.toInt(), + widthResolutions: (json['WidthResolutions'] as List?) + ?.map((e) => (e as num).toInt()) + .toList() ?? + [], + tileWidth: (json['TileWidth'] as num?)?.toInt(), + tileHeight: (json['TileHeight'] as num?)?.toInt(), + qscale: (json['Qscale'] as num?)?.toInt(), + jpegQuality: (json['JpegQuality'] as num?)?.toInt(), + processThreads: (json['ProcessThreads'] as num?)?.toInt(), + ); + +Map _$TrickplayOptionsToJson(TrickplayOptions instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('EnableHwAcceleration', instance.enableHwAcceleration); + writeNotNull('EnableHwEncoding', instance.enableHwEncoding); + writeNotNull('ScanBehavior', + trickplayScanBehaviorNullableToJson(instance.scanBehavior)); + writeNotNull('ProcessPriority', + processPriorityClassNullableToJson(instance.processPriority)); + writeNotNull('Interval', instance.interval); + writeNotNull('WidthResolutions', instance.widthResolutions); + writeNotNull('TileWidth', instance.tileWidth); + writeNotNull('TileHeight', instance.tileHeight); + writeNotNull('Qscale', instance.qscale); + writeNotNull('JpegQuality', instance.jpegQuality); + writeNotNull('ProcessThreads', instance.processThreads); + return val; +} + +TunerChannelMapping _$TunerChannelMappingFromJson(Map json) => + TunerChannelMapping( + name: json['Name'] as String?, + providerChannelName: json['ProviderChannelName'] as String?, + providerChannelId: json['ProviderChannelId'] as String?, + id: json['Id'] as String?, + ); + +Map _$TunerChannelMappingToJson(TunerChannelMapping instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('ProviderChannelName', instance.providerChannelName); + writeNotNull('ProviderChannelId', instance.providerChannelId); + writeNotNull('Id', instance.id); + return val; +} + +TunerHostInfo _$TunerHostInfoFromJson(Map json) => + TunerHostInfo( + id: json['Id'] as String?, + url: json['Url'] as String?, + type: json['Type'] as String?, + deviceId: json['DeviceId'] as String?, + friendlyName: json['FriendlyName'] as String?, + importFavoritesOnly: json['ImportFavoritesOnly'] as bool?, + allowHWTranscoding: json['AllowHWTranscoding'] as bool?, + enableStreamLooping: json['EnableStreamLooping'] as bool?, + source: json['Source'] as String?, + tunerCount: (json['TunerCount'] as num?)?.toInt(), + userAgent: json['UserAgent'] as String?, + ignoreDts: json['IgnoreDts'] as bool?, + ); + +Map _$TunerHostInfoToJson(TunerHostInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Id', instance.id); + writeNotNull('Url', instance.url); + writeNotNull('Type', instance.type); + writeNotNull('DeviceId', instance.deviceId); + writeNotNull('FriendlyName', instance.friendlyName); + writeNotNull('ImportFavoritesOnly', instance.importFavoritesOnly); + writeNotNull('AllowHWTranscoding', instance.allowHWTranscoding); + writeNotNull('EnableStreamLooping', instance.enableStreamLooping); + writeNotNull('Source', instance.source); + writeNotNull('TunerCount', instance.tunerCount); + writeNotNull('UserAgent', instance.userAgent); + writeNotNull('IgnoreDts', instance.ignoreDts); + return val; +} + +TypeOptions _$TypeOptionsFromJson(Map json) => TypeOptions( + type: json['Type'] as String?, + metadataFetchers: (json['MetadataFetchers'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + metadataFetcherOrder: (json['MetadataFetcherOrder'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + imageFetchers: (json['ImageFetchers'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + imageFetcherOrder: (json['ImageFetcherOrder'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + imageOptions: (json['ImageOptions'] as List?) + ?.map((e) => ImageOption.fromJson(e as Map)) + .toList() ?? + [], + ); + +Map _$TypeOptionsToJson(TypeOptions instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Type', instance.type); + writeNotNull('MetadataFetchers', instance.metadataFetchers); + writeNotNull('MetadataFetcherOrder', instance.metadataFetcherOrder); + writeNotNull('ImageFetchers', instance.imageFetchers); + writeNotNull('ImageFetcherOrder', instance.imageFetcherOrder); + writeNotNull( + 'ImageOptions', instance.imageOptions?.map((e) => e.toJson()).toList()); + return val; +} + +UpdateLibraryOptionsDto _$UpdateLibraryOptionsDtoFromJson( + Map json) => + UpdateLibraryOptionsDto( + id: json['Id'] as String?, + libraryOptions: json['LibraryOptions'] == null + ? null + : LibraryOptions.fromJson( + json['LibraryOptions'] as Map), + ); + +Map _$UpdateLibraryOptionsDtoToJson( + UpdateLibraryOptionsDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Id', instance.id); + writeNotNull('LibraryOptions', instance.libraryOptions?.toJson()); + return val; +} + +UpdateMediaPathRequestDto _$UpdateMediaPathRequestDtoFromJson( + Map json) => + UpdateMediaPathRequestDto( + name: json['Name'] as String, + pathInfo: + MediaPathInfo.fromJson(json['PathInfo'] as Map), + ); + +Map _$UpdateMediaPathRequestDtoToJson( + UpdateMediaPathRequestDto instance) => + { + 'Name': instance.name, + 'PathInfo': instance.pathInfo.toJson(), + }; + +UpdatePlaylistDto _$UpdatePlaylistDtoFromJson(Map json) => + UpdatePlaylistDto( + name: json['Name'] as String?, + ids: (json['Ids'] as List?)?.map((e) => e as String).toList() ?? + [], + users: (json['Users'] as List?) + ?.map((e) => + PlaylistUserPermissions.fromJson(e as Map)) + .toList() ?? + [], + isPublic: json['IsPublic'] as bool?, + ); + +Map _$UpdatePlaylistDtoToJson(UpdatePlaylistDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('Ids', instance.ids); + writeNotNull('Users', instance.users?.map((e) => e.toJson()).toList()); + writeNotNull('IsPublic', instance.isPublic); + return val; +} + +UpdatePlaylistUserDto _$UpdatePlaylistUserDtoFromJson( + Map json) => + UpdatePlaylistUserDto( + canEdit: json['CanEdit'] as bool?, + ); + +Map _$UpdatePlaylistUserDtoToJson( + UpdatePlaylistUserDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('CanEdit', instance.canEdit); + return val; +} + +UpdateUserItemDataDto _$UpdateUserItemDataDtoFromJson( + Map json) => + UpdateUserItemDataDto( + rating: (json['Rating'] as num?)?.toDouble(), + playedPercentage: (json['PlayedPercentage'] as num?)?.toDouble(), + unplayedItemCount: (json['UnplayedItemCount'] as num?)?.toInt(), + playbackPositionTicks: (json['PlaybackPositionTicks'] as num?)?.toInt(), + playCount: (json['PlayCount'] as num?)?.toInt(), + isFavorite: json['IsFavorite'] as bool?, + likes: json['Likes'] as bool?, + lastPlayedDate: json['LastPlayedDate'] == null + ? null + : DateTime.parse(json['LastPlayedDate'] as String), + played: json['Played'] as bool?, + key: json['Key'] as String?, + itemId: json['ItemId'] as String?, + ); + +Map _$UpdateUserItemDataDtoToJson( + UpdateUserItemDataDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Rating', instance.rating); + writeNotNull('PlayedPercentage', instance.playedPercentage); + writeNotNull('UnplayedItemCount', instance.unplayedItemCount); + writeNotNull('PlaybackPositionTicks', instance.playbackPositionTicks); + writeNotNull('PlayCount', instance.playCount); + writeNotNull('IsFavorite', instance.isFavorite); + writeNotNull('Likes', instance.likes); + writeNotNull('LastPlayedDate', instance.lastPlayedDate?.toIso8601String()); + writeNotNull('Played', instance.played); + writeNotNull('Key', instance.key); + writeNotNull('ItemId', instance.itemId); + return val; +} + +UpdateUserPassword _$UpdateUserPasswordFromJson(Map json) => + UpdateUserPassword( + currentPassword: json['CurrentPassword'] as String?, + currentPw: json['CurrentPw'] as String?, + newPw: json['NewPw'] as String?, + resetPassword: json['ResetPassword'] as bool?, + ); + +Map _$UpdateUserPasswordToJson(UpdateUserPassword instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('CurrentPassword', instance.currentPassword); + writeNotNull('CurrentPw', instance.currentPw); + writeNotNull('NewPw', instance.newPw); + writeNotNull('ResetPassword', instance.resetPassword); + return val; +} + +UploadSubtitleDto _$UploadSubtitleDtoFromJson(Map json) => + UploadSubtitleDto( + language: json['Language'] as String, + format: json['Format'] as String, + isForced: json['IsForced'] as bool, + isHearingImpaired: json['IsHearingImpaired'] as bool, + data: json['Data'] as String, + ); + +Map _$UploadSubtitleDtoToJson(UploadSubtitleDto instance) => + { + 'Language': instance.language, + 'Format': instance.format, + 'IsForced': instance.isForced, + 'IsHearingImpaired': instance.isHearingImpaired, + 'Data': instance.data, + }; + +UserConfiguration _$UserConfigurationFromJson(Map json) => + UserConfiguration( + audioLanguagePreference: json['AudioLanguagePreference'] as String?, + playDefaultAudioTrack: json['PlayDefaultAudioTrack'] as bool?, + subtitleLanguagePreference: json['SubtitleLanguagePreference'] as String?, + displayMissingEpisodes: json['DisplayMissingEpisodes'] as bool?, + groupedFolders: (json['GroupedFolders'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + subtitleMode: subtitlePlaybackModeNullableFromJson(json['SubtitleMode']), + displayCollectionsView: json['DisplayCollectionsView'] as bool?, + enableLocalPassword: json['EnableLocalPassword'] as bool?, + orderedViews: (json['OrderedViews'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + latestItemsExcludes: (json['LatestItemsExcludes'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + myMediaExcludes: (json['MyMediaExcludes'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + hidePlayedInLatest: json['HidePlayedInLatest'] as bool?, + rememberAudioSelections: json['RememberAudioSelections'] as bool?, + rememberSubtitleSelections: json['RememberSubtitleSelections'] as bool?, + enableNextEpisodeAutoPlay: json['EnableNextEpisodeAutoPlay'] as bool?, + castReceiverId: json['CastReceiverId'] as String?, + ); + +Map _$UserConfigurationToJson(UserConfiguration instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('AudioLanguagePreference', instance.audioLanguagePreference); + writeNotNull('PlayDefaultAudioTrack', instance.playDefaultAudioTrack); + writeNotNull( + 'SubtitleLanguagePreference', instance.subtitleLanguagePreference); + writeNotNull('DisplayMissingEpisodes', instance.displayMissingEpisodes); + writeNotNull('GroupedFolders', instance.groupedFolders); + writeNotNull('SubtitleMode', + subtitlePlaybackModeNullableToJson(instance.subtitleMode)); + writeNotNull('DisplayCollectionsView', instance.displayCollectionsView); + writeNotNull('EnableLocalPassword', instance.enableLocalPassword); + writeNotNull('OrderedViews', instance.orderedViews); + writeNotNull('LatestItemsExcludes', instance.latestItemsExcludes); + writeNotNull('MyMediaExcludes', instance.myMediaExcludes); + writeNotNull('HidePlayedInLatest', instance.hidePlayedInLatest); + writeNotNull('RememberAudioSelections', instance.rememberAudioSelections); + writeNotNull( + 'RememberSubtitleSelections', instance.rememberSubtitleSelections); + writeNotNull('EnableNextEpisodeAutoPlay', instance.enableNextEpisodeAutoPlay); + writeNotNull('CastReceiverId', instance.castReceiverId); + return val; +} + +UserDataChangedMessage _$UserDataChangedMessageFromJson( + Map json) => + UserDataChangedMessage( + data: json['Data'] == null + ? null + : UserDataChangeInfo.fromJson(json['Data'] as Map), + messageId: json['MessageId'] as String?, + messageType: + UserDataChangedMessage.sessionMessageTypeMessageTypeNullableFromJson( + json['MessageType']), + ); + +Map _$UserDataChangedMessageToJson( + UserDataChangedMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Data', instance.data?.toJson()); + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +UserDataChangeInfo _$UserDataChangeInfoFromJson(Map json) => + UserDataChangeInfo( + userId: json['UserId'] as String?, + userDataList: (json['UserDataList'] as List?) + ?.map((e) => UserItemDataDto.fromJson(e as Map)) + .toList() ?? + [], + ); + +Map _$UserDataChangeInfoToJson(UserDataChangeInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('UserId', instance.userId); + writeNotNull( + 'UserDataList', instance.userDataList?.map((e) => e.toJson()).toList()); + return val; +} + +UserDeletedMessage _$UserDeletedMessageFromJson(Map json) => + UserDeletedMessage( + data: json['Data'] as String?, + messageId: json['MessageId'] as String?, + messageType: + UserDeletedMessage.sessionMessageTypeMessageTypeNullableFromJson( + json['MessageType']), + ); + +Map _$UserDeletedMessageToJson(UserDeletedMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Data', instance.data); + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +UserDto _$UserDtoFromJson(Map json) => UserDto( + name: json['Name'] as String?, + serverId: json['ServerId'] as String?, + serverName: json['ServerName'] as String?, + id: json['Id'] as String?, + primaryImageTag: json['PrimaryImageTag'] as String?, + hasPassword: json['HasPassword'] as bool?, + hasConfiguredPassword: json['HasConfiguredPassword'] as bool?, + hasConfiguredEasyPassword: json['HasConfiguredEasyPassword'] as bool?, + enableAutoLogin: json['EnableAutoLogin'] as bool?, + lastLoginDate: json['LastLoginDate'] == null + ? null + : DateTime.parse(json['LastLoginDate'] as String), + lastActivityDate: json['LastActivityDate'] == null + ? null + : DateTime.parse(json['LastActivityDate'] as String), + configuration: json['Configuration'] == null + ? null + : UserConfiguration.fromJson( + json['Configuration'] as Map), + policy: json['Policy'] == null + ? null + : UserPolicy.fromJson(json['Policy'] as Map), + primaryImageAspectRatio: + (json['PrimaryImageAspectRatio'] as num?)?.toDouble(), + ); + +Map _$UserDtoToJson(UserDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('ServerId', instance.serverId); + writeNotNull('ServerName', instance.serverName); + writeNotNull('Id', instance.id); + writeNotNull('PrimaryImageTag', instance.primaryImageTag); + writeNotNull('HasPassword', instance.hasPassword); + writeNotNull('HasConfiguredPassword', instance.hasConfiguredPassword); + writeNotNull('HasConfiguredEasyPassword', instance.hasConfiguredEasyPassword); + writeNotNull('EnableAutoLogin', instance.enableAutoLogin); + writeNotNull('LastLoginDate', instance.lastLoginDate?.toIso8601String()); + writeNotNull( + 'LastActivityDate', instance.lastActivityDate?.toIso8601String()); + writeNotNull('Configuration', instance.configuration?.toJson()); + writeNotNull('Policy', instance.policy?.toJson()); + writeNotNull('PrimaryImageAspectRatio', instance.primaryImageAspectRatio); + return val; +} + +UserInterfaceConfiguration _$UserInterfaceConfigurationFromJson( + Map json) => + UserInterfaceConfiguration( + skipButtonVisible: json['SkipButtonVisible'] as bool?, + skipButtonIntroText: json['SkipButtonIntroText'] as String?, + skipButtonEndCreditsText: json['SkipButtonEndCreditsText'] as String?, + ); + +Map _$UserInterfaceConfigurationToJson( + UserInterfaceConfiguration instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('SkipButtonVisible', instance.skipButtonVisible); + writeNotNull('SkipButtonIntroText', instance.skipButtonIntroText); + writeNotNull('SkipButtonEndCreditsText', instance.skipButtonEndCreditsText); + return val; +} + +UserItemDataDto _$UserItemDataDtoFromJson(Map json) => + UserItemDataDto( + rating: (json['Rating'] as num?)?.toDouble(), + playedPercentage: (json['PlayedPercentage'] as num?)?.toDouble(), + unplayedItemCount: (json['UnplayedItemCount'] as num?)?.toInt(), + playbackPositionTicks: (json['PlaybackPositionTicks'] as num?)?.toInt(), + playCount: (json['PlayCount'] as num?)?.toInt(), + isFavorite: json['IsFavorite'] as bool?, + likes: json['Likes'] as bool?, + lastPlayedDate: json['LastPlayedDate'] == null + ? null + : DateTime.parse(json['LastPlayedDate'] as String), + played: json['Played'] as bool?, + key: json['Key'] as String?, + itemId: json['ItemId'] as String?, + ); + +Map _$UserItemDataDtoToJson(UserItemDataDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Rating', instance.rating); + writeNotNull('PlayedPercentage', instance.playedPercentage); + writeNotNull('UnplayedItemCount', instance.unplayedItemCount); + writeNotNull('PlaybackPositionTicks', instance.playbackPositionTicks); + writeNotNull('PlayCount', instance.playCount); + writeNotNull('IsFavorite', instance.isFavorite); + writeNotNull('Likes', instance.likes); + writeNotNull('LastPlayedDate', instance.lastPlayedDate?.toIso8601String()); + writeNotNull('Played', instance.played); + writeNotNull('Key', instance.key); + writeNotNull('ItemId', instance.itemId); + return val; +} + +UserPolicy _$UserPolicyFromJson(Map json) => UserPolicy( + isAdministrator: json['IsAdministrator'] as bool?, + isHidden: json['IsHidden'] as bool?, + enableCollectionManagement: + json['EnableCollectionManagement'] as bool? ?? false, + enableSubtitleManagement: + json['EnableSubtitleManagement'] as bool? ?? false, + enableLyricManagement: json['EnableLyricManagement'] as bool? ?? false, + isDisabled: json['IsDisabled'] as bool?, + maxParentalRating: (json['MaxParentalRating'] as num?)?.toInt(), + blockedTags: (json['BlockedTags'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + allowedTags: (json['AllowedTags'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + enableUserPreferenceAccess: json['EnableUserPreferenceAccess'] as bool?, + accessSchedules: (json['AccessSchedules'] as List?) + ?.map((e) => AccessSchedule.fromJson(e as Map)) + .toList() ?? + [], + blockUnratedItems: + unratedItemListFromJson(json['BlockUnratedItems'] as List?), + enableRemoteControlOfOtherUsers: + json['EnableRemoteControlOfOtherUsers'] as bool?, + enableSharedDeviceControl: json['EnableSharedDeviceControl'] as bool?, + enableRemoteAccess: json['EnableRemoteAccess'] as bool?, + enableLiveTvManagement: json['EnableLiveTvManagement'] as bool?, + enableLiveTvAccess: json['EnableLiveTvAccess'] as bool?, + enableMediaPlayback: json['EnableMediaPlayback'] as bool?, + enableAudioPlaybackTranscoding: + json['EnableAudioPlaybackTranscoding'] as bool?, + enableVideoPlaybackTranscoding: + json['EnableVideoPlaybackTranscoding'] as bool?, + enablePlaybackRemuxing: json['EnablePlaybackRemuxing'] as bool?, + forceRemoteSourceTranscoding: + json['ForceRemoteSourceTranscoding'] as bool?, + enableContentDeletion: json['EnableContentDeletion'] as bool?, + enableContentDeletionFromFolders: + (json['EnableContentDeletionFromFolders'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + enableContentDownloading: json['EnableContentDownloading'] as bool?, + enableSyncTranscoding: json['EnableSyncTranscoding'] as bool?, + enableMediaConversion: json['EnableMediaConversion'] as bool?, + enabledDevices: (json['EnabledDevices'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + enableAllDevices: json['EnableAllDevices'] as bool?, + enabledChannels: (json['EnabledChannels'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + enableAllChannels: json['EnableAllChannels'] as bool?, + enabledFolders: (json['EnabledFolders'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + enableAllFolders: json['EnableAllFolders'] as bool?, + invalidLoginAttemptCount: + (json['InvalidLoginAttemptCount'] as num?)?.toInt(), + loginAttemptsBeforeLockout: + (json['LoginAttemptsBeforeLockout'] as num?)?.toInt(), + maxActiveSessions: (json['MaxActiveSessions'] as num?)?.toInt(), + enablePublicSharing: json['EnablePublicSharing'] as bool?, + blockedMediaFolders: (json['BlockedMediaFolders'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + blockedChannels: (json['BlockedChannels'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + remoteClientBitrateLimit: + (json['RemoteClientBitrateLimit'] as num?)?.toInt(), + authenticationProviderId: json['AuthenticationProviderId'] as String, + passwordResetProviderId: json['PasswordResetProviderId'] as String, + syncPlayAccess: + syncPlayUserAccessTypeNullableFromJson(json['SyncPlayAccess']), + ); + +Map _$UserPolicyToJson(UserPolicy instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('IsAdministrator', instance.isAdministrator); + writeNotNull('IsHidden', instance.isHidden); + writeNotNull( + 'EnableCollectionManagement', instance.enableCollectionManagement); + writeNotNull('EnableSubtitleManagement', instance.enableSubtitleManagement); + writeNotNull('EnableLyricManagement', instance.enableLyricManagement); + writeNotNull('IsDisabled', instance.isDisabled); + writeNotNull('MaxParentalRating', instance.maxParentalRating); + writeNotNull('BlockedTags', instance.blockedTags); + writeNotNull('AllowedTags', instance.allowedTags); + writeNotNull( + 'EnableUserPreferenceAccess', instance.enableUserPreferenceAccess); + writeNotNull('AccessSchedules', + instance.accessSchedules?.map((e) => e.toJson()).toList()); + val['BlockUnratedItems'] = unratedItemListToJson(instance.blockUnratedItems); + writeNotNull('EnableRemoteControlOfOtherUsers', + instance.enableRemoteControlOfOtherUsers); + writeNotNull('EnableSharedDeviceControl', instance.enableSharedDeviceControl); + writeNotNull('EnableRemoteAccess', instance.enableRemoteAccess); + writeNotNull('EnableLiveTvManagement', instance.enableLiveTvManagement); + writeNotNull('EnableLiveTvAccess', instance.enableLiveTvAccess); + writeNotNull('EnableMediaPlayback', instance.enableMediaPlayback); + writeNotNull('EnableAudioPlaybackTranscoding', + instance.enableAudioPlaybackTranscoding); + writeNotNull('EnableVideoPlaybackTranscoding', + instance.enableVideoPlaybackTranscoding); + writeNotNull('EnablePlaybackRemuxing', instance.enablePlaybackRemuxing); + writeNotNull( + 'ForceRemoteSourceTranscoding', instance.forceRemoteSourceTranscoding); + writeNotNull('EnableContentDeletion', instance.enableContentDeletion); + writeNotNull('EnableContentDeletionFromFolders', + instance.enableContentDeletionFromFolders); + writeNotNull('EnableContentDownloading', instance.enableContentDownloading); + writeNotNull('EnableSyncTranscoding', instance.enableSyncTranscoding); + writeNotNull('EnableMediaConversion', instance.enableMediaConversion); + writeNotNull('EnabledDevices', instance.enabledDevices); + writeNotNull('EnableAllDevices', instance.enableAllDevices); + writeNotNull('EnabledChannels', instance.enabledChannels); + writeNotNull('EnableAllChannels', instance.enableAllChannels); + writeNotNull('EnabledFolders', instance.enabledFolders); + writeNotNull('EnableAllFolders', instance.enableAllFolders); + writeNotNull('InvalidLoginAttemptCount', instance.invalidLoginAttemptCount); + writeNotNull( + 'LoginAttemptsBeforeLockout', instance.loginAttemptsBeforeLockout); + writeNotNull('MaxActiveSessions', instance.maxActiveSessions); + writeNotNull('EnablePublicSharing', instance.enablePublicSharing); + writeNotNull('BlockedMediaFolders', instance.blockedMediaFolders); + writeNotNull('BlockedChannels', instance.blockedChannels); + writeNotNull('RemoteClientBitrateLimit', instance.remoteClientBitrateLimit); + val['AuthenticationProviderId'] = instance.authenticationProviderId; + val['PasswordResetProviderId'] = instance.passwordResetProviderId; + writeNotNull('SyncPlayAccess', + syncPlayUserAccessTypeNullableToJson(instance.syncPlayAccess)); + return val; +} + +UserUpdatedMessage _$UserUpdatedMessageFromJson(Map json) => + UserUpdatedMessage( + data: json['Data'] == null + ? null + : UserDto.fromJson(json['Data'] as Map), + messageId: json['MessageId'] as String?, + messageType: + UserUpdatedMessage.sessionMessageTypeMessageTypeNullableFromJson( + json['MessageType']), + ); + +Map _$UserUpdatedMessageToJson(UserUpdatedMessage instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Data', instance.data?.toJson()); + writeNotNull('MessageId', instance.messageId); + writeNotNull( + 'MessageType', sessionMessageTypeNullableToJson(instance.messageType)); + return val; +} + +UtcTimeResponse _$UtcTimeResponseFromJson(Map json) => + UtcTimeResponse( + requestReceptionTime: json['RequestReceptionTime'] == null + ? null + : DateTime.parse(json['RequestReceptionTime'] as String), + responseTransmissionTime: json['ResponseTransmissionTime'] == null + ? null + : DateTime.parse(json['ResponseTransmissionTime'] as String), + ); + +Map _$UtcTimeResponseToJson(UtcTimeResponse instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull( + 'RequestReceptionTime', instance.requestReceptionTime?.toIso8601String()); + writeNotNull('ResponseTransmissionTime', + instance.responseTransmissionTime?.toIso8601String()); + return val; +} + +ValidatePathDto _$ValidatePathDtoFromJson(Map json) => + ValidatePathDto( + validateWritable: json['ValidateWritable'] as bool?, + path: json['Path'] as String?, + isFile: json['IsFile'] as bool?, + ); + +Map _$ValidatePathDtoToJson(ValidatePathDto instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('ValidateWritable', instance.validateWritable); + writeNotNull('Path', instance.path); + writeNotNull('IsFile', instance.isFile); + return val; +} + +VersionInfo _$VersionInfoFromJson(Map json) => VersionInfo( + version: json['version'] as String?, + versionNumber: json['VersionNumber'] as String?, + changelog: json['changelog'] as String?, + targetAbi: json['targetAbi'] as String?, + sourceUrl: json['sourceUrl'] as String?, + checksum: json['checksum'] as String?, + timestamp: json['timestamp'] as String?, + repositoryName: json['repositoryName'] as String?, + repositoryUrl: json['repositoryUrl'] as String?, + ); + +Map _$VersionInfoToJson(VersionInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('version', instance.version); + writeNotNull('VersionNumber', instance.versionNumber); + writeNotNull('changelog', instance.changelog); + writeNotNull('targetAbi', instance.targetAbi); + writeNotNull('sourceUrl', instance.sourceUrl); + writeNotNull('checksum', instance.checksum); + writeNotNull('timestamp', instance.timestamp); + writeNotNull('repositoryName', instance.repositoryName); + writeNotNull('repositoryUrl', instance.repositoryUrl); + return val; +} + +VirtualFolderInfo _$VirtualFolderInfoFromJson(Map json) => + VirtualFolderInfo( + name: json['Name'] as String?, + locations: (json['Locations'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + collectionType: + collectionTypeOptionsNullableFromJson(json['CollectionType']), + libraryOptions: json['LibraryOptions'] == null + ? null + : LibraryOptions.fromJson( + json['LibraryOptions'] as Map), + itemId: json['ItemId'] as String?, + primaryImageItemId: json['PrimaryImageItemId'] as String?, + refreshProgress: (json['RefreshProgress'] as num?)?.toDouble(), + refreshStatus: json['RefreshStatus'] as String?, + ); + +Map _$VirtualFolderInfoToJson(VirtualFolderInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Name', instance.name); + writeNotNull('Locations', instance.locations); + writeNotNull('CollectionType', + collectionTypeOptionsNullableToJson(instance.collectionType)); + writeNotNull('LibraryOptions', instance.libraryOptions?.toJson()); + writeNotNull('ItemId', instance.itemId); + writeNotNull('PrimaryImageItemId', instance.primaryImageItemId); + writeNotNull('RefreshProgress', instance.refreshProgress); + writeNotNull('RefreshStatus', instance.refreshStatus); + return val; +} + +WakeOnLanInfo _$WakeOnLanInfoFromJson(Map json) => + WakeOnLanInfo( + macAddress: json['MacAddress'] as String?, + port: (json['Port'] as num?)?.toInt(), + ); + +Map _$WakeOnLanInfoToJson(WakeOnLanInfo instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('MacAddress', instance.macAddress); + writeNotNull('Port', instance.port); + return val; +} + +WebSocketMessage _$WebSocketMessageFromJson(Map json) => + WebSocketMessage(); + +Map _$WebSocketMessageToJson(WebSocketMessage instance) => + {}; + +XbmcMetadataOptions _$XbmcMetadataOptionsFromJson(Map json) => + XbmcMetadataOptions( + userId: json['UserId'] as String?, + releaseDateFormat: json['ReleaseDateFormat'] as String?, + saveImagePathsInNfo: json['SaveImagePathsInNfo'] as bool?, + enablePathSubstitution: json['EnablePathSubstitution'] as bool?, + enableExtraThumbsDuplication: + json['EnableExtraThumbsDuplication'] as bool?, + ); + +Map _$XbmcMetadataOptionsToJson(XbmcMetadataOptions instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('UserId', instance.userId); + writeNotNull('ReleaseDateFormat', instance.releaseDateFormat); + writeNotNull('SaveImagePathsInNfo', instance.saveImagePathsInNfo); + writeNotNull('EnablePathSubstitution', instance.enablePathSubstitution); + writeNotNull( + 'EnableExtraThumbsDuplication', instance.enableExtraThumbsDuplication); + return val; +} + +BaseItemDto$ImageBlurHashes _$BaseItemDto$ImageBlurHashesFromJson( + Map json) => + BaseItemDto$ImageBlurHashes( + primary: json['Primary'] as Map?, + art: json['Art'] as Map?, + backdrop: json['Backdrop'] as Map?, + banner: json['Banner'] as Map?, + logo: json['Logo'] as Map?, + thumb: json['Thumb'] as Map?, + disc: json['Disc'] as Map?, + box: json['Box'] as Map?, + screenshot: json['Screenshot'] as Map?, + menu: json['Menu'] as Map?, + chapter: json['Chapter'] as Map?, + boxRear: json['BoxRear'] as Map?, + profile: json['Profile'] as Map?, + ); + +Map _$BaseItemDto$ImageBlurHashesToJson( + BaseItemDto$ImageBlurHashes instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Primary', instance.primary); + writeNotNull('Art', instance.art); + writeNotNull('Backdrop', instance.backdrop); + writeNotNull('Banner', instance.banner); + writeNotNull('Logo', instance.logo); + writeNotNull('Thumb', instance.thumb); + writeNotNull('Disc', instance.disc); + writeNotNull('Box', instance.box); + writeNotNull('Screenshot', instance.screenshot); + writeNotNull('Menu', instance.menu); + writeNotNull('Chapter', instance.chapter); + writeNotNull('BoxRear', instance.boxRear); + writeNotNull('Profile', instance.profile); + return val; +} + +BaseItemPerson$ImageBlurHashes _$BaseItemPerson$ImageBlurHashesFromJson( + Map json) => + BaseItemPerson$ImageBlurHashes( + primary: json['Primary'] as Map?, + art: json['Art'] as Map?, + backdrop: json['Backdrop'] as Map?, + banner: json['Banner'] as Map?, + logo: json['Logo'] as Map?, + thumb: json['Thumb'] as Map?, + disc: json['Disc'] as Map?, + box: json['Box'] as Map?, + screenshot: json['Screenshot'] as Map?, + menu: json['Menu'] as Map?, + chapter: json['Chapter'] as Map?, + boxRear: json['BoxRear'] as Map?, + profile: json['Profile'] as Map?, + ); + +Map _$BaseItemPerson$ImageBlurHashesToJson( + BaseItemPerson$ImageBlurHashes instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('Primary', instance.primary); + writeNotNull('Art', instance.art); + writeNotNull('Backdrop', instance.backdrop); + writeNotNull('Banner', instance.banner); + writeNotNull('Logo', instance.logo); + writeNotNull('Thumb', instance.thumb); + writeNotNull('Disc', instance.disc); + writeNotNull('Box', instance.box); + writeNotNull('Screenshot', instance.screenshot); + writeNotNull('Menu', instance.menu); + writeNotNull('Chapter', instance.chapter); + writeNotNull('BoxRear', instance.boxRear); + writeNotNull('Profile', instance.profile); + return val; +} diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb new file mode 100644 index 0000000..bc96e53 --- /dev/null +++ b/lib/l10n/app_en.arb @@ -0,0 +1,669 @@ +{ + "@@locale": "en", + "switchUser": "Switch user", + "userName": "Username", + "password": "Password", + "login": "Login", + "logout": "Logout", + "cancel": "Cancel", + "accept": "Accept", + "code": "Code", + "error": "Error", + "clear": "Clear", + "days": "Days", + "search": "Search", + "loggedIn": "Logged-in", + "change": "Change", + "other": "Other", + "dynamicText": "Dynamic", + "enabled": "Enabled", + "disabled": "Disabled", + "dashboard": "Dashboard", + "advanced": "Advanced", + "refresh": "Refresh", + "delete": "Delete", + "goTo": "Go To", + "loop": "Loop", + "empty": "Empty", + "noRating": "No rating", + "backgroundBlur": "Background blur", + "autoPlay": "Auto-play", + "resume": "Resume {item}", + "@resume": { + "description": "resume", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "play": "Play {item}", + "@play": { + "description": "Play with", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "read": "Read {item}", + "@read": { + "description": "read", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "readFromStart": "Read {item} from start", + "@readFromStart": { + "description": "Read book from start", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "playFrom": "Play from {name}", + "@playFrom": { + "description": "playFrom", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "playFromStart": "Play {name} from the start", + "@playFromStart": { + "description": "speel vanaf het begin", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "moreFrom": "More from {info}", + "@moreFrom": { + "description": "More from", + "placeholders": { + "info": { + "type": "String" + } + } + }, + "selectedWith": "Selected {info}", + "@selectedWith": { + "description": "selected", + "placeholders": { + "info": { + "type": "String" + } + } + }, + "selected": "Selected", + "restart": "Restart", + "reWatch": "Rewatch", + "options": "Options", + "list": "List", + "grid": "Grid", + "masonry": "Masonry", + "start": "Start", + "none": "None", + "chapter": "{count, plural, other{Chapters} one{Chapter}}", + "@chapter": { + "description": "chapter", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "watchOn": "Watch on", + "sync": "Sync", + "moreOptions": "More options", + "continuePage": "Continue - page {page}", + "@continuePage": { + "description": "Continue - page 1", + "placeholders": { + "page": { + "type": "int" + } + } + }, + "openShow": "Open show", + "showDetails": "Show details", + "showAlbum": "Show album", + "season": "{count, plural, other{Seasons} one{Season} }", + "@season": { + "description": "season", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "episode": "{count, plural, other{Episodes} one{Episode} }", + "@episode": { + "description": "episode", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "addToCollection": "Add to collection", + "addToPlaylist": "Add to playlist", + "removeFromCollection": "Remove to collection", + "removeFromPlaylist": "Remove to playlist", + "markAsWatched": "Mark as watched", + "markAsUnwatched": "Mark as unwatched", + "removeAsFavorite": "Remove as favorite", + "addAsFavorite": "Add as favorite", + "editMetadata": "Edit metadata", + "refreshMetadata": "Refresh metadata", + "syncDetails": "Sync details", + "identify": "Identify", + "info": "Info", + "clearAllSettings": "Clear all settings", + "clearAllSettingsQuestion": "Clear all settings?", + "unableToReverseAction": "This action can not be reversed, it will remove all settings.", + "navigationDashboard": "Dashboard", + "navigationFavorites": "Favorites", + "navigationSync": "Synced", + "navigation": "Navigation", + "library": "{count, plural, other{Libraries} one{Library}}", + "@library": { + "description": "Plural", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "scanLibrary": "Scan library", + "dashboardContinue": "Continue", + "dashboardContinueWatching": "Continue Watching", + "dashboardContinueReading": "Continue Reading", + "dashboardContinueListening": "Continue Listening", + "dashboardNextUp": "Next-up", + "dashboardRecentlyAdded": "Recently added in {name}", + "@dashboardRecentlyAdded": { + "description": "Recently added on home screen", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "settings": "Settings", + "settingsClientTitle": "Fladder", + "settingsClientDesc": "General, Time-out, Layout, Theme", + "settingsQuickConnectTitle": "Quick connect", + "settingsProfileTitle": "Profile", + "settingsProfileDesc": "Lockscreen", + "settingsPlayerTitle": "Player", + "settingsPlayerDesc": "Aspect-ratio, Advanced", + "logoutUserPopupTitle": "Log-out user {userName}?", + "@logoutUserPopupTitle": { + "description": "Pop-up for loging out the user", + "placeholders": { + "userName": { + "type": "String" + } + } + }, + "logoutUserPopupContent": "This will log-out {userName} and delete te user from the app.\nYou will have to log back in to {serverName}.", + "@logoutUserPopupContent": { + "description": "Pop-up for loging out the user description", + "placeholders": { + "userName": { + "type": "String" + }, + "serverName": { + "type": "String" + } + } + }, + "quickConnectTitle": "Quick-connect", + "quickConnectAction": "Enter quick connect code for", + "quickConnectInputACode": "Input a code", + "quickConnectWrongCode": "Wrong code", + "downloadsTitle": "Downloads", + "downloadsPath": "Path", + "pathEditTitle": "Change location", + "pathEditSelect": "Select downloads destination", + "pathClearTitle": "Clear downloads path", + "pathEditDesc": "This location is set for all users, any synced data will no longer be accessible.\nIt will remain on your storage.", + "downloadsSyncedData": "Synced data", + "downloadsClearTitle": "Clear synced data", + "downloadsClearDesc": "Are you sure you want to remove all synced data?\nThis will clear all data for every synced user!", + "lockscreen": "Lockscreen", + "timeOut": "Time-out", + "home": "Home", + "settingsHomeCarouselTitle": "Dashboard carousel", + "settingsHomeCarouselDesc": "Shows a carousel on the dashboard screen", + "settingsHomeNextUpTitle": "Next-up posters", + "settingsHomeNextUpDesc": "Type of posters shown in the dashboard screen", + "settingsVisual": "Visual", + "settingsBlurredPlaceholderTitle": "Blurred placeholder", + "settingsBlurredPlaceholderDesc": "Show blurred background when loading posters", + "settingsBlurEpisodesTitle": "Blur next-up episodes", + "settingsBlurEpisodesDesc": "Blur all upcoming episodes", + "settingsEnableOsMediaControls": "Enable OS media controls", + "settingsNextUpCutoffDays": "Next-up cutoff days", + "settingsShowScaleSlider": "Show poster size slide", + "settingsPosterSize": "Poster size", + "settingsPosterSlider": "Show scale slider", + "settingsPosterPinch": "Pinch-zoom to scale posters", + "theme": "Theme", + "mode": "Mode", + "themeModeSystem": "System", + "themeModeLight": "Light", + "themeModeDark": "Dark", + "themeColor": "Theme color", + "color": "Color", + "amoledBlack": "Amoled black", + "hide": "Hide", + "nextUp": "Next Up", + "settingsContinue": "Continue", + "separate": "Separate", + "combined": "Combined", + "settingsSecurity": "Security", + "settingSecurityApplockTitle": "App lock", + "appLockTitle": "Set the log-in method for {userName}", + "@appLockTitle": { + "description": "Pop-up to pick a login method", + "placeholders": { + "userName": { + "type": "String" + } + } + }, + "biometricsFailedCheckAgain": "Biometrics failed check settings and try again", + "appLockAutoLogin": "Auto login", + "appLockPasscode": "Passcode", + "appLockBiometrics": "Biometrics", + "settingsPlayerVideoHWAccelTitle": "Hardware acceleration", + "settingsPlayerVideoHWAccelDesc": "Use the gpu to render video (recommended)", + "settingsPlayerNativeLibassAccelTitle": "Native libass subtitles", + "settingsPlayerNativeLibassAccelDesc": "Use video player libass subtitle renderer", + "settingsPlayerMobileWarning": "Enabling Hardware acceleration and native libass subtitles on Android might cause some subtitles to not render.", + "settingsPlayerCustomSubtitlesTitle": "Customize subtitles", + "settingsPlayerCustomSubtitlesDesc": "Customize Size, Color, Position, Outline", + "videoScalingFillScreenTitle": "Fill screen", + "videoScalingFillScreenDesc": "Fill the navigation and statusbar", + "videoScalingFillScreenNotif": "Fill-screen overwrites video fit, in horizontal rotation", + "videoScaling": "Video scaling", + "videoScalingFill": "Fill", + "videoScalingContain": "Contain", + "videoScalingCover": "Cover", + "videoScalingFitWidth": "Fit Width", + "videoScalingFitHeight": "Fit Height", + "videoScalingScaleDown": "ScaleDown", + "subtitleConfiguratorPlaceHolder": "This is placeholder text, \n nothing to see here.", + "subtitleConfigurator": "Subtitle configurator", + "refreshPopup": "Refresh - {name}", + "@refreshPopup": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "scanningName": "Scanning - {name}", + "@scanningName": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "refreshPopupContentMetadata": "Metadata is refreshed based on settings and internet services that are enabled in the Dashboard.", + "replaceExistingImages": "Replace existing images", + "metadataRefreshDefault": "Scan for new and updated files", + "metadataRefreshValidation": "Search for missing metadata", + "metadataRefreshFull": "Replace all metadata", + "syncedItems": "Synced items", + "noItemsSynced": "No items synced", + "syncDeletePopupPermanent": "This action is permanent and will remove all localy synced files", + "totalSize": "Total size: {size}", + "@totalSize": { + "placeholders": { + "size": { + "type": "String" + } + } + }, + "mediaTypeBase": "Base Type", + "mediaTypeMovie": "Movie", + "mediaTypeSeries": "Series", + "mediaTypeSeason": "Season", + "mediaTypeEpisode": "Episode", + "mediaTypePhoto": "Photo", + "mediaTypePerson": "Person", + "mediaTypePhotoAlbum": "Photo Album", + "mediaTypeFolder": "Folder", + "mediaTypeBoxset": "Boxset", + "mediaTypePlaylist": "Playlist", + "mediaTypeBook": "Book", + "actor": "{count, plural, other{Actors} one{Actor}}", + "@actor": { + "description": "actor", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "writer": "{count, plural, other{Writer} two{Writers}}", + "@writer": { + "description": "writer", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "director": "{count, plural, other{Director} two{Directors}}", + "@director": { + "description": "director", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "video": "Video", + "audio": "Audio", + "subtitles": "Subtitles", + "related": "Related", + "all": "All", + "overview": "Overview", + "selectViewType": "Select view type", + "noItemsToShow": "No items to show", + "sortBy": "Sort by", + "groupBy": "Group by", + "scrollToTop": "Scroll to top", + "disableFilters": "Disable filters", + "selectAll": "Select all", + "clearSelection": "Clear selection", + "shuffleVideos": "Shuffle videos", + "shuffleGallery": "Shuffle gallery", + "unknown": "Unknown", + "favorites": "Favorites", + "recursive": "Recursive", + "genre": "{count, plural, other{Genres} one{Genre}}", + "@genre": { + "description": "genre", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "studio": "{count, plural, other{Studios} one{Studio}}", + "@studio": { + "description": "studio", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "label": "{count, plural, other{Labels} one{Label}}", + "@label": { + "description": "label", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "group": "Group", + "type": "{count, plural, other{Types} one{Type}}", + "@type": { + "description": "type", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "filter": "{count, plural, other{Filters} one{Filter}}", + "@filter": { + "description": "filter", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "showEmpty": "Show empty", + "hideEmpty": "Hide empty", + "rating": "{count, plural, other{Ratings} one{Rating}}", + "@rating": { + "description": "rating", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "year": "{count, plural, other{Years} one{Year}}", + "@year": { + "description": "year", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "playVideos": "Play videos", + "playLabel": "Play", + "forceRefresh": "Force refresh", + "itemCount": "Item count: {count}", + "@itemCount": { + "description": "Item count", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "invalidUrl": "Invalid url", + "invalidUrlDesc": "Url needs to start with http(s)://", + "incorrectPinTryAgain": "Incorrect pin try again", + "somethingWentWrongPasswordCheck": "Something went wrong, check your password", + "unableToConnectHost": "Unable to connect to host", + "server": "Server", + "retrievePublicListOfUsers": "Retrieve public list of users", + "displayLanguage": "Display language", + "deleteItem": "Delete {item}?", + "@deleteItem": { + "description": "deleteItem", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "syncDeleteItemTitle": "Delete synced item", + "syncDeleteItemDesc": "Delete all synced data for?\n{item}", + "@syncDeleteItemDesc": { + "description": "Sync delete item pop-up window", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "syncOpenParent": "Open parent", + "syncRemoveDataTitle": "Remove synced data?", + "syncRemoveDataDesc": "Delete synced video data? This is permanent and you will need to re-sync the files", + "collectionFolder": "Collection folder", + "musicAlbum": "Album", + "active": "Active", + "name": "Name", + "result": "Result", + "close": "Close", + "replaceAllImages": "Replace all images", + "noResults": "No results", + "openWebLink": "Open web link", + "setIdentityTo": "Set identity to {name}", + "@setIdentityTo": { + "description": "setIdentityTo", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "somethingWentWrong": "Something went wrong", + "clearChanges": "Clear changes", + "useDefaults": "Use defaults", + "light": "Light", + "normal": "Normal", + "bold": "Bold", + "fontSize": "Font size", + "heightOffset": "Height offset", + "fontColor": "Font color", + "outlineColor": "Outline color", + "outlineSize": "Outline size", + "backgroundOpacity": "Background opacity", + "shadow": "Shadow", + "played": "Played", + "unPlayed": "Unplayed", + "resumable": "Resumable", + "sortOrder": "Sort order", + "sortName": "Name", + "communityRating": "Community Rating", + "parentalRating": "Parental Rating", + "dateAdded": "Date added", + "dateLastContentAdded": "Date last content added", + "favorite": "Favorite", + "datePlayed": "Date played", + "folders": "Folders", + "playCount": "Play count", + "releaseDate": "Release date", + "runTime": "Run time", + "ascending": "Ascending", + "descending": "Descending", + "minutes": "{count, plural, other{Minutes} one{Minute} }", + "@minutes": { + "description": "minute", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "seconds": "{count, plural, other{Seconds} one{Second}}", + "@seconds": { + "description": "second", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "page": "Page {index}", + "@page": { + "description": "page", + "placeholders": { + "index": { + "type": "int" + } + } + }, + "set": "Set", + "@set": { + "description": "Use for setting a certain value", + "context": "Set 'time'" + }, + "never": "Never", + "selectTime": "Select time", + "immediately": "Immediately", + "timeAndAnnotation": "{minutes} and {seconds}", + "@timeAndAnnotation": { + "description": "timeAndAnnotation", + "placeholders": { + "minutes": { + "type": "String" + }, + "seconds": { + "type": "String" + } + } + }, + "scanYourFingerprintToAuthenticate": "Scan your fingerprint to authenticate {user}", + "@scanYourFingerprintToAuthenticate": { + "placeholders": { + "user": { + "type": "String" + } + } + }, + "scanBiometricHint": "Verify identity", + "deleteFileFromSystem": "Deleting this item {item} will delete it from both the file system and your media library.\nAre you sure you wish to continue?", + "@deleteFileFromSystem": { + "description": "Delete file from system", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "notPartOfAlbum": "Not part of a album", + "retry": "Retry", + "failedToLoadImage": "Failed to load image", + "save": "Save", + "metaDataSavedFor": "Metadata saved for {item}", + "@metaDataSavedFor": { + "description": "metaDataSavedFor", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "libraryPageSizeTitle": "Library page size", + "libraryPageSizeDesc": "Set the amount to load at a time. 0 disables paging", + "fetchingLibrary": "Fetching library items", + "libraryFetchNoItemsFound": "No items found, try different settings.", + "noSuggestionsFound": "No suggestions found", + "viewPhotos": "View photos", + "random": "Random", + "tag": "{count, plural, one{Tag} other{Tags}}", + "@tag": { + "description": "tag", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "saved": "Saved", + "discovered": "Discovered", + "noServersFound": "No new servers found", + "about": "About", + "openParent": "Open parent", + "mouseDragSupport": "Drag using mouse", + "controls": "Controls" +} diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb new file mode 100644 index 0000000..f379365 --- /dev/null +++ b/lib/l10n/app_es.arb @@ -0,0 +1,669 @@ +{ + "@@locale": "es", + "switchUser": "Cambiar usuario", + "userName": "Nombre de usuario", + "password": "Contraseña", + "login": "Iniciar sesión", + "logout": "Cerrar sesión", + "cancel": "Cancelar", + "accept": "Aceptar", + "code": "Código", + "error": "Error", + "clear": "Borrar", + "days": "Días", + "search": "Buscar", + "loggedIn": "Conectado", + "change": "Cambiar", + "other": "Otro", + "dynamicText": "Dinámico", + "enabled": "Habilitado", + "disabled": "Deshabilitado", + "dashboard": "Tablero", + "advanced": "Avanzado", + "refresh": "Actualizar", + "delete": "Eliminar", + "goTo": "Ir a", + "loop": "Bucle", + "empty": "Vacío", + "noRating": "Sin calificación", + "backgroundBlur": "Desenfoque de fondo", + "autoPlay": "Reproducción automática", + "resume": "Reanudar {item}", + "@resume": { + "description": "reanudar", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "play": "Reproducir {item}", + "@play": { + "description": "Reproducir con", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "read": "Leer {item}", + "@read": { + "description": "leer", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "readFromStart": "Leer {item} desde el principio", + "@readFromStart": { + "description": "Leer libro desde el principio", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "playFrom": "Reproducir desde {name}", + "@playFrom": { + "description": "reproducir desde", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "moreFrom": "Más de {info}", + "@moreFrom": { + "description": "Más de", + "placeholders": { + "info": { + "type": "String" + } + } + }, + "selectedWith": "Seleccionado {info}", + "@selectedWith": { + "description": "seleccionado", + "placeholders": { + "info": { + "type": "String" + } + } + }, + "selected": "Seleccionado", + "restart": "Reiniciar", + "reWatch": "Volver a ver", + "options": "Opciones", + "list": "Lista", + "grid": "Cuadrícula", + "masonry": "Mampostería", + "start": "Iniciar", + "none": "Ninguno", + "chapter": "{count, plural, other{Capítulos} one{Capítulo}}", + "@chapter": { + "description": "capítulo", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "watchOn": "Ver en", + "sync": "Sincronizar", + "moreOptions": "Más opciones", + "continuePage": "Continuar - página {page}", + "@continuePage": { + "description": "Continuar - página 1", + "placeholders": { + "page": { + "type": "int" + } + } + }, + "openShow": "Abrir espectáculo", + "showDetails": "Mostrar detalles", + "showAlbum": "Mostrar álbum", + "season": "{count, plural, other{Temporadas} one{Temporada}}", + "@season": { + "description": "temporada", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "episode": "{count, plural, other{Episodios} one{Episodio}}", + "@episode": { + "description": "episodio", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "addToCollection": "Agregar a la colección", + "addToPlaylist": "Agregar a la lista de reproducción", + "removeFromCollection": "Eliminar de la colección", + "removeFromPlaylist": "Eliminar de la lista de reproducción", + "markAsWatched": "Marcar como visto", + "markAsUnwatched": "Marcar como no visto", + "removeAsFavorite": "Eliminar como favorito", + "addAsFavorite": "Agregar como favorito", + "editMetadata": "Editar metadatos", + "refreshMetadata": "Actualizar metadatos", + "syncDetails": "Sincronizar detalles", + "identify": "Identificar", + "info": "Información", + "clearAllSettings": "Borrar todos los ajustes", + "clearAllSettingsQuestion": "¿Borrar todos los ajustes?", + "unableToReverseAction": "Esta acción no se puede deshacer, eliminará todos los ajustes.", + "navigationDashboard": "Tablero", + "navigationFavorites": "Favoritos", + "navigationSync": "Sincronizado", + "navigation": "Navegación", + "library": "{count, plural, other{Bibliotecas} one{Biblioteca}}", + "@library": { + "description": "plural", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "scanLibrary": "Escanear biblioteca", + "dashboardContinue": "Continuar", + "dashboardContinueWatching": "Continuar viendo", + "dashboardContinueReading": "Continuar leyendo", + "dashboardContinueListening": "Continuar escuchando", + "dashboardNextUp": "Próximo", + "dashboardRecentlyAdded": "Recientemente añadido en {name}", + "@dashboardRecentlyAdded": { + "description": "Recientemente añadido en la pantalla de inicio", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "settings": "Ajustes", + "settingsClientTitle": "Fladder", + "settingsClientDesc": "General, Tiempo de espera, Diseño, Tema", + "settingsQuickConnectTitle": "Conexión rápida", + "settingsProfileTitle": "Perfil", + "settingsProfileDesc": "Pantalla de bloqueo", + "settingsPlayerTitle": "Reproductor", + "settingsPlayerDesc": "Relación de aspecto, Avanzado", + "logoutUserPopupTitle": "¿Cerrar sesión del usuario {userName}?", + "@logoutUserPopupTitle": { + "description": "Pop-up para cerrar sesión del usuario", + "placeholders": { + "userName": { + "type": "String" + } + } + }, + "logoutUserPopupContent": "Esto cerrará la sesión de {userName} y eliminará al usuario de la aplicación.\nDeberá volver a iniciar sesión en {serverName}.", + "@logoutUserPopupContent": { + "description": "Pop-up para cerrar sesión del usuario descripción", + "placeholders": { + "userName": { + "type": "String" + }, + "serverName": { + "type": "String" + } + } + }, + "quickConnectTitle": "Conexión rápida", + "quickConnectAction": "Ingrese el código de conexión rápida para", + "quickConnectInputACode": "Ingrese un código", + "quickConnectWrongCode": "Código incorrecto", + "downloadsTitle": "Descargas", + "downloadsPath": "Ruta", + "pathEditTitle": "Cambiar ubicación", + "pathEditSelect": "Seleccionar destino de descargas", + "pathClearTitle": "Borrar ruta de descargas", + "pathEditDesc": "Esta ubicación se establece para todos los usuarios, los datos sincronizados ya no serán accesibles.\nPermanecerán en su almacenamiento.", + "downloadsSyncedData": "Datos sincronizados", + "downloadsClearTitle": "Borrar datos sincronizados", + "downloadsClearDesc": "¿Está seguro de que desea eliminar todos los datos sincronizados?\n¡Esto eliminará todos los datos de cada usuario sincronizado!", + "lockscreen": "Pantalla de bloqueo", + "timeOut": "Tiempo de espera", + "home": "Inicio", + "settingsHomeCarouselTitle": "Carrusel del tablero", + "settingsHomeCarouselDesc": "Muestra un carrusel en la pantalla del tablero", + "settingsHomeNextUpTitle": "Próximos pósteres", + "settingsHomeNextUpDesc": "Tipo de pósteres mostrados en la pantalla del tablero", + "settingsVisual": "Visual", + "settingsBlurredPlaceholderTitle": "Marcador de posición difuminado", + "settingsBlurredPlaceholderDesc": "Mostrar fondo difuminado al cargar pósteres", + "settingsBlurEpisodesTitle": "Difuminar próximos episodios", + "settingsBlurEpisodesDesc": "Difuminar todos los próximos episodios", + "settingsEnableOsMediaControls": "Habilitar controles multimedia del sistema operativo", + "settingsNextUpCutoffDays": "Días límite de próximos", + "settingsShowScaleSlider": "Mostrar control deslizante de tamaño de póster", + "settingsPosterSize": "Tamaño del póster", + "settingsPosterSlider": "Mostrar control deslizante de escala", + "settingsPosterPinch": "Pellizcar para escalar pósteres", + "theme": "Tema", + "mode": "Modo", + "themeModeSystem": "Sistema", + "themeModeLight": "Claro", + "themeModeDark": "Oscuro", + "themeColor": "Color del tema", + "color": "Color", + "amoledBlack": "Negro amoled", + "hide": "Ocultar", + "nextUp": "Próximos", + "settingsContinue": "Continuar", + "separate": "Separado", + "combined": "Combinado", + "settingsSecurity": "Seguridad", + "settingSecurityApplockTitle": "Bloqueo de aplicación", + "appLockTitle": "Establecer el método de inicio de sesión para {userName}", + "@appLockTitle": { + "description": "Pop-up para elegir un método de inicio de sesión", + "placeholders": { + "userName": { + "type": "String" + } + } + }, + "biometricsFailedCheckAgain": "Falló la biometría, verifique la configuración y vuelva a intentarlo", + "appLockAutoLogin": "Inicio de sesión automático", + "appLockPasscode": "Código de acceso", + "appLockBiometrics": "Biometría", + "settingsPlayerVideoHWAccelTitle": "Aceleración de hardware", + "settingsPlayerVideoHWAccelDesc": "Usar la gpu para renderizar video (recomendado)", + "settingsPlayerNativeLibassAccelTitle": "Subtítulos nativos libass", + "settingsPlayerNativeLibassAccelDesc": "Usar el renderizador de subtítulos libass del reproductor de video", + "settingsPlayerMobileWarning": "Habilitar la aceleración de hardware y los subtítulos libass nativos en Android puede hacer que algunos subtítulos no se rendericen.", + "settingsPlayerCustomSubtitlesTitle": "Personalizar subtítulos", + "settingsPlayerCustomSubtitlesDesc": "Personalizar tamaño, color, posición, contorno", + "videoScalingFillScreenTitle": "Llenar pantalla", + "videoScalingFillScreenDesc": "Llenar la barra de navegación y la barra de estado", + "videoScalingFillScreenNotif": "Llenar pantalla sobrescribe ajuste de video, en rotación horizontal", + "videoScaling": "Escalado de video", + "videoScalingFill": "Llenar", + "videoScalingContain": "Contener", + "videoScalingCover": "Cubrir", + "videoScalingFitWidth": "Ajustar ancho", + "videoScalingFitHeight": "Ajustar altura", + "videoScalingScaleDown": "Reducir escala", + "subtitleConfiguratorPlaceHolder": "Este es un texto de marcador de posición,\nnada que ver aquí.", + "subtitleConfigurator": "Configurador de subtítulos", + "refreshPopup": "Actualizar - {name}", + "@refreshPopup": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "scanningName": "Escaneando - {name}", + "@scanningName": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "refreshPopupContentMetadata": "Los metadatos se actualizan según la configuración y los servicios de Internet que están habilitados en el Tablero.", + "replaceExistingImages": "Reemplazar imágenes existentes", + "metadataRefreshDefault": "Buscar archivos nuevos y actualizados", + "metadataRefreshValidation": "Buscar metadatos faltantes", + "metadataRefreshFull": "Reemplazar todos los metadatos", + "syncedItems": "Elementos sincronizados", + "noItemsSynced": "No hay elementos sincronizados", + "syncDeletePopupPermanent": "Esta acción es permanente y eliminará todos los archivos sincronizados localmente", + "totalSize": "Tamaño total: {size}", + "@totalSize": { + "placeholders": { + "size": { + "type": "String" + } + } + }, + "mediaTypeBase": "Tipo base", + "mediaTypeMovie": "Película", + "mediaTypeSeries": "Serie", + "mediaTypeSeason": "Temporada", + "mediaTypeEpisode": "Episodio", + "mediaTypePhoto": "Foto", + "mediaTypePerson": "Persona", + "mediaTypePhotoAlbum": "Álbum de fotos", + "mediaTypeFolder": "Carpeta", + "mediaTypeBoxset": "Conjunto de cajas", + "mediaTypePlaylist": "Lista de reproducción", + "mediaTypeBook": "Libro", + "actor": "{count, plural, other{Actores} one{Actor}}", + "@actor": { + "description": "actor", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "writer": "{count, plural, other{Escritores} one{Escritor}}", + "@writer": { + "description": "escritor", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "director": "{count, plural, other{Directores} one{Director}}", + "@director": { + "description": "director", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "video": "Video", + "audio": "Audio", + "subtitles": "Subtítulos", + "related": "Relacionado", + "all": "Todo", + "overview": "Visión general", + "selectViewType": "Seleccionar tipo de vista", + "noItemsToShow": "No hay elementos para mostrar", + "sortBy": "Ordenar por", + "groupBy": "Agrupar por", + "scrollToTop": "Desplazarse hacia arriba", + "disableFilters": "Deshabilitar filtros", + "selectAll": "Seleccionar todo", + "clearSelection": "Borrar selección", + "shuffleVideos": "Videos aleatorios", + "shuffleGallery": "Galería aleatoria", + "unknown": "Desconocido", + "favorites": "Favoritos", + "recursive": "Recursivo", + "genre": "{count, plural, other{Géneros} one{Género}}", + "@genre": { + "description": "género", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "studio": "{count, plural, other{Estudios} one{Estudio}}", + "@studio": { + "description": "estudio", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "label": "{count, plural, other{Etiquetas} one{Etiqueta}}", + "@label": { + "description": "etiqueta", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "group": "Grupo", + "type": "{count, plural, other{Tipos} one{Tipo}}", + "@type": { + "description": "tipo", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "filter": "{count, plural, other{Filtros} one{Filtro}}", + "@filter": { + "description": "filtro", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "showEmpty": "Mostrar vacío", + "hideEmpty": "Ocultar vacío", + "rating": "{count, plural, other{Calificaciones} one{Calificación}}", + "@rating": { + "description": "calificación", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "year": "{count, plural, other{Años} one{Año}}", + "@year": { + "description": "año", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "playVideos": "Reproducir videos", + "playLabel": "Reproducir", + "forceRefresh": "Actualizar a la fuerza", + "itemCount": "Cantidad de elementos: {count}", + "@itemCount": { + "description": "Cantidad de elementos", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "invalidUrl": "URL inválida", + "invalidUrlDesc": "La URL debe comenzar con http(s)://", + "incorrectPinTryAgain": "PIN incorrecto, intente nuevamente", + "somethingWentWrongPasswordCheck": "Algo salió mal, verifique su contraseña", + "unableToConnectHost": "No se puede conectar al host", + "server": "Servidor", + "retrievePublicListOfUsers": "Recuperar lista pública de usuarios", + "displayLanguage": "Idioma de visualización", + "deleteItem": "¿Eliminar {item}?", + "@deleteItem": { + "description": "deleteItem", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "syncDeleteItemTitle": "Eliminar elemento sincronizado", + "syncDeleteItemDesc": "¿Eliminar todos los datos sincronizados de?\n{item}", + "@syncDeleteItemDesc": { + "description": "Ventana emergente de eliminación de elemento sincronizado", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "syncOpenParent": "Abrir padre", + "syncRemoveDataTitle": "¿Eliminar datos sincronizados?", + "syncRemoveDataDesc": "¿Eliminar los datos de video sincronizados? Esto es permanente y necesitarás volver a sincronizar los archivos", + "collectionFolder": "Carpeta de colección", + "musicAlbum": "Álbum", + "active": "Activo", + "name": "Nombre", + "result": "Resultado", + "close": "Cerrar", + "replaceAllImages": "Reemplazar todas las imágenes", + "noResults": "Sin resultados", + "openWebLink": "Abrir enlace web", + "setIdentityTo": "Establecer identidad a {name}", + "@setIdentityTo": { + "description": "setIdentityTo", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "somethingWentWrong": "Algo salió mal", + "clearChanges": "Borrar cambios", + "useDefaults": "Usar valores predeterminados", + "light": "Ligero", + "normal": "Normal", + "bold": "Negrita", + "fontSize": "Tamaño de fuente", + "heightOffset": "Desplazamiento de altura", + "fontColor": "Color de fuente", + "outlineColor": "Color del contorno", + "outlineSize": "Tamaño del contorno", + "backgroundOpacity": "Opacidad de fondo", + "shadow": "Sombra", + "played": "Reproducido", + "unPlayed": "No reproducido", + "resumable": "Reanudable", + "sortOrder": "Orden de clasificación", + "sortName": "Nombre", + "communityRating": "Calificación de la comunidad", + "parentalRating": "Calificación parental", + "dateAdded": "Fecha de añadido", + "dateLastContentAdded": "Fecha del último contenido añadido", + "favorite": "Favorito", + "datePlayed": "Fecha de reproducción", + "folders": "Carpetas", + "playCount": "Conteo de reproducciones", + "releaseDate": "Fecha de lanzamiento", + "runTime": "Duración", + "ascending": "Ascendente", + "descending": "Descendente", + "playFromStart": "Reproducir {name} desde el principio", + "@playFromStart": { + "description": "reproducir desde el inicio", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "minutes": "{count, plural, other{Minutos} one{Minuto}}", + "@minutes": { + "description": "minuto", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "seconds": "{count, plural, other{Segundos} one{Segundo}}", + "@seconds": { + "description": "segundo", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "page": "Página {index}", + "@page": { + "description": "página", + "placeholders": { + "index": { + "type": "int" + } + } + }, + "set": "Establecer", + "@set": { + "description": "Usar para establecer un cierto valor", + "context": "Establecer 'tiempo'" + }, + "never": "Nunca", + "selectTime": "Seleccionar hora", + "immediately": "Inmediatamente", + "timeAndAnnotation": "{minutes} y {seconds}", + "@timeAndAnnotation": { + "description": "timeAndAnnotation", + "placeholders": { + "minutes": { + "type": "String" + }, + "seconds": { + "type": "String" + } + } + }, + "scanYourFingerprintToAuthenticate": "Escanea tu huella digital para autenticar a {user}", + "@scanYourFingerprintToAuthenticate": { + "placeholders": { + "user": { + "type": "String" + } + } + }, + "scanBiometricHint": "Verificar identidad", + "deleteFileFromSystem": "Eliminar este elemento {item} lo eliminará tanto del sistema de archivos como de su biblioteca multimedia.\n¿Estás seguro de que deseas continuar?", + "@deleteFileFromSystem": { + "description": "Eliminar archivo del sistema", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "notPartOfAlbum": "No forma parte de un álbum", + "retry": "Reintentar", + "failedToLoadImage": "Error al cargar la imagen", + "save": "Guardar", + "metaDataSavedFor": "Metadatos guardados para {item}", + "@metaDataSavedFor": { + "description": "metadatosGuardadosPara", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "libraryPageSizeTitle": "Tamaño de página de la biblioteca", + "libraryPageSizeDesc": "Establece la cantidad a cargar a la vez. 0 desactiva el paginado.", + "fetchingLibrary": "Cargando elementos de la biblioteca", + "libraryFetchNoItemsFound": "No se encontraron elementos, intenta con diferentes configuraciones.", + "noSuggestionsFound": "No se encontraron sugerencias", + "viewPhotos": "Ver fotos", + "random": "Aleatorio", + "tag": "{count, plural, one{Etiqueta} other{Etiquetas}}", + "@tag": { + "description": "etiqueta", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "saved": "Guardado", + "discovered": "Descubierto", + "noServersFound": "No se encontraron nuevos servidores", + "about": "Acerca de", + "openParent": "Abrir carpeta superior", + "mouseDragSupport": "Arrastrar con el ratón", + "controls": "Controles" +} diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb new file mode 100644 index 0000000..8ccb46e --- /dev/null +++ b/lib/l10n/app_fr.arb @@ -0,0 +1,669 @@ +{ + "@@locale": "fr", + "switchUser": "Changer d'utilisateur", + "userName": "Nom d'utilisateur", + "password": "Mot de passe", + "login": "Connexion", + "logout": "Déconnexion", + "cancel": "Annuler", + "accept": "Accepter", + "code": "Code", + "error": "Erreur", + "clear": "Effacer", + "days": "Jours", + "search": "Recherche", + "loggedIn": "Connecté", + "change": "Changer", + "other": "Autre", + "dynamicText": "Dynamique", + "enabled": "Activé", + "disabled": "Désactivé", + "dashboard": "Tableau de bord", + "advanced": "Avancé", + "refresh": "Rafraîchir", + "delete": "Supprimer", + "goTo": "Aller à", + "loop": "Boucle", + "empty": "Vide", + "noRating": "Pas de note", + "backgroundBlur": "Flou de fond", + "autoPlay": "Lecture automatique", + "resume": "Reprendre {item}", + "@resume": { + "description": "reprendre", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "play": "Lire {item}", + "@play": { + "description": "Lire avec", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "read": "Lire {item}", + "@read": { + "description": "lire", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "readFromStart": "Lire {item} depuis le début", + "@readFromStart": { + "description": "Lire le livre depuis le début", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "playFrom": "Lire depuis {name}", + "@playFrom": { + "description": "jouer de", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "moreFrom": "Plus de {info}", + "@moreFrom": { + "description": "Plus de", + "placeholders": { + "info": { + "type": "String" + } + } + }, + "selectedWith": "Sélectionné {info}", + "@selectedWith": { + "description": "sélectionné", + "placeholders": { + "info": { + "type": "String" + } + } + }, + "selected": "Sélectionné", + "restart": "Redémarrer", + "reWatch": "Revoir", + "watchOn": "Regarder sur", + "options": "Options", + "list": "Liste", + "grid": "Grille", + "masonry": "Maçonnerie", + "start": "Commencer", + "none": "Aucun", + "chapter": "{count, plural, other{Chapitres} one{Chapitre}}", + "@chapter": { + "description": "chapitre", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "sync": "Synchroniser", + "moreOptions": "Plus d'options", + "continuePage": "Continuer - page {page}", + "@continuePage": { + "description": "Continuer - page 1", + "placeholders": { + "page": { + "type": "int" + } + } + }, + "openShow": "Ouvrir le spectacle", + "showDetails": "Afficher les détails", + "showAlbum": "Afficher l'album", + "season": "{count, plural, other{Saisons} one{Saison}}", + "@season": { + "description": "saison", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "episode": "{count, plural, other{Épisodes} one{Épisode}}", + "@episode": { + "description": "épisode", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "addToCollection": "Ajouter à la collection", + "addToPlaylist": "Ajouter à la playlist", + "removeFromCollection": "Retirer de la collection", + "removeFromPlaylist": "Retirer de la playlist", + "markAsWatched": "Marquer comme regardé", + "markAsUnwatched": "Marquer comme non regardé", + "removeAsFavorite": "Retirer des favoris", + "addAsFavorite": "Ajouter aux favoris", + "editMetadata": "Modifier les métadonnées", + "refreshMetadata": "Rafraîchir les métadonnées", + "syncDetails": "Synchroniser les détails", + "identify": "Identifier", + "info": "Infos", + "clearAllSettings": "Effacer tous les paramètres", + "clearAllSettingsQuestion": "Effacer tous les paramètres?", + "unableToReverseAction": "Cette action ne peut pas être annulée, elle supprimera tous les paramètres.", + "navigationDashboard": "Tableau de bord", + "navigationFavorites": "Favoris", + "navigationSync": "Synchronisé", + "navigation": "Navigation", + "library": "{count, plural, other{Bibliothèques} one{Bibliothèque}}", + "@library": { + "description": "pluriel", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "scanLibrary": "Scanner la bibliothèque", + "dashboardContinue": "Continuer", + "dashboardContinueWatching": "Continuer à regarder", + "dashboardContinueReading": "Continuer à lire", + "dashboardContinueListening": "Continuer à écouter", + "dashboardNextUp": "Suivant", + "dashboardRecentlyAdded": "Récemment ajouté dans {name}", + "@dashboardRecentlyAdded": { + "description": "Récemment ajouté sur l'écran d'accueil", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "settings": "Paramètres", + "settingsClientTitle": "Fladder", + "settingsClientDesc": "Général, Timeout, Disposition, Thème", + "settingsQuickConnectTitle": "Connexion rapide", + "settingsProfileTitle": "Profil", + "settingsProfileDesc": "Écran de verrouillage", + "settingsPlayerTitle": "Lecteur", + "settingsPlayerDesc": "Ratio, Avancé", + "logoutUserPopupTitle": "Déconnecter l'utilisateur {userName}?", + "@logoutUserPopupTitle": { + "description": "Pop-up pour déconnecter l'utilisateur", + "placeholders": { + "userName": { + "type": "String" + } + } + }, + "logoutUserPopupContent": "Cela déconnectera {userName} et supprimera l'utilisateur de l'application.\nVous devrez vous reconnecter à {serverName}.", + "@logoutUserPopupContent": { + "description": "Pop-up pour déconnecter l'utilisateur description", + "placeholders": { + "userName": { + "type": "String" + }, + "serverName": { + "type": "String" + } + } + }, + "quickConnectTitle": "Connexion rapide", + "quickConnectAction": "Entrer le code de connexion rapide pour", + "quickConnectInputACode": "Entrer un code", + "quickConnectWrongCode": "Code incorrect", + "downloadsTitle": "Téléchargements", + "downloadsPath": "Chemin", + "pathEditTitle": "Changer l'emplacement", + "pathEditSelect": "Sélectionner la destination des téléchargements", + "pathClearTitle": "Effacer le chemin de téléchargement", + "pathEditDesc": "Cet emplacement est défini pour tous les utilisateurs, toutes les données synchronisées ne seront plus accessibles.\nElles resteront sur votre stockage.", + "downloadsSyncedData": "Données synchronisées", + "downloadsClearTitle": "Effacer les données synchronisées", + "downloadsClearDesc": "Êtes-vous sûr de vouloir supprimer toutes les données synchronisées?\nCela effacera toutes les données pour chaque utilisateur synchronisé!", + "lockscreen": "Écran de verrouillage", + "timeOut": "Timeout", + "home": "Accueil", + "settingsHomeCarouselTitle": "Carrousel du tableau de bord", + "settingsHomeCarouselDesc": "Affiche un carrousel sur l'écran du tableau de bord", + "settingsHomeNextUpTitle": "Affiches à venir", + "settingsHomeNextUpDesc": "Type d'affiches affichées sur l'écran du tableau de bord", + "settingsVisual": "Visuel", + "settingsBlurredPlaceholderTitle": "Placeholder flou", + "settingsBlurredPlaceholderDesc": "Afficher un arrière-plan flou lors du chargement des affiches", + "settingsBlurEpisodesTitle": "Flouter les prochains épisodes", + "settingsBlurEpisodesDesc": "Flouter tous les épisodes à venir", + "settingsEnableOsMediaControls": "Activer les contrôles multimédia de l'OS", + "settingsNextUpCutoffDays": "Jours de coupure suivants", + "settingsShowScaleSlider": "Afficher le curseur de taille des affiches", + "settingsPosterSize": "Taille de l'affiche", + "settingsPosterSlider": "Afficher le curseur de mise à l'échelle", + "settingsPosterPinch": "Pincer pour zoomer pour mettre à l'échelle les affiches", + "theme": "Thème", + "mode": "Mode", + "themeModeSystem": "Système", + "themeModeLight": "Clair", + "themeModeDark": "Sombre", + "themeColor": "Couleur du thème", + "color": "Couleur", + "amoledBlack": "Noir Amoled", + "hide": "Cacher", + "nextUp": "Suivant", + "settingsContinue": "Continuer", + "separate": "Séparer", + "combined": "Combiné", + "settingsSecurity": "Sécurité", + "settingSecurityApplockTitle": "Verrouillage de l'application", + "appLockTitle": "Définir la méthode de connexion pour {userName}", + "@appLockTitle": { + "description": "Pop-up pour choisir une méthode de connexion", + "placeholders": { + "userName": { + "type": "String" + } + } + }, + "biometricsFailedCheckAgain": "Échec de la biométrie, vérifiez les paramètres et réessayez", + "appLockAutoLogin": "Connexion automatique", + "appLockPasscode": "Code d'accès", + "appLockBiometrics": "Biométrie", + "settingsPlayerVideoHWAccelTitle": "Accélération matérielle", + "settingsPlayerVideoHWAccelDesc": "Utiliser le GPU pour rendre la vidéo (recommandé)", + "settingsPlayerNativeLibassAccelTitle": "Sous-titres natifs libass", + "settingsPlayerNativeLibassAccelDesc": "Utiliser le rendu des sous-titres libass du lecteur vidéo", + "settingsPlayerMobileWarning": "L'activation de l'accélération matérielle et des sous-titres natifs libass sur Android peut empêcher certains sous-titres de s'afficher.", + "settingsPlayerCustomSubtitlesTitle": "Personnaliser les sous-titres", + "settingsPlayerCustomSubtitlesDesc": "Personnaliser la taille, la couleur, la position, le contour", + "videoScalingFillScreenTitle": "Remplir l'écran", + "videoScalingFillScreenDesc": "Remplir la barre de navigation et la barre d'état", + "videoScalingFillScreenNotif": "Le remplissage de l'écran écrase l'ajustement de la vidéo, en rotation horizontale", + "videoScaling": "Mise à l'échelle de la vidéo", + "videoScalingFill": "Remplir", + "videoScalingContain": "Contenir", + "videoScalingCover": "Couverture", + "videoScalingFitWidth": "Ajuster la largeur", + "videoScalingFitHeight": "Ajuster la hauteur", + "videoScalingScaleDown": "Réduire l'échelle", + "subtitleConfiguratorPlaceHolder": "Ceci est un texte de placeholder,\nrien à voir ici.", + "subtitleConfigurator": "Configurateur de sous-titres", + "refreshPopup": "Rafraîchir - {name}", + "@refreshPopup": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "scanningName": "Analyse - {name}", + "@scanningName": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "refreshPopupContentMetadata": "Les métadonnées sont mises à jour en fonction des paramètres et des services Internet activés dans le tableau de bord.", + "replaceExistingImages": "Remplacer les images existantes", + "metadataRefreshDefault": "Rechercher des fichiers nouveaux et mis à jour", + "metadataRefreshValidation": "Rechercher des métadonnées manquantes", + "metadataRefreshFull": "Remplacer toutes les métadonnées", + "syncedItems": "Éléments synchronisés", + "noItemsSynced": "Aucun élément synchronisé", + "syncDeletePopupPermanent": "Cette action est permanente et supprimera tous les fichiers synchronisés localement", + "totalSize": "Taille totale : {size}", + "@totalSize": { + "placeholders": { + "size": { + "type": "String" + } + } + }, + "mediaTypeBase": "Type de base", + "mediaTypeMovie": "Film", + "mediaTypeSeries": "Série", + "mediaTypeSeason": "Saison", + "mediaTypeEpisode": "Épisode", + "mediaTypePhoto": "Photo", + "mediaTypePerson": "Personne", + "mediaTypePhotoAlbum": "Album photo", + "mediaTypeFolder": "Dossier", + "mediaTypeBoxset": "Coffret", + "mediaTypePlaylist": "Liste de lecture", + "mediaTypeBook": "Livre", + "actor": "{count, plural, other{Acteurs} one{Acteur}}", + "@actor": { + "description": "acteur", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "writer": "{count, plural, other{Écrivains} one{Écrivain}}", + "@writer": { + "description": "écrivain", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "director": "{count, plural, other{Réalisateurs} one{Réalisateur}}", + "@director": { + "description": "réalisateur", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "video": "Vidéo", + "audio": "Audio", + "subtitles": "Sous-titres", + "related": "Lié", + "all": "Tout", + "overview": "Aperçu", + "selectViewType": "Sélectionner le type de vue", + "noItemsToShow": "Aucun élément à afficher", + "sortBy": "Trier par", + "groupBy": "Grouper par", + "scrollToTop": "Défiler vers le haut", + "disableFilters": "Désactiver les filtres", + "selectAll": "Tout sélectionner", + "clearSelection": "Effacer la sélection", + "shuffleVideos": "Mélanger les vidéos", + "shuffleGallery": "Mélanger la galerie", + "unknown": "Inconnu", + "favorites": "Favoris", + "recursive": "Récursif", + "genre": "{count, plural, other{Genres} one{Genre}}", + "@genre": { + "description": "genre", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "studio": "{count, plural, other{Studios} one{Studio}}", + "@studio": { + "description": "studio", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "label": "{count, plural, other{Étiquettes} one{Étiquette}}", + "@label": { + "description": "étiquette", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "group": "Groupe", + "type": "{count, plural, other{Types} one{Type}}", + "@type": { + "description": "type", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "filter": "{count, plural, other{Filtres} one{Filtre}}", + "@filter": { + "description": "filtre", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "showEmpty": "Afficher vide", + "hideEmpty": "Cacher vide", + "rating": "{count, plural, other{Notes} one{Note}}", + "@rating": { + "description": "note", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "year": "{count, plural, other{Années} one{Année}}", + "@year": { + "description": "année", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "playVideos": "Lire les vidéos", + "playLabel": "Lire", + "forceRefresh": "Forcer le rafraîchissement", + "itemCount": "Nombre d'éléments: {count}", + "@itemCount": { + "description": "Nombre d'éléments", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "invalidUrl": "URL invalide", + "invalidUrlDesc": "L'URL doit commencer par http(s)://", + "incorrectPinTryAgain": "PIN incorrect, réessayez", + "somethingWentWrongPasswordCheck": "Quelque chose s'est mal passé, vérifiez votre mot de passe", + "unableToConnectHost": "Impossible de se connecter à l'hôte", + "server": "Serveur", + "retrievePublicListOfUsers": "Récupérer la liste publique des utilisateurs", + "displayLanguage": "Langue d'affichage", + "deleteItem": "Supprimer {item}?", + "@deleteItem": { + "description": "deleteItem", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "syncDeleteItemTitle": "Supprimer l'élément synchronisé", + "syncDeleteItemDesc": "Supprimer toutes les données synchronisées pour?\n{item}", + "@syncDeleteItemDesc": { + "description": "Fenêtre contextuelle de suppression d'élément synchronisé", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "syncOpenParent": "Ouvrir le parent", + "syncRemoveDataTitle": "Supprimer les données synchronisées?", + "syncRemoveDataDesc": "Supprimer les données vidéo synchronisées? Ceci est permanent et vous devrez resynchroniser les fichiers", + "collectionFolder": "Dossier de collection", + "musicAlbum": "Album", + "active": "Actif", + "name": "Nom", + "result": "Résultat", + "close": "Fermer", + "replaceAllImages": "Remplacer toutes les images", + "noResults": "Aucun résultat", + "openWebLink": "Ouvrir le lien web", + "setIdentityTo": "Définir l'identité sur {name}", + "@setIdentityTo": { + "description": "setIdentityTo", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "somethingWentWrong": "Quelque chose a mal tourné", + "clearChanges": "Effacer les modifications", + "useDefaults": "Utiliser les paramètres par défaut", + "light": "Léger", + "normal": "Normal", + "bold": "Gras", + "fontSize": "Taille de la police", + "heightOffset": "Décalage de hauteur", + "fontColor": "Couleur de la police", + "outlineColor": "Couleur du contour", + "outlineSize": "Taille du contour", + "backgroundOpacity": "Opacité de l'arrière-plan", + "shadow": "Ombre", + "played": "Joué", + "unPlayed": "Non joué", + "resumable": "Reprenable", + "sortOrder": "Ordre de tri", + "sortName": "Nom", + "communityRating": "Évaluation de la communauté", + "parentalRating": "Évaluation parentale", + "dateAdded": "Date d'ajout", + "dateLastContentAdded": "Date du dernier contenu ajouté", + "favorite": "Favori", + "datePlayed": "Date de lecture", + "folders": "Dossiers", + "playCount": "Nombre de lectures", + "releaseDate": "Date de sortie", + "runTime": "Durée", + "ascending": "Ascendant", + "descending": "Descendant", + "playFromStart": "Lire {name} depuis le début", + "@playFromStart": { + "description": "jouer depuis le début", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "minutes": "{count, plural, other{Minutes} one{Minute}}", + "@minutes": { + "description": "minute", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "seconds": "{count, plural, other{Secondes} one{Seconde}}", + "@seconds": { + "description": "seconde", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "page": "Page {index}", + "@page": { + "description": "page", + "placeholders": { + "index": { + "type": "int" + } + } + }, + "set": "Régler", + "@set": { + "description": "Utiliser pour définir une certaine valeur", + "context": "Régler 'heure'" + }, + "never": "Jamais", + "selectTime": "Sélectionner l'heure", + "immediately": "Immédiatement", + "timeAndAnnotation": "{minutes} et {seconds}", + "@timeAndAnnotation": { + "description": "timeAndAnnotation", + "placeholders": { + "minutes": { + "type": "String" + }, + "seconds": { + "type": "String" + } + } + }, + "scanYourFingerprintToAuthenticate": "Scannez votre empreinte digitale pour authentifier {user}", + "@scanYourFingerprintToAuthenticate": { + "placeholders": { + "user": { + "type": "String" + } + } + }, + "scanBiometricHint": "Vérifier identité", + "deleteFileFromSystem": "Supprimer cet élément {item} le supprimera à la fois du système de fichiers et de votre bibliothèque multimédia.\nÊtes-vous sûr de vouloir continuer?", + "@deleteFileFromSystem": { + "description": "Supprimer le fichier du système", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "notPartOfAlbum": "Ne fait pas partie d'un album", + "retry": "Réessayer", + "failedToLoadImage": "Échec du chargement de l'image", + "save": "Enregistrer", + "metaDataSavedFor": "Métadonnées enregistrées pour {item}", + "@metaDataSavedFor": { + "description": "métadonnéesEnregistréesPour", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "libraryPageSizeTitle": "Taille de la page de la bibliothèque", + "libraryPageSizeDesc": "Définir la quantité à charger à la fois. 0 désactive la pagination.", + "fetchingLibrary": "Chargement des éléments de la bibliothèque", + "libraryFetchNoItemsFound": "Aucun élément trouvé, essayez avec des paramètres différents.", + "noSuggestionsFound": "Aucune suggestion trouvée", + "viewPhotos": "Voir les photos", + "random": "Aléatoire", + "tag": "{count, plural, one{Étiquette} other{Étiquettes}}", + "@tag": { + "description": "étiquette", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "saved": "Enregistré", + "discovered": "Découvert", + "noServersFound": "Aucun nouveau serveur trouvé", + "about": "À propos", + "openParent": "Ouvrir le dossier parent", + "mouseDragSupport": "Faire glisser avec la souris", + "controls": "Commandes" +} diff --git a/lib/l10n/app_jp.arb b/lib/l10n/app_jp.arb new file mode 100644 index 0000000..155faea --- /dev/null +++ b/lib/l10n/app_jp.arb @@ -0,0 +1,669 @@ +{ + "@@locale": "ja", + "switchUser": "ユーザーを切り替える", + "userName": "ユーザー名", + "password": "パスワード", + "login": "ログイン", + "logout": "ログアウト", + "cancel": "キャンセル", + "accept": "承認", + "code": "コード", + "error": "エラー", + "clear": "クリア", + "days": "日", + "search": "検索", + "loggedIn": "ログイン済み", + "change": "変更", + "other": "その他", + "dynamicText": "動的", + "enabled": "有効", + "disabled": "無効", + "dashboard": "ダッシュボード", + "advanced": "高度な", + "refresh": "リフレッシュ", + "delete": "削除", + "goTo": "行く", + "loop": "ループ", + "empty": "空", + "noRating": "評価なし", + "backgroundBlur": "背景ぼかし", + "autoPlay": "自動再生", + "resume": "{item}を再開する", + "@resume": { + "description": "再開する", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "play": "{item}を再生する", + "@play": { + "description": "再生する", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "read": "{item}を読む", + "@read": { + "description": "読む", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "readFromStart": "{item}を最初から読む", + "@readFromStart": { + "description": "最初から読む", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "playFrom": "{name}から再生する", + "@playFrom": { + "description": "から再生する", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "moreFrom": "{info}の詳細", + "@moreFrom": { + "description": "詳細", + "placeholders": { + "info": { + "type": "String" + } + } + }, + "selectedWith": "{info}を選択済み", + "@selectedWith": { + "description": "選択済み", + "placeholders": { + "info": { + "type": "String" + } + } + }, + "selected": "選択済み", + "restart": "再起動", + "reWatch": "再視聴", + "watchOn": "で見る", + "options": "オプション", + "list": "リスト", + "grid": "グリッド", + "masonry": "石工", + "start": "スタート", + "none": "なし", + "chapter": "{count, plural, other{チャプター} one{チャプター}}", + "@chapter": { + "description": "チャプター", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "sync": "同期", + "moreOptions": "その他のオプション", + "continuePage": "続行 - ページ {page}", + "@continuePage": { + "description": "続行 - ページ 1", + "placeholders": { + "page": { + "type": "int" + } + } + }, + "openShow": "番組を開く", + "showDetails": "詳細を表示", + "showAlbum": "アルバムを表示", + "season": "{count, plural, other{シーズン} one{シーズン}}", + "@season": { + "description": "シーズン", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "episode": "{count, plural, other{エピソード} one{エピソード}}", + "@episode": { + "description": "エピソード", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "addToCollection": "コレクションに追加", + "addToPlaylist": "プレイリストに追加", + "removeFromCollection": "コレクションから削除", + "removeFromPlaylist": "プレイリストから削除", + "markAsWatched": "視聴済みにマーク", + "markAsUnwatched": "未視聴にマーク", + "removeAsFavorite": "お気に入りから削除", + "addAsFavorite": "お気に入りに追加", + "editMetadata": "メタデータを編集", + "refreshMetadata": "メタデータを更新", + "syncDetails": "詳細を同期", + "identify": "識別", + "info": "情報", + "clearAllSettings": "すべての設定をクリア", + "clearAllSettingsQuestion": "すべての設定をクリアしますか?", + "unableToReverseAction": "この操作は元に戻せません。すべての設定が削除されます。", + "navigationDashboard": "ダッシュボード", + "navigationFavorites": "お気に入り", + "navigationSync": "同期済み", + "navigation": "ナビゲーション", + "library": "{count, plural, other{ライブラリ} one{ライブラリ}}", + "@library": { + "description": "複数", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "scanLibrary": "ライブラリをスキャン", + "dashboardContinue": "続行", + "dashboardContinueWatching": "視聴を続ける", + "dashboardContinueReading": "読み続ける", + "dashboardContinueListening": "リスニングを続ける", + "dashboardNextUp": "次へ", + "dashboardRecentlyAdded": "{name}に最近追加", + "@dashboardRecentlyAdded": { + "description": "ホーム画面に最近追加", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "settings": "設定", + "settingsClientTitle": "Fladder", + "settingsClientDesc": "一般, タイムアウト, レイアウト, テーマ", + "settingsQuickConnectTitle": "クイック接続", + "settingsProfileTitle": "プロフィール", + "settingsProfileDesc": "ロック画面", + "settingsPlayerTitle": "プレーヤー", + "settingsPlayerDesc": "アスペクト比, 高度な", + "logoutUserPopupTitle": "ユーザー {userName} をログアウトしますか?", + "@logoutUserPopupTitle": { + "description": "ユーザーをログアウトするためのポップアップ", + "placeholders": { + "userName": { + "type": "String" + } + } + }, + "logoutUserPopupContent": "これにより、{userName} がログアウトされ、アプリからユーザーが削除されます。\n{serverName}に再ログインする必要があります。", + "@logoutUserPopupContent": { + "description": "ユーザーをログアウトするためのポップアップの説明", + "placeholders": { + "userName": { + "type": "String" + }, + "serverName": { + "type": "String" + } + } + }, + "quickConnectTitle": "クイック接続", + "quickConnectAction": "クイック接続コードを入力", + "quickConnectInputACode": "コードを入力", + "quickConnectWrongCode": "コードが間違っています", + "downloadsTitle": "ダウンロード", + "downloadsPath": "パス", + "pathEditTitle": "場所を変更", + "pathEditSelect": "ダウンロード先を選択", + "pathClearTitle": "ダウンロードパスをクリア", + "pathEditDesc": "この場所はすべてのユーザーに設定されており、同期されたデータはもうアクセスできません。\nストレージに残ります。", + "downloadsSyncedData": "同期データ", + "downloadsClearTitle": "同期データをクリア", + "downloadsClearDesc": "すべての同期データを削除してもよろしいですか?\nこれにより、すべての同期ユーザーのデータがクリアされます!", + "lockscreen": "ロック画面", + "timeOut": "タイムアウト", + "home": "ホーム", + "settingsHomeCarouselTitle": "ダッシュボードのカルーセル", + "settingsHomeCarouselDesc": "ダッシュボード画面にカルーセルを表示", + "settingsHomeNextUpTitle": "次のポスター", + "settingsHomeNextUpDesc": "ダッシュボード画面に表示されるポスターの種類", + "settingsVisual": "ビジュアル", + "settingsBlurredPlaceholderTitle": "ぼかしプレースホルダー", + "settingsBlurredPlaceholderDesc": "ポスターの読み込み中にぼかし背景を表示", + "settingsBlurEpisodesTitle": "次のエピソードをぼかす", + "settingsBlurEpisodesDesc": "次のエピソードをすべてぼかす", + "settingsEnableOsMediaControls": "OSメディアコントロールを有効にする", + "settingsNextUpCutoffDays": "次のカットオフ日", + "settingsShowScaleSlider": "ポスターサイズスライダーを表示", + "settingsPosterSize": "ポスターサイズ", + "settingsPosterSlider": "スケールスライダーを表示", + "settingsPosterPinch": "ポスターをスケールするためにピンチズーム", + "theme": "テーマ", + "mode": "モード", + "themeModeSystem": "システム", + "themeModeLight": "ライト", + "themeModeDark": "ダーク", + "themeColor": "テーマカラー", + "color": "カラー", + "amoledBlack": "アモレッドブラック", + "hide": "非表示", + "nextUp": "次へ", + "settingsContinue": "続行", + "separate": "分離", + "combined": "組み合わせ", + "settingsSecurity": "セキュリティ", + "settingSecurityApplockTitle": "アプリロック", + "appLockTitle": "{userName}のログイン方法を設定", + "@appLockTitle": { + "description": "ログイン方法を選択するポップアップ", + "placeholders": { + "userName": { + "type": "String" + } + } + }, + "biometricsFailedCheckAgain": "生体認証に失敗しました。設定を確認してもう一度お試しください。", + "appLockAutoLogin": "自動ログイン", + "appLockPasscode": "パスコード", + "appLockBiometrics": "生体認証", + "settingsPlayerVideoHWAccelTitle": "ハードウェアアクセラレーション", + "settingsPlayerVideoHWAccelDesc": "ビデオをレンダリングするためにGPUを使用する(推奨)", + "settingsPlayerNativeLibassAccelTitle": "ネイティブlibass字幕", + "settingsPlayerNativeLibassAccelDesc": "ビデオプレーヤーlibass字幕レンダラーを使用する", + "settingsPlayerMobileWarning": "Androidでハードウェアアクセラレーションとネイティブlibass字幕を有効にすると、一部の字幕がレンダリングされない場合があります。", + "settingsPlayerCustomSubtitlesTitle": "字幕のカスタマイズ", + "settingsPlayerCustomSubtitlesDesc": "サイズ、色、位置、アウトラインをカスタマイズする", + "videoScalingFillScreenTitle": "画面全体に表示", + "videoScalingFillScreenDesc": "ナビゲーションバーとステータスバーを埋める", + "videoScalingFillScreenNotif": "画面全体はビデオフィットを上書きし、水平回転で", + "videoScaling": "ビデオスケーリング", + "videoScalingFill": "全体に表示", + "videoScalingContain": "含む", + "videoScalingCover": "カバー", + "videoScalingFitWidth": "幅に合わせる", + "videoScalingFitHeight": "高さに合わせる", + "videoScalingScaleDown": "スケールダウン", + "subtitleConfiguratorPlaceHolder": "これはプレースホルダーテキストです。\nここには何もありません。", + "subtitleConfigurator": "字幕コンフィギュレーター", + "refreshPopup": "リフレッシュ - {name}", + "@refreshPopup": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "scanningName": "スキャン中 - {name}", + "@scanningName": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "refreshPopupContentMetadata": "メタデータはダッシュボードで有効にされた設定とインターネットサービスに基づいて更新されます。", + "replaceExistingImages": "既存の画像を置き換える", + "metadataRefreshDefault": "新しいファイルと更新されたファイルをスキャン", + "metadataRefreshValidation": "欠落しているメタデータを検索", + "metadataRefreshFull": "すべてのメタデータを置き換える", + "syncedItems": "同期されたアイテム", + "noItemsSynced": "同期されたアイテムはありません", + "syncDeletePopupPermanent": "この操作は恒久的であり、すべてのローカルに同期されたファイルを削除します", + "totalSize": "合計サイズ: {size}", + "@totalSize": { + "placeholders": { + "size": { + "type": "String" + } + } + }, + "mediaTypeBase": "基本タイプ", + "mediaTypeMovie": "映画", + "mediaTypeSeries": "シリーズ", + "mediaTypeSeason": "シーズン", + "mediaTypeEpisode": "エピソード", + "mediaTypePhoto": "写真", + "mediaTypePerson": "人物", + "mediaTypePhotoAlbum": "フォトアルバム", + "mediaTypeFolder": "フォルダー", + "mediaTypeBoxset": "ボックスセット", + "mediaTypePlaylist": "プレイリスト", + "mediaTypeBook": "本", + "actor": "{count, plural, other{俳優} one{俳優}}", + "@actor": { + "description": "俳優", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "writer": "{count, plural, other{作家} one{作家}}", + "@writer": { + "description": "作家", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "director": "{count, plural, other{監督} one{監督}}", + "@director": { + "description": "監督", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "video": "ビデオ", + "audio": "オーディオ", + "subtitles": "字幕", + "related": "関連", + "all": "すべて", + "overview": "概要", + "selectViewType": "ビュータイプを選択", + "noItemsToShow": "表示するアイテムがありません", + "sortBy": "並び替え", + "groupBy": "グループ化", + "scrollToTop": "トップにスクロール", + "disableFilters": "フィルターを無効にする", + "selectAll": "すべて選択", + "clearSelection": "選択をクリア", + "shuffleVideos": "ビデオをシャッフル", + "shuffleGallery": "ギャラリーをシャッフル", + "unknown": "不明", + "favorites": "お気に入り", + "recursive": "再帰的", + "genre": "{count, plural, other{ジャンル} one{ジャンル}}", + "@genre": { + "description": "ジャンル", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "studio": "{count, plural, other{スタジオ} one{スタジオ}}", + "@studio": { + "description": "スタジオ", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "label": "{count, plural, other{ラベル} one{ラベル}}", + "@label": { + "description": "ラベル", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "group": "グループ", + "type": "{count, plural, other{タイプ} one{タイプ}}", + "@type": { + "description": "タイプ", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "filter": "{count, plural, other{フィルター} one{フィルター}}", + "@filter": { + "description": "フィルター", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "showEmpty": "空を表示", + "hideEmpty": "空を非表示", + "rating": "{count, plural, other{評価} one{評価}}", + "@rating": { + "description": "評価", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "year": "{count, plural, other{年} one{年}}", + "@year": { + "description": "年", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "playVideos": "ビデオを再生", + "playLabel": "再生", + "forceRefresh": "強制リフレッシュ", + "itemCount": "アイテム数: {count}", + "@itemCount": { + "description": "アイテム数", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "invalidUrl": "無効なURL", + "invalidUrlDesc": "URLはhttp(s)://で始まる必要があります", + "incorrectPinTryAgain": "PINが間違っています、もう一度試してください", + "somethingWentWrongPasswordCheck": "何かがうまくいかなかった、パスワードを確認してください", + "unableToConnectHost": "ホストに接続できません", + "server": "サーバー", + "retrievePublicListOfUsers": "ユーザーの公開リストを取得", + "displayLanguage": "表示言語", + "deleteItem": "{item}を削除しますか?", + "@deleteItem": { + "description": "deleteItem", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "syncDeleteItemTitle": "同期されたアイテムを削除", + "syncDeleteItemDesc": "すべての同期されたデータを削除しますか?\n{item}", + "@syncDeleteItemDesc": { + "description": "同期削除アイテムのポップアップウィンドウ", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "syncOpenParent": "親を開く", + "syncRemoveDataTitle": "同期データを削除しますか?", + "syncRemoveDataDesc": "同期されたビデオデータを削除しますか?これは永久的なもので、ファイルを再同期する必要があります", + "collectionFolder": "コレクションフォルダ", + "musicAlbum": "アルバム", + "active": "アクティブ", + "name": "名前", + "result": "結果", + "close": "閉じる", + "replaceAllImages": "すべての画像を置き換える", + "noResults": "結果がありません", + "openWebLink": "ウェブリンクを開く", + "setIdentityTo": "{name}にアイデンティティを設定", + "@setIdentityTo": { + "description": "setIdentityTo", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "somethingWentWrong": "問題が発生しました", + "clearChanges": "変更をクリア", + "useDefaults": "デフォルトを使用", + "light": "ライト", + "normal": "ノーマル", + "bold": "ボールド", + "fontSize": "フォントサイズ", + "heightOffset": "高さのオフセット", + "fontColor": "フォントの色", + "outlineColor": "アウトラインの色", + "outlineSize": "アウトラインのサイズ", + "backgroundOpacity": "背景の不透明度", + "shadow": "影", + "played": "再生済み", + "unPlayed": "未再生", + "resumable": "再開可能", + "sortOrder": "並び順", + "sortName": "名前", + "communityRating": "コミュニティ評価", + "parentalRating": "ペアレンタル評価", + "dateAdded": "追加日", + "dateLastContentAdded": "最後にコンテンツが追加された日", + "favorite": "お気に入り", + "datePlayed": "再生日", + "folders": "フォルダ", + "playCount": "再生回数", + "releaseDate": "リリース日", + "runTime": "再生時間", + "ascending": "昇順", + "descending": "降順", + "playFromStart": "{name} を最初から再生", + "@playFromStart": { + "description": "最初から再生", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "minutes": "分", + "@minutes": { + "description": "分", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "seconds": "秒", + "@seconds": { + "description": "秒", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "page": "{index} ページ", + "@page": { + "description": "ページ", + "placeholders": { + "index": { + "type": "int" + } + } + }, + "set": "設定", + "@set": { + "description": "特定の値を設定するために使用", + "context": "時間を設定" + }, + "never": "なし", + "selectTime": "時間を選択", + "immediately": "すぐに", + "timeAndAnnotation": "{minutes} と {seconds}", + "@timeAndAnnotation": { + "description": "timeAndAnnotation", + "placeholders": { + "minutes": { + "type": "String" + }, + "seconds": { + "type": "String" + } + } + }, + "scanYourFingerprintToAuthenticate": "指紋をスキャンして{user}を認証してください", + "@scanYourFingerprintToAuthenticate": { + "placeholders": { + "user": { + "type": "String" + } + } + }, + "scanBiometricHint": "身元を確認する", + "deleteFileFromSystem": "このアイテム {item} を削除すると、ファイルシステムとメディアライブラリの両方から削除されます。\n続行してもよろしいですか?", + "@deleteFileFromSystem": { + "description": "システムからファイルを削除", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "notPartOfAlbum": "アルバムの一部ではありません", + "retry": "再試行", + "failedToLoadImage": "画像の読み込みに失敗しました", + "save": "保存", + "metaDataSavedFor": "{item} のメタデータが保存されました", + "@metaDataSavedFor": { + "description": "メタデータが保存されました", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "libraryPageSizeTitle": "ライブラリページのサイズ", + "libraryPageSizeDesc": "一度に読み込む量を設定します。0はページングを無効にします。", + "fetchingLibrary": "ライブラリアイテムを取得しています", + "libraryFetchNoItemsFound": "アイテムが見つかりませんでした。設定を変更してみてください。", + "noSuggestionsFound": "提案が見つかりません", + "viewPhotos": "写真を見る", + "random": "ランダム", + "tag": "{count, plural, one{タグ} other{タグ}}", + "@tag": { + "description": "タグ", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "saved": "保存済み", + "discovered": "発見済み", + "noServersFound": "新しいサーバーが見つかりません", + "about": "情報", + "openParent": "親フォルダを開く", + "mouseDragSupport": "マウスでドラッグ", + "controls": "コントロール" +} diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb new file mode 100644 index 0000000..1440ee2 --- /dev/null +++ b/lib/l10n/app_nl.arb @@ -0,0 +1,669 @@ +{ + "@@locale": "nl", + "switchUser": "Wissel gebruiker", + "userName": "Gebruikersnaam", + "password": "Wachtwoord", + "login": "Inloggen", + "logout": "Uitloggen", + "cancel": "Annuleren", + "accept": "Accepteren", + "code": "Code", + "error": "Fout", + "clear": "Wissen", + "days": "Dagen", + "search": "Zoeken", + "loggedIn": "Ingelogd", + "change": "Wijzig", + "other": "Overig", + "dynamicText": "Dynamisch", + "enabled": "Ingeschakeld", + "disabled": "Uitgeschakeld", + "dashboard": "Dashboard", + "advanced": "Geavanceerd", + "refresh": "Vernieuwen", + "delete": "Verwijderen", + "goTo": "Ga naar", + "loop": "Lus", + "empty": "Leeg", + "noRating": "Geen beoordeling", + "backgroundBlur": "Achtergrond vervagen", + "autoPlay": "Automatisch afspelen", + "resume": "{item} Hervatten", + "@resume": { + "description": "hervatten", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "play": "{item} Afspelen", + "@play": { + "description": "Speel met", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "read": "{item} Lezen", + "@read": { + "description": "lezen", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "readFromStart": "{item} vanaf het begin lezen", + "@readFromStart": { + "description": "Lees boek vanaf het begin", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "playFrom": "Speel vanaf {name}", + "@playFrom": { + "description": "speel vanaf", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "playFromStart": "{name} Vanaf het begin afspelen", + "@playFromStart": { + "description": "speel vanaf het begin", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "moreFrom": "Meer van {info}", + "@moreFrom": { + "description": "Meer van", + "placeholders": { + "info": { + "type": "String" + } + } + }, + "selectedWith": "Geselecteerd {info}", + "@selectedWith": { + "description": "geselecteerd", + "placeholders": { + "info": { + "type": "String" + } + } + }, + "selected": "Geselecteerd", + "restart": "Herstarten", + "reWatch": "Opnieuw bekijken", + "watchOn": "Kijk op", + "options": "Opties", + "list": "Lijst", + "grid": "Raster", + "masonry": "Metseleffect", + "start": "Start", + "none": "Geen", + "chapter": "{count, plural, other{Hoofdstukken} one{Hoofdstuk}}", + "@chapter": { + "description": "hoofdstuk", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "sync": "Synchroniseren", + "moreOptions": "Meer opties", + "continuePage": "Doorgaan - pagina {page}", + "@continuePage": { + "description": "Doorgaan - pagina 1", + "placeholders": { + "page": { + "type": "int" + } + } + }, + "openShow": "Open show", + "showDetails": "Toon details", + "showAlbum": "Toon album", + "season": "{count, plural, other{Seizoenen} one{Seizoen}}", + "@season": { + "description": "seizoen", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "episode": "{count, plural, other{Afleveringen} one{Aflevering}}", + "@episode": { + "description": "aflevering", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "addToCollection": "Toevoegen aan collectie", + "addToPlaylist": "Toevoegen aan afspeellijst", + "removeFromCollection": "Verwijderen uit collectie", + "removeFromPlaylist": "Verwijderen uit afspeellijst", + "markAsWatched": "Markeer als bekeken", + "markAsUnwatched": "Markeer als niet bekeken", + "removeAsFavorite": "Verwijderen als favoriet", + "addAsFavorite": "Toevoegen als favoriet", + "editMetadata": "Metadata bewerken", + "refreshMetadata": "Metadata vernieuwen", + "syncDetails": "Details synchroniseren", + "identify": "Identificeren", + "info": "Info", + "clearAllSettings": "Alle instellingen wissen", + "clearAllSettingsQuestion": "Alle instellingen wissen?", + "unableToReverseAction": "Deze actie kan niet ongedaan worden gemaakt, het verwijdert alle instellingen.", + "navigationDashboard": "Dashboard", + "navigationFavorites": "Favorieten", + "navigationSync": "Gesynchroniseerd", + "navigation": "Navigatie", + "library": "{count, plural, other{Bibliotheken} one{Bibliotheek}}", + "@library": { + "description": "meervoud", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "scanLibrary": "Scan bibliotheek", + "dashboardContinue": "Doorgaan", + "dashboardContinueWatching": "Doorgaan met kijken", + "dashboardContinueReading": "Doorgaan met lezen", + "dashboardContinueListening": "Doorgaan met luisteren", + "dashboardNextUp": "Volgende", + "dashboardRecentlyAdded": "Onlangs toegevoegd in {name}", + "@dashboardRecentlyAdded": { + "description": "Onlangs toegevoegd op startscherm", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "settings": "Instellingen", + "settingsClientTitle": "Fladder", + "settingsClientDesc": "Algemeen, Time-out, Lay-out, Thema", + "settingsQuickConnectTitle": "Snel verbinden", + "settingsProfileTitle": "Profiel", + "settingsProfileDesc": "Vergrendelscherm", + "settingsPlayerTitle": "Speler", + "settingsPlayerDesc": "Beeldverhouding, Geavanceerd", + "logoutUserPopupTitle": "Gebruiker {userName} uitloggen?", + "@logoutUserPopupTitle": { + "description": "Pop-up voor uitloggen gebruiker", + "placeholders": { + "userName": { + "type": "String" + } + } + }, + "logoutUserPopupContent": "Dit zal {userName} uitloggen en de gebruiker uit de app verwijderen.\nJe moet opnieuw inloggen op {serverName}.", + "@logoutUserPopupContent": { + "description": "Pop-up voor uitloggen gebruiker beschrijving", + "placeholders": { + "userName": { + "type": "String" + }, + "serverName": { + "type": "String" + } + } + }, + "quickConnectTitle": "Snel verbinden", + "quickConnectAction": "Voer snelverbind code in voor", + "quickConnectInputACode": "Voer een code in", + "quickConnectWrongCode": "Verkeerde code", + "downloadsTitle": "Downloads", + "downloadsPath": "Pad", + "pathEditTitle": "Locatie wijzigen", + "pathEditSelect": "Selecteer downloadbestemming", + "pathClearTitle": "Downloadpad wissen", + "pathEditDesc": "Deze locatie is ingesteld voor alle gebruikers, gesynchroniseerde gegevens zijn niet meer toegankelijk.\nHet blijft op je opslag.", + "downloadsSyncedData": "Gesynchroniseerde gegevens", + "downloadsClearTitle": "Gesynchroniseerde gegevens wissen", + "downloadsClearDesc": "Weet je zeker dat je alle gesynchroniseerde gegevens wilt verwijderen?\nDit wist alle gegevens voor elke gesynchroniseerde gebruiker!", + "lockscreen": "Vergrendelscherm", + "timeOut": "Time-out", + "home": "Home", + "settingsHomeCarouselTitle": "Dashboard carrousel", + "settingsHomeCarouselDesc": "Toont een carrousel op het dashboard scherm", + "settingsHomeNextUpTitle": "Volgende posters", + "settingsHomeNextUpDesc": "Soort posters getoond op het dashboard scherm", + "settingsVisual": "Visueel", + "settingsBlurredPlaceholderTitle": "Vervaagde placeholder", + "settingsBlurredPlaceholderDesc": "Toon vervaagde achtergrond bij het laden van posters", + "settingsBlurEpisodesTitle": "Vervagen volgende afleveringen", + "settingsBlurEpisodesDesc": "Vervaag alle komende afleveringen", + "settingsEnableOsMediaControls": "OS media bediening inschakelen", + "settingsNextUpCutoffDays": "Volgende cutoff dagen", + "settingsShowScaleSlider": "Toon posterschaal schuifregelaar", + "settingsPosterSize": "Poster grootte", + "settingsPosterSlider": "Toon schaal schuifregelaar", + "settingsPosterPinch": "Knijp-zoom om posters te schalen", + "theme": "Thema", + "mode": "Modus", + "themeModeSystem": "Systeem", + "themeModeLight": "Licht", + "themeModeDark": "Donker", + "themeColor": "Thema kleur", + "color": "Kleur", + "amoledBlack": "Amoled zwart", + "hide": "Verbergen", + "nextUp": "Volgende", + "settingsContinue": "Doorgaan", + "separate": "Gescheiden", + "combined": "Gecombineerd", + "settingsSecurity": "Beveiliging", + "settingSecurityApplockTitle": "App vergrendelen", + "appLockTitle": "Stel de inlogmethode in voor {userName}", + "@appLockTitle": { + "description": "Pop-up om een inlogmethode te kiezen", + "placeholders": { + "userName": { + "type": "String" + } + } + }, + "biometricsFailedCheckAgain": "Biometrie mislukt, controleer de instellingen en probeer opnieuw", + "appLockAutoLogin": "Automatisch inloggen", + "appLockPasscode": "Wachtwoord", + "appLockBiometrics": "Biometrie", + "settingsPlayerVideoHWAccelTitle": "Hardwareversnelling", + "settingsPlayerVideoHWAccelDesc": "Gebruik de gpu om video weer te geven (aanbevolen)", + "settingsPlayerNativeLibassAccelTitle": "Native libass ondertiteling", + "settingsPlayerNativeLibassAccelDesc": "Gebruik videospeler libass ondertitel renderer", + "settingsPlayerMobileWarning": "Hardwareversnelling en native libass ondertitels inschakelen op Android kan ervoor zorgen dat sommige ondertitels niet worden weergegeven.", + "settingsPlayerCustomSubtitlesTitle": "Ondertitels aanpassen", + "settingsPlayerCustomSubtitlesDesc": "Pas grootte, kleur, positie, omtrek aan", + "videoScalingFillScreenTitle": "Vul scherm", + "videoScalingFillScreenDesc": "Vul de navigatie- en statusbalk", + "videoScalingFillScreenNotif": "Volledig scherm overschrijft videopasvorm, in horizontale rotatie", + "videoScaling": "Videoschaling", + "videoScalingFill": "Vullen", + "videoScalingContain": "Bevatten", + "videoScalingCover": "Bedekken", + "videoScalingFitWidth": "Pas breedte aan", + "videoScalingFitHeight": "Pas hoogte aan", + "videoScalingScaleDown": "Schaal omlaag", + "subtitleConfiguratorPlaceHolder": "Dit is placeholder tekst,\nniets te zien hier.", + "subtitleConfigurator": "Ondertitel configurator", + "refreshPopup": "Vernieuwen - {name}", + "@refreshPopup": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "scanningName": "Scannen - {name}", + "@scanningName": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "refreshPopupContentMetadata": "Metadata wordt vernieuwd op basis van instellingen en internetdiensten die zijn ingeschakeld in het Dashboard.", + "replaceExistingImages": "Bestaande afbeeldingen vervangen", + "metadataRefreshDefault": "Scannen naar nieuwe en bijgewerkte bestanden", + "metadataRefreshValidation": "Zoeken naar ontbrekende metadata", + "metadataRefreshFull": "Alle metadata vervangen", + "syncedItems": "Gesynchroniseerde items", + "noItemsSynced": "Geen items gesynchroniseerd", + "syncDeletePopupPermanent": "Deze actie is permanent en verwijdert alle lokaal gesynchroniseerde bestanden", + "totalSize": "Totale grootte: {size}", + "@totalSize": { + "placeholders": { + "size": { + "type": "String" + } + } + }, + "mediaTypeBase": "Basis type", + "mediaTypeMovie": "Film", + "mediaTypeSeries": "Serie", + "mediaTypeSeason": "Seizoen", + "mediaTypeEpisode": "Aflevering", + "mediaTypePhoto": "Foto", + "mediaTypePerson": "Persoon", + "mediaTypePhotoAlbum": "Foto album", + "mediaTypeFolder": "Map", + "mediaTypeBoxset": "Boxset", + "mediaTypePlaylist": "Afspeellijst", + "mediaTypeBook": "Boek", + "actor": "{count, plural, other{Acteurs} one{Acteur}}", + "@actor": { + "description": "acteur", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "writer": "{count, plural, other{Schrijvers} one{Schrijver}}", + "@writer": { + "description": "schrijver", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "director": "{count, plural, other{Regisseurs} one{Regisseur}}", + "@director": { + "description": "regisseur", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "video": "Video", + "audio": "Audio", + "subtitles": "Ondertitels", + "related": "Gerelateerd", + "all": "Alles", + "overview": "Overzicht", + "selectViewType": "Selecteer weergavetype", + "noItemsToShow": "Geen items om te tonen", + "sortBy": "Sorteer op", + "groupBy": "Groepeer op", + "scrollToTop": "Scroll naar boven", + "disableFilters": "Filters uitschakelen", + "selectAll": "Alles selecteren", + "clearSelection": "Selectie wissen", + "shuffleVideos": "Video's shuffle", + "shuffleGallery": "Galerij shuffle", + "unknown": "Onbekend", + "favorites": "Favorieten", + "recursive": "Recursief", + "genre": "{count, plural, other{Genres} one{Genre}}", + "@genre": { + "description": "genre", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "studio": "{count, plural, other{Studio's} one{Studio}}", + "@studio": { + "description": "studio", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "label": "{count, plural, other{Labels} one{Label}}", + "@label": { + "description": "label", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "group": "Groeperen", + "type": "{count, plural, other{Types} one{Type}}", + "@type": { + "description": "type", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "filter": "{count, plural, other{Filters} one{Filter}}", + "@filter": { + "description": "filter", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "showEmpty": "Toon leeg", + "hideEmpty": "Verberg leeg", + "rating": "{count, plural, other{Beoordelingen} one{Beoordeling}}", + "@rating": { + "description": "beoordeling", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "year": "{count, plural, other{Jaren} one{Jaar}}", + "@year": { + "description": "jaar", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "playVideos": "Video's afspelen", + "playLabel": "Afspelen", + "forceRefresh": "Geforceerd vernieuwen", + "itemCount": "Aantal items: {count}", + "@itemCount": { + "description": "Aantal items", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "invalidUrl": "Ongeldige url", + "invalidUrlDesc": "Url moet beginnen met http(s)://", + "incorrectPinTryAgain": "Onjuiste pin, probeer opnieuw", + "somethingWentWrongPasswordCheck": "Er is iets misgegaan, controleer uw wachtwoord", + "unableToConnectHost": "Kan geen verbinding maken met host", + "server": "Server", + "retrievePublicListOfUsers": "Publieke lijst van gebruikers ophalen", + "displayLanguage": "Weergavetaal", + "deleteItem": "{item} verwijderen?", + "@deleteItem": { + "description": "deleteItem", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "syncDeleteItemTitle": "Gesynchroniseerd item verwijderen", + "syncDeleteItemDesc": "Alle gesynchroniseerde gegevens verwijderen voor?\n{item}", + "@syncDeleteItemDesc": { + "description": "Pop-upvenster voor synchronisatie van te verwijderen item", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "syncOpenParent": "Ouder openen", + "syncRemoveDataTitle": "Gesynchroniseerde gegevens verwijderen?", + "syncRemoveDataDesc": "Gesynchroniseerde videogegevens verwijderen? Dit is permanent en u moet de bestanden opnieuw synchroniseren", + "collectionFolder": "Collectiemap", + "musicAlbum": "Album", + "active": "Actief", + "name": "Naam", + "result": "Resultaat", + "close": "Sluiten", + "replaceAllImages": "Alle afbeeldingen vervangen", + "noResults": "Geen resultaten", + "openWebLink": "Weblink openen", + "setIdentityTo": "Identiteit instellen op {name}", + "@setIdentityTo": { + "description": "setIdentityTo", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "somethingWentWrong": "Er is iets misgegaan", + "clearChanges": "Wijzigingen wissen", + "useDefaults": "Standaardwaarden gebruiken", + "light": "Licht", + "normal": "Normaal", + "bold": "Vet", + "fontSize": "Lettergrootte", + "heightOffset": "Hoogte-offset", + "fontColor": "Letterkleur", + "outlineColor": "Omtreklijnkleur", + "outlineSize": "Omtreklijn grootte", + "backgroundOpacity": "Achtergrond doorzichtigheid", + "shadow": "Schaduw", + "played": "Gespeeld", + "unPlayed": "Ongespeeld", + "resumable": "Hervatbaar", + "sortOrder": "Sorteervolgorde", + "sortName": "Naam", + "communityRating": "Gemeenschapswaardering", + "parentalRating": "Ouderlijk toezicht beoordeling", + "dateAdded": "Datum toegevoegd", + "dateLastContentAdded": "Datum laatste inhoud toegevoegd", + "favorite": "Favoriet", + "datePlayed": "Datum afgespeeld", + "folders": "Mappen", + "playCount": "Aantal keren afgespeeld", + "releaseDate": "Releasedatum", + "runTime": "Looptijd", + "ascending": "Oplopend", + "descending": "Aflopend", + "minutes": "{count, plural, other{Minuten} one{Minuut}}", + "@minutes": { + "description": "minuut", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "seconds": "{count, plural, other{Seconden} one{Seconde}}", + "@seconds": { + "description": "seconde", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "page": "Pagina {index}", + "@page": { + "description": "pagina", + "placeholders": { + "index": { + "type": "int" + } + } + }, + "set": "Instellen", + "@set": { + "description": "Gebruik voor het instellen van een bepaalde waarde", + "context": "Instellen 'tijd'" + }, + "never": "Nooit", + "selectTime": "Tijd selecteren", + "immediately": "Direct", + "timeAndAnnotation": "{minutes} en {seconds}", + "@timeAndAnnotation": { + "description": "timeAndAnnotation", + "placeholders": { + "minutes": { + "type": "String" + }, + "seconds": { + "type": "String" + } + } + }, + "scanYourFingerprintToAuthenticate": "Scan je vingerafdruk om {user} te verifiëren", + "@scanYourFingerprintToAuthenticate": { + "placeholders": { + "user": { + "type": "String" + } + } + }, + "scanBiometricHint": "Identiteit verifiëren", + "deleteFileFromSystem": "Het verwijderen van dit item {item} zal het zowel uit het bestandssysteem als uit je mediatheek verwijderen.\nWeet je zeker dat je wilt doorgaan?", + "@deleteFileFromSystem": { + "description": "Bestand uit systeem verwijderen", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "notPartOfAlbum": "Maakt geen deel uit van een album", + "retry": "Opnieuw proberen", + "failedToLoadImage": "Kan afbeelding niet laden", + "save": "Opslaan", + "metaDataSavedFor": "Metadata opgeslagen voor {item}", + "@metaDataSavedFor": { + "description": "metadataOpgeslagenVoor", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "libraryPageSizeTitle": "Bibliotheek paginagrootte", + "libraryPageSizeDesc": "Stel de hoeveelheid in om per keer te laden. 0 schakelt paginering uit.", + "fetchingLibrary": "Bibliotheek items ophalen", + "libraryFetchNoItemsFound": "Geen items gevonden, probeer andere instellingen.", + "noSuggestionsFound": "Geen suggesties gevonden", + "viewPhotos": "Foto's bekijken", + "random": "Willekeurig", + "tag": "{count, plural, one{Label} other{Labels}}", + "@tag": { + "description": "label", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "saved": "Opgeslagen", + "discovered": "Ontdekt", + "noServersFound": "Geen nieuwe servers gevonden", + "about": "Over", + "openParent": "Bovenliggende map openen", + "mouseDragSupport": "Slepen met de muis", + "controls": "Bediening" +} diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb new file mode 100644 index 0000000..22dcbda --- /dev/null +++ b/lib/l10n/app_zh.arb @@ -0,0 +1,669 @@ +{ + "@@locale": "zh", + "switchUser": "切换用户", + "userName": "用户名", + "password": "密码", + "login": "登录", + "logout": "登出", + "cancel": "取消", + "accept": "接受", + "code": "代码", + "error": "错误", + "clear": "清除", + "days": "天", + "search": "搜索", + "loggedIn": "已登录", + "change": "更改", + "other": "其他", + "dynamicText": "动态", + "enabled": "启用", + "disabled": "禁用", + "dashboard": "仪表板", + "advanced": "高级", + "refresh": "刷新", + "delete": "删除", + "goTo": "去往", + "loop": "循环", + "empty": "空", + "noRating": "无评分", + "backgroundBlur": "背景模糊", + "autoPlay": "自动播放", + "resume": "继续 {item}", + "@resume": { + "description": "继续", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "play": "播放 {item}", + "@play": { + "description": "播放", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "read": "阅读 {item}", + "@read": { + "description": "阅读", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "readFromStart": "从头开始阅读 {item}", + "@readFromStart": { + "description": "从头开始阅读书籍", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "playFrom": "从 {name} 开始播放", + "@playFrom": { + "description": "从...开始播放", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "moreFrom": "更多来自 {info}", + "@moreFrom": { + "description": "更多来自", + "placeholders": { + "info": { + "type": "String" + } + } + }, + "selectedWith": "选择了 {info}", + "@selectedWith": { + "description": "选择", + "placeholders": { + "info": { + "type": "String" + } + } + }, + "selected": "已选择", + "restart": "重新开始", + "reWatch": "重新观看", + "watchOn": "观看于", + "options": "选项", + "list": "列表", + "grid": "网格", + "masonry": "砖石", + "start": "开始", + "none": "无", + "chapter": "{count, plural, other{章节} one{章节}}", + "@chapter": { + "description": "章节", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "sync": "同步", + "moreOptions": "更多选项", + "continuePage": "继续 - 第 {page} 页", + "@continuePage": { + "description": "继续 - 第 1 页", + "placeholders": { + "page": { + "type": "int" + } + } + }, + "openShow": "打开节目", + "showDetails": "显示详情", + "showAlbum": "显示相册", + "season": "{count, plural, other{季} one{季}}", + "@season": { + "description": "季", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "episode": "{count, plural, other{集} one{集}}", + "@episode": { + "description": "集", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "addToCollection": "添加到收藏", + "addToPlaylist": "添加到播放列表", + "removeFromCollection": "从收藏中删除", + "removeFromPlaylist": "从播放列表中删除", + "markAsWatched": "标记为已观看", + "markAsUnwatched": "标记为未观看", + "removeAsFavorite": "取消收藏", + "addAsFavorite": "添加为收藏", + "editMetadata": "编辑元数据", + "refreshMetadata": "刷新元数据", + "syncDetails": "同步详情", + "identify": "识别", + "info": "信息", + "clearAllSettings": "清除所有设置", + "clearAllSettingsQuestion": "清除所有设置?", + "unableToReverseAction": "此操作无法撤销,它将删除所有设置。", + "navigationDashboard": "仪表板", + "navigationFavorites": "收藏夹", + "navigationSync": "已同步", + "navigation": "导航", + "library": "{count, plural, other{库} one{库}}", + "@library": { + "description": "复数", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "scanLibrary": "扫描库", + "dashboardContinue": "继续", + "dashboardContinueWatching": "继续观看", + "dashboardContinueReading": "继续阅读", + "dashboardContinueListening": "继续听", + "dashboardNextUp": "下一个", + "dashboardRecentlyAdded": "最近添加于 {name}", + "@dashboardRecentlyAdded": { + "description": "最近添加到首页", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "settings": "设置", + "settingsClientTitle": "Fladder", + "settingsClientDesc": "常规,超时,布局,主题", + "settingsQuickConnectTitle": "快速连接", + "settingsProfileTitle": "个人资料", + "settingsProfileDesc": "锁屏", + "settingsPlayerTitle": "播放器", + "settingsPlayerDesc": "纵横比,高级", + "logoutUserPopupTitle": "登出用户 {userName}?", + "@logoutUserPopupTitle": { + "description": "登出用户的弹窗", + "placeholders": { + "userName": { + "type": "String" + } + } + }, + "logoutUserPopupContent": "这将登出 {userName} 并从应用程序中删除用户。\n你需要重新登录到 {serverName}。", + "@logoutUserPopupContent": { + "description": "登出用户的弹窗描述", + "placeholders": { + "userName": { + "type": "String" + }, + "serverName": { + "type": "String" + } + } + }, + "quickConnectTitle": "快速连接", + "quickConnectAction": "输入快速连接代码", + "quickConnectInputACode": "输入代码", + "quickConnectWrongCode": "错误的代码", + "downloadsTitle": "下载", + "downloadsPath": "路径", + "pathEditTitle": "更改位置", + "pathEditSelect": "选择下载目标", + "pathClearTitle": "清除下载路径", + "pathEditDesc": "此位置设置适用于所有用户,任何同步的数据将不再可访问。\n它将保留在你的存储中。", + "downloadsSyncedData": "同步数据", + "downloadsClearTitle": "清除同步数据", + "downloadsClearDesc": "你确定要删除所有同步数据吗?\n这将清除每个同步用户的所有数据!", + "lockscreen": "锁屏", + "timeOut": "超时", + "home": "主页", + "settingsHomeCarouselTitle": "仪表板轮播", + "settingsHomeCarouselDesc": "在仪表板屏幕上显示轮播", + "settingsHomeNextUpTitle": "下一个海报", + "settingsHomeNextUpDesc": "仪表板屏幕上显示的海报类型", + "settingsVisual": "视觉", + "settingsBlurredPlaceholderTitle": "模糊的占位符", + "settingsBlurredPlaceholderDesc": "加载海报时显示模糊的背景", + "settingsBlurEpisodesTitle": "模糊下一个集数", + "settingsBlurEpisodesDesc": "模糊所有即将播放的集数", + "settingsEnableOsMediaControls": "启用操作系统媒体控制", + "settingsNextUpCutoffDays": "下一个截止天数", + "settingsShowScaleSlider": "显示海报大小滑块", + "settingsPosterSize": "海报大小", + "settingsPosterSlider": "显示比例滑块", + "settingsPosterPinch": "捏合缩放以调整海报大小", + "theme": "主题", + "mode": "模式", + "themeModeSystem": "系统", + "themeModeLight": "浅色", + "themeModeDark": "深色", + "themeColor": "主题颜色", + "color": "颜色", + "amoledBlack": "Amoled 黑色", + "hide": "隐藏", + "nextUp": "下一个", + "settingsContinue": "继续", + "separate": "分开", + "combined": "组合", + "settingsSecurity": "安全", + "settingSecurityApplockTitle": "应用锁", + "appLockTitle": "设置 {userName} 的登录方式", + "@appLockTitle": { + "description": "选择登录方式的弹窗", + "placeholders": { + "userName": { + "type": "String" + } + } + }, + "biometricsFailedCheckAgain": "生物识别失败,请检查设置并重试", + "appLockAutoLogin": "自动登录", + "appLockPasscode": "密码", + "appLockBiometrics": "生物识别", + "settingsPlayerVideoHWAccelTitle": "硬件加速", + "settingsPlayerVideoHWAccelDesc": "使用 GPU 渲染视频(推荐)", + "settingsPlayerNativeLibassAccelTitle": "本地 libass 字幕", + "settingsPlayerNativeLibassAccelDesc": "使用视频播放器 libass 字幕渲染器", + "settingsPlayerMobileWarning": "在 Android 上启用硬件加速和本地 libass 字幕可能会导致某些字幕无法渲染。", + "settingsPlayerCustomSubtitlesTitle": "自定义字幕", + "settingsPlayerCustomSubtitlesDesc": "自定义大小、颜色、位置、轮廓", + "videoScalingFillScreenTitle": "填满屏幕", + "videoScalingFillScreenDesc": "填充导航栏和状态栏", + "videoScalingFillScreenNotif": "全屏覆盖视频适应,在水平旋转中", + "videoScaling": "视频缩放", + "videoScalingFill": "填充", + "videoScalingContain": "包含", + "videoScalingCover": "覆盖", + "videoScalingFitWidth": "适应宽度", + "videoScalingFitHeight": "适应高度", + "videoScalingScaleDown": "缩小", + "subtitleConfiguratorPlaceHolder": "这是占位符文本,\n这里没有什么可看的。", + "subtitleConfigurator": "字幕配置器", + "refreshPopup": "刷新 - {name}", + "@refreshPopup": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "scanningName": "扫描 - {name}", + "@scanningName": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "refreshPopupContentMetadata": "根据仪表板中启用的设置和互联网服务刷新元数据。", + "replaceExistingImages": "替换现有图像", + "metadataRefreshDefault": "扫描新文件和更新的文件", + "metadataRefreshValidation": "搜索缺失的元数据", + "metadataRefreshFull": "替换所有元数据", + "syncedItems": "同步项目", + "noItemsSynced": "没有同步项目", + "syncDeletePopupPermanent": "此操作是永久性的,将删除所有本地同步的文件", + "totalSize": "总大小:{size}", + "@totalSize": { + "placeholders": { + "size": { + "type": "String" + } + } + }, + "mediaTypeBase": "基础类型", + "mediaTypeMovie": "电影", + "mediaTypeSeries": "系列", + "mediaTypeSeason": "季", + "mediaTypeEpisode": "集", + "mediaTypePhoto": "照片", + "mediaTypePerson": "人物", + "mediaTypePhotoAlbum": "相册", + "mediaTypeFolder": "文件夹", + "mediaTypeBoxset": "套装", + "mediaTypePlaylist": "播放列表", + "mediaTypeBook": "书籍", + "actor": "{count, plural, other{演员} one{演员}}", + "@actor": { + "description": "演员", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "writer": "{count, plural, other{作家} one{作家}}", + "@writer": { + "description": "作家", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "director": "{count, plural, other{导演} one{导演}}", + "@director": { + "description": "导演", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "video": "视频", + "audio": "音频", + "subtitles": "字幕", + "related": "相关", + "all": "全部", + "overview": "概述", + "selectViewType": "选择查看类型", + "noItemsToShow": "没有可显示的项目", + "sortBy": "排序方式", + "groupBy": "分组依据", + "scrollToTop": "滚动到顶部", + "disableFilters": "禁用过滤器", + "selectAll": "全选", + "clearSelection": "清除选择", + "shuffleVideos": "随机播放视频", + "shuffleGallery": "随机播放图库", + "unknown": "未知", + "favorites": "收藏", + "recursive": "递归", + "genre": "{count, plural, other{类型} one{类型}}", + "@genre": { + "description": "类型", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "studio": "{count, plural, other{工作室} one{工作室}}", + "@studio": { + "description": "工作室", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "label": "{count, plural, other{标签} one{标签}}", + "@label": { + "description": "标签", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "group": "组", + "type": "{count, plural, other{类型} one{类型}}", + "@type": { + "description": "类型", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "filter": "{count, plural, other{过滤器} one{过滤器}}", + "@filter": { + "description": "过滤器", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "showEmpty": "显示空", + "hideEmpty": "隐藏空", + "rating": "{count, plural, other{评分} one{评分}}", + "@rating": { + "description": "评分", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "year": "{count, plural, other{年} one{年}}", + "@year": { + "description": "年", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "playVideos": "播放视频", + "playLabel": "播放", + "forceRefresh": "强制刷新", + "itemCount": "项目数:{count}", + "@itemCount": { + "description": "项目数", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "invalidUrl": "无效的 URL", + "invalidUrlDesc": "URL 必须以 http(s):// 开头", + "incorrectPinTryAgain": "错误的 PIN,请重试", + "somethingWentWrongPasswordCheck": "出了点问题,请检查您的密码", + "unableToConnectHost": "无法连接到主机", + "server": "服务器", + "retrievePublicListOfUsers": "检索公共用户列表", + "displayLanguage": "显示语言 (显示语言)", + "deleteItem": "删除 {item}?", + "@deleteItem": { + "description": "deleteItem", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "syncDeleteItemTitle": "删除同步的项目", + "syncDeleteItemDesc": "删除所有同步数据?\n{item}", + "@syncDeleteItemDesc": { + "description": "同步删除项目弹出窗口", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "syncOpenParent": "打开父级", + "syncRemoveDataTitle": "删除同步的数据?", + "syncRemoveDataDesc": "删除同步的视频数据?这是永久性的,您需要重新同步文件", + "collectionFolder": "收藏夹", + "musicAlbum": "专辑", + "active": "活跃", + "name": "名称", + "result": "结果", + "close": "关闭", + "replaceAllImages": "替换所有图像", + "noResults": "没有结果", + "openWebLink": "打开网页链接", + "setIdentityTo": "设置身份为 {name}", + "@setIdentityTo": { + "description": "setIdentityTo", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "somethingWentWrong": "出了些问题", + "clearChanges": "清除更改", + "useDefaults": "使用默认值", + "light": "浅色", + "normal": "正常", + "bold": "粗体", + "fontSize": "字体大小", + "heightOffset": "高度偏移", + "fontColor": "字体颜色", + "outlineColor": "轮廓颜色", + "outlineSize": "轮廓大小", + "backgroundOpacity": "背景不透明度", + "shadow": "阴影", + "played": "已播放", + "unPlayed": "未播放", + "resumable": "可恢复", + "sortOrder": "排序顺序", + "sortName": "名称", + "communityRating": "社区评分", + "parentalRating": "家长评级", + "dateAdded": "添加日期", + "dateLastContentAdded": "最后添加内容的日期", + "favorite": "收藏", + "datePlayed": "播放日期", + "folders": "文件夹", + "playCount": "播放次数", + "releaseDate": "发布日期", + "runTime": "运行时间", + "ascending": "升序", + "descending": "降序", + "playFromStart": "从头播放 {name}", + "@playFromStart": { + "description": "从头播放", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "minutes": "分钟", + "@minutes": { + "description": "分钟", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "seconds": "秒", + "@seconds": { + "description": "秒", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "page": "第 {index} 页", + "@page": { + "description": "页数", + "placeholders": { + "index": { + "type": "int" + } + } + }, + "set": "设置", + "@set": { + "description": "用于设置某个值", + "context": "设置时间" + }, + "never": "从不", + "selectTime": "选择时间", + "immediately": "立即", + "timeAndAnnotation": "{minutes} 分 {seconds} 秒", + "@timeAndAnnotation": { + "description": "时间和注释", + "placeholders": { + "minutes": { + "type": "String" + }, + "seconds": { + "type": "String" + } + } + }, + "scanYourFingerprintToAuthenticate": "扫描您的指纹以验证 {user}", + "@scanYourFingerprintToAuthenticate": { + "placeholders": { + "user": { + "type": "String" + } + } + }, + "scanBiometricHint": "验证身份", + "deleteFileFromSystem": "删除此项目 {item} 将从文件系统和您的媒体库中删除它。\n您确定要继续吗?", + "@deleteFileFromSystem": { + "description": "从系统中删除文件", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "notPartOfAlbum": "不属于专辑的一部分", + "retry": "重试", + "failedToLoadImage": "加载图像失败", + "save": "保存", + "metaDataSavedFor": "{item} 的元数据已保存", + "@metaDataSavedFor": { + "description": "元数据已保存", + "placeholders": { + "item": { + "type": "String" + } + } + }, + "libraryPageSizeTitle": "库页面大小", + "libraryPageSizeDesc": "设置每次加载的数量。0 禁用分页。", + "fetchingLibrary": "正在获取库项目", + "libraryFetchNoItemsFound": "未找到项目,请尝试不同的设置。", + "noSuggestionsFound": "未找到建议", + "viewPhotos": "查看照片", + "random": "随机", + "tag": "{count, plural, one{标签} other{标签}}", + "@tag": { + "description": "标签", + "placeholders": { + "count": { + "type": "int", + "example": "1" + } + } + }, + "saved": "已保存", + "discovered": "已发现", + "noServersFound": "未找到新服务器", + "about": "关于", + "openParent": "打开上级文件夹", + "mouseDragSupport": "使用鼠标拖动", + "controls": "控制" +} diff --git a/lib/l10n/l10n_errors.txt b/lib/l10n/l10n_errors.txt new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/lib/l10n/l10n_errors.txt @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..c78be9e --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,339 @@ +import 'dart:io'; +import 'dart:ui'; + +import 'package:collection/collection.dart'; +import 'package:fladder/models/syncing/i_synced_item.dart'; +import 'package:fladder/providers/settings/client_settings_provider.dart'; +import 'package:fladder/providers/sync_provider.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +import 'package:dynamic_color/dynamic_color.dart'; +import 'package:flutter_cache_manager/flutter_cache_manager.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +// ignore: depend_on_referenced_packages +import 'package:flutter_web_plugins/url_strategy.dart'; +import 'package:go_router/go_router.dart'; +import 'package:isar/isar.dart'; +import 'package:logging/logging.dart'; +import 'package:media_kit/media_kit.dart'; +import 'package:package_info_plus/package_info_plus.dart'; +import 'package:path/path.dart' as path; +import 'package:path_provider/path_provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:window_manager/window_manager.dart'; + +import 'package:fladder/models/account_model.dart'; +import 'package:fladder/providers/shared_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/providers/video_player_provider.dart'; +import 'package:fladder/routes/app_routes.dart'; +import 'package:fladder/routes/build_routes/route_builder.dart'; +import 'package:fladder/screens/login/lock_screen.dart'; +import 'package:fladder/theme.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/application_info.dart'; +import 'package:fladder/util/string_extensions.dart'; +import 'package:fladder/util/themes_data.dart'; +import 'package:universal_html/html.dart' as html; + +bool get _isDesktop { + if (kIsWeb) return false; + return [ + TargetPlatform.windows, + TargetPlatform.linux, + TargetPlatform.macOS, + ].contains(defaultTargetPlatform); +} + +class CustomCacheManager { + static const key = 'customCacheKey'; + static CacheManager instance = CacheManager( + Config( + key, + stalePeriod: const Duration(days: 3), + maxNrOfCacheObjects: 500, + repo: JsonCacheInfoRepository(databaseName: key), + fileService: HttpFileService(), + ), + ); +} + +void main() async { + if (kIsWeb) { + usePathUrlStrategy(); + html.document.onContextMenu.listen((event) => event.preventDefault()); + GoRouter.optionURLReflectsImperativeAPIs = true; + } + _setupLogging(); + WidgetsFlutterBinding.ensureInitialized(); + MediaKit.ensureInitialized(); + + final sharedPreferences = await SharedPreferences.getInstance(); + + PackageInfo packageInfo = await PackageInfo.fromPlatform(); + + Directory isarPath = Directory(""); + Directory applicationDirectory = Directory(""); + + if (!kIsWeb) { + applicationDirectory = await getApplicationDocumentsDirectory(); + isarPath = Directory(path.joinAll([applicationDirectory.path, 'Fladder', 'Database'])); + await isarPath.create(recursive: true); + } + + if (_isDesktop) { + await WindowManager.instance.ensureInitialized(); + } + + final applicationInfo = ApplicationInfo( + name: kIsWeb ? "${packageInfo.appName.capitalize()} Web" : packageInfo.appName.capitalize(), + version: "${packageInfo.version}(${packageInfo.buildNumber})", + os: defaultTargetPlatform.name.capitalize(), + ); + + runApp( + ProviderScope( + overrides: [ + sharedPreferencesProvider.overrideWith((ref) => sharedPreferences), + applicationInfoProvider.overrideWith((ref) => applicationInfo), + syncProvider.overrideWith((ref) => SyncNotifier( + ref, + !kIsWeb + ? Isar.open( + schemas: [ISyncedItemSchema], + directory: isarPath.path, + ) + : null, + applicationDirectory, + )) + ], + child: AdaptiveLayoutBuilder( + fallBack: LayoutState.phone, + layoutPoints: [ + LayoutPoints(start: 0, end: 599, type: LayoutState.phone), + LayoutPoints(start: 600, end: 1919, type: LayoutState.tablet), + LayoutPoints(start: 1920, end: 3180, type: LayoutState.desktop), + ], + child: const Main(), + ), + ), + ); +} + +void _setupLogging() { + Logger.root.level = Level.ALL; + Logger.root.onRecord.listen((rec) { + if (kDebugMode) { + print('${rec.level.name}: ${rec.time}: ${rec.message}'); + } + }); +} + +class Main extends ConsumerStatefulWidget with WindowListener { + const Main({super.key}); + + @override + ConsumerState createState() => _MainState(); +} + +class _MainState extends ConsumerState
with WindowListener, WidgetsBindingObserver { + DateTime dateTime = DateTime.now(); + bool hidden = false; + + @override + void didChangeAppLifecycleState(AppLifecycleState state) async { + if (ref.read(lockScreenActiveProvider) || ref.read(userProvider) == null) { + dateTime = DateTime.now(); + return; + } + switch (state) { + case AppLifecycleState.resumed: + enableTimeOut(); + break; + case AppLifecycleState.hidden: + break; + case AppLifecycleState.paused: + hidden = true; + dateTime = DateTime.now(); + break; + default: + break; + } + } + + void enableTimeOut() async { + final timeOut = ref.read(clientSettingsProvider).timeOut; + + if (timeOut == null) return; + + final difference = DateTime.now().difference(dateTime).abs(); + + if (difference > timeOut && ref.read(userProvider)?.authMethod != Authentication.autoLogin && hidden) { + hidden = false; + dateTime = DateTime.now(); + + // Stop playback if the user was still watching a video + await ref.read(videoPlayerProvider).pause(); + + if (context.mounted) { + AdaptiveLayout.of(context).router.push(LockScreenRoute().route); + } + } + } + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addObserver(this); + windowManager.addListener(this); + _init(); + } + + @override + void dispose() { + super.dispose(); + WidgetsBinding.instance.removeObserver(this); + windowManager.removeListener(this); + } + + @override + void onWindowClose() { + ref.read(videoPlayerProvider).stop(); + super.onWindowClose(); + } + + @override + void onWindowResize() async { + final size = await windowManager.getSize(); + ref.read(clientSettingsProvider.notifier).setWindowSize(size); + super.onWindowResize(); + } + + @override + void onWindowResized() async { + final size = await windowManager.getSize(); + ref.read(clientSettingsProvider.notifier).setWindowSize(size); + super.onWindowResized(); + } + + @override + void onWindowMove() async { + final position = await windowManager.getPosition(); + ref.read(clientSettingsProvider.notifier).setWindowPosition(position); + super.onWindowMove(); + } + + @override + void onWindowMoved() async { + final position = await windowManager.getPosition(); + ref.read(clientSettingsProvider.notifier).setWindowPosition(position); + super.onWindowMoved(); + } + + void _init() async { + PackageInfo packageInfo = await PackageInfo.fromPlatform(); + + ref.read(sharedUtilityProvider).loadSettings(); + + final clientSettings = ref.read(clientSettingsProvider); + + if (_isDesktop) { + WindowOptions windowOptions = WindowOptions( + size: Size(clientSettings.size.x, clientSettings.size.y), + center: true, + backgroundColor: Colors.transparent, + skipTaskbar: false, + titleBarStyle: TitleBarStyle.hidden, + title: packageInfo.appName.capitalize()); + + windowManager.waitUntilReadyToShow(windowOptions, () async { + await windowManager.show(); + await windowManager.focus(); + }); + } else { + SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge, overlays: []); + SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( + statusBarColor: Colors.transparent, + systemNavigationBarColor: Colors.transparent, + systemNavigationBarDividerColor: Colors.transparent, + )); + } + } + + @override + Widget build(BuildContext context) { + final themeMode = ref.watch(clientSettingsProvider.select((value) => value.themeMode)); + final themeColor = ref.watch(clientSettingsProvider.select((value) => value.themeColor)); + final amoledBlack = ref.watch(clientSettingsProvider.select((value) => value.amoledBlack)); + final mouseDrag = ref.watch(clientSettingsProvider.select((value) => value.mouseDragSupport)); + final language = ref.watch(clientSettingsProvider + .select((value) => value.selectedLocale ?? WidgetsBinding.instance.platformDispatcher.locale)); + final scrollBehaviour = const MaterialScrollBehavior(); + return Shortcuts( + shortcuts: { + LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(), + }, + child: DynamicColorBuilder(builder: (ColorScheme? lightDynamic, ColorScheme? darkDynamic) { + final lightTheme = themeColor == null + ? FladderTheme.theme(lightDynamic ?? FladderTheme.defaultScheme(Brightness.light)) + : FladderTheme.theme(themeColor.schemeLight); + final darkTheme = (themeColor == null + ? FladderTheme.theme(darkDynamic ?? FladderTheme.defaultScheme(Brightness.dark)) + : FladderTheme.theme(themeColor.schemeDark)); + final amoledOverwrite = amoledBlack ? Colors.black : null; + return ThemesData( + light: lightTheme, + dark: darkTheme, + child: MaterialApp.router( + onGenerateTitle: (context) => ref.watch(currentTitleProvider), + theme: lightTheme, + scrollBehavior: scrollBehaviour.copyWith( + dragDevices: { + ...scrollBehaviour.dragDevices, + mouseDrag ? PointerDeviceKind.mouse : null, + }.whereNotNull().toSet(), + ), + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + builder: (context, child) => Localizations.override( + context: context, + locale: AppLocalizations.supportedLocales.firstWhere( + (element) => element.languageCode == language.languageCode, + orElse: () => Locale('en', "GB"), + ), + child: ScaffoldMessenger(child: child ?? Container()), + ), + darkTheme: darkTheme.copyWith( + scaffoldBackgroundColor: amoledOverwrite, + cardColor: amoledOverwrite, + canvasColor: amoledOverwrite, + colorScheme: darkTheme.colorScheme.copyWith( + surface: amoledOverwrite, + surfaceContainerHighest: amoledOverwrite, + ), + ), + themeMode: themeMode, + routerConfig: AdaptiveLayout.of(context).router, + ), + ); + }), + ); + } + + List getRoutes(LayoutState state) { + switch (state) { + case LayoutState.phone: + return AppRoutes.linearRoutes; + case LayoutState.tablet: + case LayoutState.desktop: + return AppRoutes.nestedRoutes; + } + } +} + +final currentTitleProvider = StateProvider((ref) { + return "Fladder"; +}); diff --git a/lib/models/account_model.dart b/lib/models/account_model.dart new file mode 100644 index 0000000..7bfacc9 --- /dev/null +++ b/lib/models/account_model.dart @@ -0,0 +1,107 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first, invalid_annotation_target + +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/credentials_model.dart'; +import 'package:fladder/util/adaptive_layout.dart'; + +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'account_model.freezed.dart'; +part 'account_model.g.dart'; + +@freezed +class AccountModel with _$AccountModel { + const AccountModel._(); + + const factory AccountModel({ + required String name, + required String id, + required String avatar, + required DateTime lastUsed, + @Default(Authentication.autoLogin) Authentication authMethod, + @Default("") String localPin, + required CredentialsModel credentials, + @Default([]) List latestItemsExcludes, + @Default([]) List searchQueryHistory, + @Default(false) bool quickConnectState, + @JsonKey(includeFromJson: false, includeToJson: false) UserPolicy? policy, + @JsonKey(includeFromJson: false, includeToJson: false) ServerConfiguration? serverConfiguration, + }) = _AccountModel; + + factory AccountModel.fromJson(Map json) => _$AccountModelFromJson(json); + + String get server { + return credentials.server; + } + + bool get canDownload { + return (policy?.enableContentDownloading ?? false) && !kIsWeb; + } + + //Check if it's the same account on the same server + bool sameIdentity(AccountModel other) { + if (identical(this, other)) return true; + return other.id == id && other.credentials.serverId == credentials.serverId; + } +} + +enum Authentication { + autoLogin(0), + biometrics(1), + passcode(2), + none(3); + + const Authentication(this.value); + final int value; + + bool available(BuildContext context) { + switch (this) { + case Authentication.none: + case Authentication.autoLogin: + case Authentication.passcode: + return true; + case Authentication.biometrics: + return !AdaptiveLayout.of(context).isDesktop; + } + } + + String name(BuildContext context) { + switch (this) { + case Authentication.none: + return context.localized.none; + case Authentication.autoLogin: + return context.localized.appLockAutoLogin; + case Authentication.biometrics: + return context.localized.appLockBiometrics; + case Authentication.passcode: + return context.localized.appLockPasscode; + } + } + + IconData get icon { + switch (this) { + case Authentication.none: + return IconsaxBold.arrow_bottom; + case Authentication.autoLogin: + return IconsaxOutline.login_1; + case Authentication.biometrics: + return IconsaxOutline.finger_scan; + case Authentication.passcode: + return IconsaxOutline.password_check; + } + } + + static Authentication fromMap(int value) { + return Authentication.values[value]; + } + + int toMap() { + return value; + } +} diff --git a/lib/models/account_model.freezed.dart b/lib/models/account_model.freezed.dart new file mode 100644 index 0000000..2ec93fd --- /dev/null +++ b/lib/models/account_model.freezed.dart @@ -0,0 +1,450 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'account_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +AccountModel _$AccountModelFromJson(Map json) { + return _AccountModel.fromJson(json); +} + +/// @nodoc +mixin _$AccountModel { + String get name => throw _privateConstructorUsedError; + String get id => throw _privateConstructorUsedError; + String get avatar => throw _privateConstructorUsedError; + DateTime get lastUsed => throw _privateConstructorUsedError; + Authentication get authMethod => throw _privateConstructorUsedError; + String get localPin => throw _privateConstructorUsedError; + CredentialsModel get credentials => throw _privateConstructorUsedError; + List get latestItemsExcludes => throw _privateConstructorUsedError; + List get searchQueryHistory => throw _privateConstructorUsedError; + bool get quickConnectState => throw _privateConstructorUsedError; + @JsonKey(includeFromJson: false, includeToJson: false) + UserPolicy? get policy => throw _privateConstructorUsedError; + @JsonKey(includeFromJson: false, includeToJson: false) + ServerConfiguration? get serverConfiguration => + throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $AccountModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AccountModelCopyWith<$Res> { + factory $AccountModelCopyWith( + AccountModel value, $Res Function(AccountModel) then) = + _$AccountModelCopyWithImpl<$Res, AccountModel>; + @useResult + $Res call( + {String name, + String id, + String avatar, + DateTime lastUsed, + Authentication authMethod, + String localPin, + CredentialsModel credentials, + List latestItemsExcludes, + List searchQueryHistory, + bool quickConnectState, + @JsonKey(includeFromJson: false, includeToJson: false) UserPolicy? policy, + @JsonKey(includeFromJson: false, includeToJson: false) + ServerConfiguration? serverConfiguration}); +} + +/// @nodoc +class _$AccountModelCopyWithImpl<$Res, $Val extends AccountModel> + implements $AccountModelCopyWith<$Res> { + _$AccountModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? name = null, + Object? id = null, + Object? avatar = null, + Object? lastUsed = null, + Object? authMethod = null, + Object? localPin = null, + Object? credentials = null, + Object? latestItemsExcludes = null, + Object? searchQueryHistory = null, + Object? quickConnectState = null, + Object? policy = freezed, + Object? serverConfiguration = freezed, + }) { + return _then(_value.copyWith( + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + avatar: null == avatar + ? _value.avatar + : avatar // ignore: cast_nullable_to_non_nullable + as String, + lastUsed: null == lastUsed + ? _value.lastUsed + : lastUsed // ignore: cast_nullable_to_non_nullable + as DateTime, + authMethod: null == authMethod + ? _value.authMethod + : authMethod // ignore: cast_nullable_to_non_nullable + as Authentication, + localPin: null == localPin + ? _value.localPin + : localPin // ignore: cast_nullable_to_non_nullable + as String, + credentials: null == credentials + ? _value.credentials + : credentials // ignore: cast_nullable_to_non_nullable + as CredentialsModel, + latestItemsExcludes: null == latestItemsExcludes + ? _value.latestItemsExcludes + : latestItemsExcludes // ignore: cast_nullable_to_non_nullable + as List, + searchQueryHistory: null == searchQueryHistory + ? _value.searchQueryHistory + : searchQueryHistory // ignore: cast_nullable_to_non_nullable + as List, + quickConnectState: null == quickConnectState + ? _value.quickConnectState + : quickConnectState // ignore: cast_nullable_to_non_nullable + as bool, + policy: freezed == policy + ? _value.policy + : policy // ignore: cast_nullable_to_non_nullable + as UserPolicy?, + serverConfiguration: freezed == serverConfiguration + ? _value.serverConfiguration + : serverConfiguration // ignore: cast_nullable_to_non_nullable + as ServerConfiguration?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$AccountModelImplCopyWith<$Res> + implements $AccountModelCopyWith<$Res> { + factory _$$AccountModelImplCopyWith( + _$AccountModelImpl value, $Res Function(_$AccountModelImpl) then) = + __$$AccountModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String name, + String id, + String avatar, + DateTime lastUsed, + Authentication authMethod, + String localPin, + CredentialsModel credentials, + List latestItemsExcludes, + List searchQueryHistory, + bool quickConnectState, + @JsonKey(includeFromJson: false, includeToJson: false) UserPolicy? policy, + @JsonKey(includeFromJson: false, includeToJson: false) + ServerConfiguration? serverConfiguration}); +} + +/// @nodoc +class __$$AccountModelImplCopyWithImpl<$Res> + extends _$AccountModelCopyWithImpl<$Res, _$AccountModelImpl> + implements _$$AccountModelImplCopyWith<$Res> { + __$$AccountModelImplCopyWithImpl( + _$AccountModelImpl _value, $Res Function(_$AccountModelImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? name = null, + Object? id = null, + Object? avatar = null, + Object? lastUsed = null, + Object? authMethod = null, + Object? localPin = null, + Object? credentials = null, + Object? latestItemsExcludes = null, + Object? searchQueryHistory = null, + Object? quickConnectState = null, + Object? policy = freezed, + Object? serverConfiguration = freezed, + }) { + return _then(_$AccountModelImpl( + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + avatar: null == avatar + ? _value.avatar + : avatar // ignore: cast_nullable_to_non_nullable + as String, + lastUsed: null == lastUsed + ? _value.lastUsed + : lastUsed // ignore: cast_nullable_to_non_nullable + as DateTime, + authMethod: null == authMethod + ? _value.authMethod + : authMethod // ignore: cast_nullable_to_non_nullable + as Authentication, + localPin: null == localPin + ? _value.localPin + : localPin // ignore: cast_nullable_to_non_nullable + as String, + credentials: null == credentials + ? _value.credentials + : credentials // ignore: cast_nullable_to_non_nullable + as CredentialsModel, + latestItemsExcludes: null == latestItemsExcludes + ? _value._latestItemsExcludes + : latestItemsExcludes // ignore: cast_nullable_to_non_nullable + as List, + searchQueryHistory: null == searchQueryHistory + ? _value._searchQueryHistory + : searchQueryHistory // ignore: cast_nullable_to_non_nullable + as List, + quickConnectState: null == quickConnectState + ? _value.quickConnectState + : quickConnectState // ignore: cast_nullable_to_non_nullable + as bool, + policy: freezed == policy + ? _value.policy + : policy // ignore: cast_nullable_to_non_nullable + as UserPolicy?, + serverConfiguration: freezed == serverConfiguration + ? _value.serverConfiguration + : serverConfiguration // ignore: cast_nullable_to_non_nullable + as ServerConfiguration?, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$AccountModelImpl extends _AccountModel with DiagnosticableTreeMixin { + const _$AccountModelImpl( + {required this.name, + required this.id, + required this.avatar, + required this.lastUsed, + this.authMethod = Authentication.autoLogin, + this.localPin = "", + required this.credentials, + final List latestItemsExcludes = const [], + final List searchQueryHistory = const [], + this.quickConnectState = false, + @JsonKey(includeFromJson: false, includeToJson: false) this.policy, + @JsonKey(includeFromJson: false, includeToJson: false) + this.serverConfiguration}) + : _latestItemsExcludes = latestItemsExcludes, + _searchQueryHistory = searchQueryHistory, + super._(); + + factory _$AccountModelImpl.fromJson(Map json) => + _$$AccountModelImplFromJson(json); + + @override + final String name; + @override + final String id; + @override + final String avatar; + @override + final DateTime lastUsed; + @override + @JsonKey() + final Authentication authMethod; + @override + @JsonKey() + final String localPin; + @override + final CredentialsModel credentials; + final List _latestItemsExcludes; + @override + @JsonKey() + List get latestItemsExcludes { + if (_latestItemsExcludes is EqualUnmodifiableListView) + return _latestItemsExcludes; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_latestItemsExcludes); + } + + final List _searchQueryHistory; + @override + @JsonKey() + List get searchQueryHistory { + if (_searchQueryHistory is EqualUnmodifiableListView) + return _searchQueryHistory; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_searchQueryHistory); + } + + @override + @JsonKey() + final bool quickConnectState; + @override + @JsonKey(includeFromJson: false, includeToJson: false) + final UserPolicy? policy; + @override + @JsonKey(includeFromJson: false, includeToJson: false) + final ServerConfiguration? serverConfiguration; + + @override + String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { + return 'AccountModel(name: $name, id: $id, avatar: $avatar, lastUsed: $lastUsed, authMethod: $authMethod, localPin: $localPin, credentials: $credentials, latestItemsExcludes: $latestItemsExcludes, searchQueryHistory: $searchQueryHistory, quickConnectState: $quickConnectState, policy: $policy, serverConfiguration: $serverConfiguration)'; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('type', 'AccountModel')) + ..add(DiagnosticsProperty('name', name)) + ..add(DiagnosticsProperty('id', id)) + ..add(DiagnosticsProperty('avatar', avatar)) + ..add(DiagnosticsProperty('lastUsed', lastUsed)) + ..add(DiagnosticsProperty('authMethod', authMethod)) + ..add(DiagnosticsProperty('localPin', localPin)) + ..add(DiagnosticsProperty('credentials', credentials)) + ..add(DiagnosticsProperty('latestItemsExcludes', latestItemsExcludes)) + ..add(DiagnosticsProperty('searchQueryHistory', searchQueryHistory)) + ..add(DiagnosticsProperty('quickConnectState', quickConnectState)) + ..add(DiagnosticsProperty('policy', policy)) + ..add(DiagnosticsProperty('serverConfiguration', serverConfiguration)); + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$AccountModelImpl && + (identical(other.name, name) || other.name == name) && + (identical(other.id, id) || other.id == id) && + (identical(other.avatar, avatar) || other.avatar == avatar) && + (identical(other.lastUsed, lastUsed) || + other.lastUsed == lastUsed) && + (identical(other.authMethod, authMethod) || + other.authMethod == authMethod) && + (identical(other.localPin, localPin) || + other.localPin == localPin) && + (identical(other.credentials, credentials) || + other.credentials == credentials) && + const DeepCollectionEquality() + .equals(other._latestItemsExcludes, _latestItemsExcludes) && + const DeepCollectionEquality() + .equals(other._searchQueryHistory, _searchQueryHistory) && + (identical(other.quickConnectState, quickConnectState) || + other.quickConnectState == quickConnectState) && + (identical(other.policy, policy) || other.policy == policy) && + (identical(other.serverConfiguration, serverConfiguration) || + other.serverConfiguration == serverConfiguration)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, + name, + id, + avatar, + lastUsed, + authMethod, + localPin, + credentials, + const DeepCollectionEquality().hash(_latestItemsExcludes), + const DeepCollectionEquality().hash(_searchQueryHistory), + quickConnectState, + policy, + serverConfiguration); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$AccountModelImplCopyWith<_$AccountModelImpl> get copyWith => + __$$AccountModelImplCopyWithImpl<_$AccountModelImpl>(this, _$identity); + + @override + Map toJson() { + return _$$AccountModelImplToJson( + this, + ); + } +} + +abstract class _AccountModel extends AccountModel { + const factory _AccountModel( + {required final String name, + required final String id, + required final String avatar, + required final DateTime lastUsed, + final Authentication authMethod, + final String localPin, + required final CredentialsModel credentials, + final List latestItemsExcludes, + final List searchQueryHistory, + final bool quickConnectState, + @JsonKey(includeFromJson: false, includeToJson: false) + final UserPolicy? policy, + @JsonKey(includeFromJson: false, includeToJson: false) + final ServerConfiguration? serverConfiguration}) = _$AccountModelImpl; + const _AccountModel._() : super._(); + + factory _AccountModel.fromJson(Map json) = + _$AccountModelImpl.fromJson; + + @override + String get name; + @override + String get id; + @override + String get avatar; + @override + DateTime get lastUsed; + @override + Authentication get authMethod; + @override + String get localPin; + @override + CredentialsModel get credentials; + @override + List get latestItemsExcludes; + @override + List get searchQueryHistory; + @override + bool get quickConnectState; + @override + @JsonKey(includeFromJson: false, includeToJson: false) + UserPolicy? get policy; + @override + @JsonKey(includeFromJson: false, includeToJson: false) + ServerConfiguration? get serverConfiguration; + @override + @JsonKey(ignore: true) + _$$AccountModelImplCopyWith<_$AccountModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/account_model.g.dart b/lib/models/account_model.g.dart new file mode 100644 index 0000000..a5e0052 --- /dev/null +++ b/lib/models/account_model.g.dart @@ -0,0 +1,50 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'account_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$AccountModelImpl _$$AccountModelImplFromJson(Map json) => + _$AccountModelImpl( + name: json['name'] as String, + id: json['id'] as String, + avatar: json['avatar'] as String, + lastUsed: DateTime.parse(json['lastUsed'] as String), + authMethod: + $enumDecodeNullable(_$AuthenticationEnumMap, json['authMethod']) ?? + Authentication.autoLogin, + localPin: json['localPin'] as String? ?? "", + credentials: CredentialsModel.fromJson(json['credentials'] as String), + latestItemsExcludes: (json['latestItemsExcludes'] as List?) + ?.map((e) => e as String) + .toList() ?? + const [], + searchQueryHistory: (json['searchQueryHistory'] as List?) + ?.map((e) => e as String) + .toList() ?? + const [], + quickConnectState: json['quickConnectState'] as bool? ?? false, + ); + +Map _$$AccountModelImplToJson(_$AccountModelImpl instance) => + { + 'name': instance.name, + 'id': instance.id, + 'avatar': instance.avatar, + 'lastUsed': instance.lastUsed.toIso8601String(), + 'authMethod': _$AuthenticationEnumMap[instance.authMethod]!, + 'localPin': instance.localPin, + 'credentials': instance.credentials, + 'latestItemsExcludes': instance.latestItemsExcludes, + 'searchQueryHistory': instance.searchQueryHistory, + 'quickConnectState': instance.quickConnectState, + }; + +const _$AuthenticationEnumMap = { + Authentication.autoLogin: 'autoLogin', + Authentication.biometrics: 'biometrics', + Authentication.passcode: 'passcode', + Authentication.none: 'none', +}; diff --git a/lib/models/book_model.dart b/lib/models/book_model.dart new file mode 100644 index 0000000..8f418a1 --- /dev/null +++ b/lib/models/book_model.dart @@ -0,0 +1,72 @@ +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/images_models.dart'; +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/models/items/overview_model.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class BookModel extends ItemBaseModel { + final String? parentName; + final List items; + BookModel( + {this.items = const [], + required this.parentName, + required super.name, + required super.id, + required super.overview, + required super.parentId, + required super.playlistId, + required super.images, + required super.childCount, + required super.primaryRatio, + required super.userData, + super.jellyType, + required super.canDownload, + required super.canDelete}); + + @override + String? get subText => parentName; + + @override + String? detailedName(BuildContext context) => "$name ${parentName != null ? "\n ($parentName)" : ""} "; + + @override + ItemBaseModel get parentBaseModel => copyWith(id: parentId); + + @override + bool get playAble => true; + + int get currentPage => userData.playbackPositionTicks ~/ 10000; + + @override + String playText(BuildContext context) => context.localized.read(name); + + @override + double get progress => userData.progress != 0 ? 100 : 0; + + @override + String playButtonLabel(BuildContext context) => progress != 0 + ? context.localized.continuePage(currentPage) + : userData.played == true + ? "${context.localized.restart} $name" + : context.localized.read(name); + + factory BookModel.fromBaseDto(BaseItemDto item, Ref ref) { + return BookModel( + name: item.name ?? "", + id: item.id ?? "", + parentName: item.seriesName ?? item.seasonName, + childCount: item.childCount, + overview: OverviewModel.fromBaseItemDto(item, ref), + userData: UserData.fromDto(item.userData), + parentId: item.parentId, + playlistId: item.playlistItemId, + images: ImagesData.fromBaseItem(item, ref), + canDelete: item.canDelete, + canDownload: item.canDownload, + primaryRatio: item.primaryImageAspectRatio, + ); + } +} diff --git a/lib/models/boxset_model.dart b/lib/models/boxset_model.dart new file mode 100644 index 0000000..f05b01e --- /dev/null +++ b/lib/models/boxset_model.dart @@ -0,0 +1,47 @@ +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/images_models.dart'; +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/models/items/overview_model.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:dart_mappable/dart_mappable.dart'; + +part 'boxset_model.mapper.dart'; + +@MappableClass() +class BoxSetModel extends ItemBaseModel with BoxSetModelMappable { + final List items; + const BoxSetModel({ + this.items = const [], + required super.name, + required super.id, + required super.overview, + required super.parentId, + required super.playlistId, + required super.images, + required super.childCount, + required super.primaryRatio, + required super.userData, + required super.canDelete, + required super.canDownload, + super.jellyType, + }); + + factory BoxSetModel.fromBaseDto(BaseItemDto item, Ref ref) { + return BoxSetModel( + name: item.name ?? "", + id: item.id ?? "", + childCount: item.childCount, + overview: OverviewModel.fromBaseItemDto(item, ref), + userData: UserData.fromDto(item.userData), + parentId: item.parentId, + playlistId: item.playlistItemId, + images: ImagesData.fromBaseItem(item, ref), + primaryRatio: item.primaryImageAspectRatio, + canDelete: item.canDelete, + canDownload: item.canDownload, + jellyType: item.type, + ); + } +} diff --git a/lib/models/boxset_model.mapper.dart b/lib/models/boxset_model.mapper.dart new file mode 100644 index 0000000..3904439 --- /dev/null +++ b/lib/models/boxset_model.mapper.dart @@ -0,0 +1,242 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member +// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter + +part of 'boxset_model.dart'; + +class BoxSetModelMapper extends SubClassMapperBase { + BoxSetModelMapper._(); + + static BoxSetModelMapper? _instance; + static BoxSetModelMapper ensureInitialized() { + if (_instance == null) { + MapperContainer.globals.use(_instance = BoxSetModelMapper._()); + ItemBaseModelMapper.ensureInitialized().addSubMapper(_instance!); + ItemBaseModelMapper.ensureInitialized(); + OverviewModelMapper.ensureInitialized(); + UserDataMapper.ensureInitialized(); + } + return _instance!; + } + + @override + final String id = 'BoxSetModel'; + + static List _$items(BoxSetModel v) => v.items; + static const Field> _f$items = + Field('items', _$items, opt: true, def: const []); + static String _$name(BoxSetModel v) => v.name; + static const Field _f$name = Field('name', _$name); + static String _$id(BoxSetModel v) => v.id; + static const Field _f$id = Field('id', _$id); + static OverviewModel _$overview(BoxSetModel v) => v.overview; + static const Field _f$overview = + Field('overview', _$overview); + static String? _$parentId(BoxSetModel v) => v.parentId; + static const Field _f$parentId = + Field('parentId', _$parentId); + static String? _$playlistId(BoxSetModel v) => v.playlistId; + static const Field _f$playlistId = + Field('playlistId', _$playlistId); + static ImagesData? _$images(BoxSetModel v) => v.images; + static const Field _f$images = + Field('images', _$images); + static int? _$childCount(BoxSetModel v) => v.childCount; + static const Field _f$childCount = + Field('childCount', _$childCount); + static double? _$primaryRatio(BoxSetModel v) => v.primaryRatio; + static const Field _f$primaryRatio = + Field('primaryRatio', _$primaryRatio); + static UserData _$userData(BoxSetModel v) => v.userData; + static const Field _f$userData = + Field('userData', _$userData); + static bool? _$canDelete(BoxSetModel v) => v.canDelete; + static const Field _f$canDelete = + Field('canDelete', _$canDelete); + static bool? _$canDownload(BoxSetModel v) => v.canDownload; + static const Field _f$canDownload = + Field('canDownload', _$canDownload); + static BaseItemKind? _$jellyType(BoxSetModel v) => v.jellyType; + static const Field _f$jellyType = + Field('jellyType', _$jellyType, opt: true); + + @override + final MappableFields fields = const { + #items: _f$items, + #name: _f$name, + #id: _f$id, + #overview: _f$overview, + #parentId: _f$parentId, + #playlistId: _f$playlistId, + #images: _f$images, + #childCount: _f$childCount, + #primaryRatio: _f$primaryRatio, + #userData: _f$userData, + #canDelete: _f$canDelete, + #canDownload: _f$canDownload, + #jellyType: _f$jellyType, + }; + @override + final bool ignoreNull = true; + + @override + final String discriminatorKey = 'type'; + @override + final dynamic discriminatorValue = 'BoxSetModel'; + @override + late final ClassMapperBase superMapper = + ItemBaseModelMapper.ensureInitialized(); + + static BoxSetModel _instantiate(DecodingData data) { + return BoxSetModel( + items: data.dec(_f$items), + name: data.dec(_f$name), + id: data.dec(_f$id), + overview: data.dec(_f$overview), + parentId: data.dec(_f$parentId), + playlistId: data.dec(_f$playlistId), + images: data.dec(_f$images), + childCount: data.dec(_f$childCount), + primaryRatio: data.dec(_f$primaryRatio), + userData: data.dec(_f$userData), + canDelete: data.dec(_f$canDelete), + canDownload: data.dec(_f$canDownload), + jellyType: data.dec(_f$jellyType)); + } + + @override + final Function instantiate = _instantiate; + + static BoxSetModel fromMap(Map map) { + return ensureInitialized().decodeMap(map); + } + + static BoxSetModel fromJson(String json) { + return ensureInitialized().decodeJson(json); + } +} + +mixin BoxSetModelMappable { + String toJson() { + return BoxSetModelMapper.ensureInitialized() + .encodeJson(this as BoxSetModel); + } + + Map toMap() { + return BoxSetModelMapper.ensureInitialized() + .encodeMap(this as BoxSetModel); + } + + BoxSetModelCopyWith get copyWith => + _BoxSetModelCopyWithImpl(this as BoxSetModel, $identity, $identity); + @override + String toString() { + return BoxSetModelMapper.ensureInitialized() + .stringifyValue(this as BoxSetModel); + } +} + +extension BoxSetModelValueCopy<$R, $Out> + on ObjectCopyWith<$R, BoxSetModel, $Out> { + BoxSetModelCopyWith<$R, BoxSetModel, $Out> get $asBoxSetModel => + $base.as((v, t, t2) => _BoxSetModelCopyWithImpl(v, t, t2)); +} + +abstract class BoxSetModelCopyWith<$R, $In extends BoxSetModel, $Out> + implements ItemBaseModelCopyWith<$R, $In, $Out> { + ListCopyWith<$R, ItemBaseModel, + ItemBaseModelCopyWith<$R, ItemBaseModel, ItemBaseModel>> get items; + @override + OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview; + @override + UserDataCopyWith<$R, UserData, UserData> get userData; + @override + $R call( + {List? items, + String? name, + String? id, + OverviewModel? overview, + String? parentId, + String? playlistId, + ImagesData? images, + int? childCount, + double? primaryRatio, + UserData? userData, + bool? canDelete, + bool? canDownload, + BaseItemKind? jellyType}); + BoxSetModelCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t); +} + +class _BoxSetModelCopyWithImpl<$R, $Out> + extends ClassCopyWithBase<$R, BoxSetModel, $Out> + implements BoxSetModelCopyWith<$R, BoxSetModel, $Out> { + _BoxSetModelCopyWithImpl(super.value, super.then, super.then2); + + @override + late final ClassMapperBase $mapper = + BoxSetModelMapper.ensureInitialized(); + @override + ListCopyWith<$R, ItemBaseModel, + ItemBaseModelCopyWith<$R, ItemBaseModel, ItemBaseModel>> + get items => ListCopyWith( + $value.items, (v, t) => v.copyWith.$chain(t), (v) => call(items: v)); + @override + OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview => + $value.overview.copyWith.$chain((v) => call(overview: v)); + @override + UserDataCopyWith<$R, UserData, UserData> get userData => + $value.userData.copyWith.$chain((v) => call(userData: v)); + @override + $R call( + {List? items, + String? name, + String? id, + OverviewModel? overview, + Object? parentId = $none, + Object? playlistId = $none, + Object? images = $none, + Object? childCount = $none, + Object? primaryRatio = $none, + UserData? userData, + Object? canDelete = $none, + Object? canDownload = $none, + Object? jellyType = $none}) => + $apply(FieldCopyWithData({ + if (items != null) #items: items, + if (name != null) #name: name, + if (id != null) #id: id, + if (overview != null) #overview: overview, + if (parentId != $none) #parentId: parentId, + if (playlistId != $none) #playlistId: playlistId, + if (images != $none) #images: images, + if (childCount != $none) #childCount: childCount, + if (primaryRatio != $none) #primaryRatio: primaryRatio, + if (userData != null) #userData: userData, + if (canDelete != $none) #canDelete: canDelete, + if (canDownload != $none) #canDownload: canDownload, + if (jellyType != $none) #jellyType: jellyType + })); + @override + BoxSetModel $make(CopyWithData data) => BoxSetModel( + items: data.get(#items, or: $value.items), + name: data.get(#name, or: $value.name), + id: data.get(#id, or: $value.id), + overview: data.get(#overview, or: $value.overview), + parentId: data.get(#parentId, or: $value.parentId), + playlistId: data.get(#playlistId, or: $value.playlistId), + images: data.get(#images, or: $value.images), + childCount: data.get(#childCount, or: $value.childCount), + primaryRatio: data.get(#primaryRatio, or: $value.primaryRatio), + userData: data.get(#userData, or: $value.userData), + canDelete: data.get(#canDelete, or: $value.canDelete), + canDownload: data.get(#canDownload, or: $value.canDownload), + jellyType: data.get(#jellyType, or: $value.jellyType)); + + @override + BoxSetModelCopyWith<$R2, BoxSetModel, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t) => + _BoxSetModelCopyWithImpl($value, $cast, t); +} diff --git a/lib/models/collection_types.dart b/lib/models/collection_types.dart new file mode 100644 index 0000000..7769c22 --- /dev/null +++ b/lib/models/collection_types.dart @@ -0,0 +1,49 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:flutter/material.dart'; + +extension CollectionTypeExtension on CollectionType { + IconData get iconOutlined { + return getIconType(true); + } + + IconData get icon { + return getIconType(false); + } + + Set get itemKinds { + switch (this) { + case CollectionType.movies: + return {FladderItemType.movie}; + case CollectionType.tvshows: + return {FladderItemType.series}; + case CollectionType.homevideos: + return {FladderItemType.photoalbum, FladderItemType.folder, FladderItemType.photo, FladderItemType.video}; + case CollectionType.boxsets: + case CollectionType.folders: + case CollectionType.books: + default: + return {}; + } + } + + IconData getIconType(bool outlined) { + switch (this) { + case CollectionType.movies: + return outlined ? IconsaxOutline.video_horizontal : IconsaxBold.video_horizontal; + case CollectionType.tvshows: + return outlined ? IconsaxOutline.video_vertical : IconsaxBold.video_vertical; + case CollectionType.boxsets: + case CollectionType.folders: + return outlined ? IconsaxOutline.folder : IconsaxBold.folder; + case CollectionType.homevideos: + return outlined ? IconsaxOutline.gallery : IconsaxBold.gallery; + case CollectionType.books: + return outlined ? IconsaxOutline.book : Icons.book_rounded; + default: + return IconsaxOutline.info_circle; + } + } +} diff --git a/lib/models/credentials_model.dart b/lib/models/credentials_model.dart new file mode 100644 index 0000000..9bd2c4a --- /dev/null +++ b/lib/models/credentials_model.dart @@ -0,0 +1,81 @@ +import 'dart:convert'; + +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/util/application_info.dart'; +import 'package:xid/xid.dart'; + +class CredentialsModel { + final String token; + final String server; + final String serverName; + final String serverId; + final String deviceId; + CredentialsModel({ + this.token = "", + this.server = "", + this.serverName = "", + this.serverId = "", + required this.deviceId, + }); + + factory CredentialsModel.createNewCredentials() { + return CredentialsModel(deviceId: Xid().toString()); + } + + Map header(Ref ref) { + final application = ref.read(applicationInfoProvider); + final headers = { + 'content-type': 'application/json', + 'x-emby-token': token, + 'x-emby-authorization': + 'MediaBrowser Client="${application.name}", Device="${application.os}", DeviceId="$deviceId", Version="${application.version}"' + }; + return headers; + } + + CredentialsModel copyWith({ + String? token, + String? server, + String? serverName, + String? serverId, + String? deviceId, + }) { + return CredentialsModel( + token: token ?? this.token, + server: server ?? this.server, + serverName: serverName ?? this.serverName, + serverId: serverId ?? this.serverId, + deviceId: deviceId ?? this.deviceId, + ); + } + + Map toMap() { + return { + 'token': token, + 'server': server, + 'serverName': serverName, + 'serverId': serverId, + 'deviceId': deviceId, + }; + } + + factory CredentialsModel.fromMap(Map map) { + return CredentialsModel( + token: map['token'] ?? '', + server: map['server'] ?? '', + serverName: map['serverName'] ?? '', + serverId: map['serverId'] ?? '', + deviceId: map['deviceId'] ?? '', + ); + } + + String toJson() => json.encode(toMap()); + + factory CredentialsModel.fromJson(String source) => CredentialsModel.fromMap(json.decode(source)); + + @override + String toString() { + return 'CredentialsModel(token: $token, server: $server, serverName: $serverName, serverId: $serverId, header: $header)'; + } +} diff --git a/lib/models/favourites_model.dart b/lib/models/favourites_model.dart new file mode 100644 index 0000000..1a2a5bd --- /dev/null +++ b/lib/models/favourites_model.dart @@ -0,0 +1,26 @@ +import 'package:fladder/models/item_base_model.dart'; + +class FavouritesModel { + final bool loading; + final Map> favourites; + final List people; + + FavouritesModel({ + this.loading = false, + this.favourites = const {}, + this.people = const [], + }); + + FavouritesModel copyWith({ + bool? loading, + String? searchQuery, + Map>? favourites, + List? people, + }) { + return FavouritesModel( + loading: loading ?? this.loading, + favourites: favourites ?? this.favourites, + people: people ?? this.people, + ); + } +} diff --git a/lib/models/home_model.dart b/lib/models/home_model.dart new file mode 100644 index 0000000..119917a --- /dev/null +++ b/lib/models/home_model.dart @@ -0,0 +1,34 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +import 'package:fladder/models/item_base_model.dart'; + +class HomeModel { + final bool loading; + final List resumeVideo; + final List resumeAudio; + final List resumeBooks; + final List nextUp; + HomeModel({ + this.loading = false, + this.resumeVideo = const [], + this.resumeAudio = const [], + this.resumeBooks = const [], + this.nextUp = const [], + }); + + HomeModel copyWith({ + bool? loading, + List? resumeVideo, + List? resumeAudio, + List? resumeBooks, + List? nextUp, + List? nextUpBooks, + }) { + return HomeModel( + loading: loading ?? this.loading, + resumeVideo: resumeVideo ?? this.resumeVideo, + resumeAudio: resumeAudio ?? this.resumeAudio, + resumeBooks: resumeBooks ?? this.resumeBooks, + nextUp: nextUp ?? this.nextUp, + ); + } +} diff --git a/lib/models/information_model.dart b/lib/models/information_model.dart new file mode 100644 index 0000000..a6a5050 --- /dev/null +++ b/lib/models/information_model.dart @@ -0,0 +1,107 @@ +// ignore_for_file: constant_identifier_names + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/util/size_formatting.dart'; + +class InformationModel { + final Map baseInformation; + final List> videoStreams; + final List> audioStreams; + final List> subStreams; + InformationModel({ + required this.baseInformation, + required this.videoStreams, + required this.audioStreams, + required this.subStreams, + }); + + static InformationModel? fromResponse(BaseItemDto? item) { + if (item == null) return null; + var videoStreams = item.mediaStreams?.where((element) => element.type == MediaStreamType.video).toList() ?? []; + var audioStreams = item.mediaStreams?.where((element) => element.type == MediaStreamType.audio).toList() ?? []; + var subStreams = item.mediaStreams?.where((element) => element.type == MediaStreamType.subtitle).toList() ?? []; + return InformationModel( + baseInformation: { + "Title": item.name, + "Container": item.container, + "Path": item.path, + "Size": item.mediaSources?.firstOrNull?.size.byteFormat, + }, + videoStreams: videoStreams + .map( + (e) => { + "Title": e.displayTitle, + "Codec": e.codec, + "Profile": e.profile, + "Level": e.level, + "Resolution": "${e.width}x${e.height}", + "Aspect Ration": e.aspectRatio, + "Interlaced": e.isInterlaced, + "FrameRate": e.realFrameRate, + "Bitrate": "${e.bitRate} kbps", + "Bit depth": e.bitDepth, + "Video range": e.videoRange, + "Video range type": e.videoRangeType, + "Ref frames": e.refFrames, + }, + ) + .toList(), + audioStreams: audioStreams + .map( + (e) => { + "Title": e.displayTitle, + "Language": e.language, + "Codec": e.codec, + "Layout": e.channelLayout, + "Bitrate": "${e.bitRate} kbps", + "Sample Rate": "${e.sampleRate} Hz", + "Default": e.isDefault, + "Forced": e.isForced, + "External": e.isExternal, + }, + ) + .toList(), + subStreams: subStreams + .map( + (e) => { + "Title": e.displayTitle, + "Language": e.language, + "Codec": e.codec, + "Profile": e.profile, + "Default": e.isDefault, + "Forced": e.isForced, + "External": e.isExternal, + }, + ) + .toList(), + ); + } + + InformationModel copyWith({ + Map? baseInformation, + List>? videoStreams, + List>? audioStreams, + List>? subStreams, + }) { + return InformationModel( + baseInformation: baseInformation ?? this.baseInformation, + videoStreams: videoStreams ?? this.videoStreams, + audioStreams: audioStreams ?? this.audioStreams, + subStreams: subStreams ?? this.subStreams, + ); + } + + static String mapToString(Map map) { + return map.entries.map((e) => "${e.key}: ${e.value}").join("\n"); + } + + static String streamsToString(List> streams) { + return streams.map((e) => mapToString(e)).join("\n"); + } + + @override + String toString() => "${mapToString(baseInformation)}\n\n" + "${streamsToString(videoStreams)}\n\n" + "${streamsToString(audioStreams)}\n\n" + "${streamsToString(subStreams)}\n\n"; +} diff --git a/lib/models/item_base_model.dart b/lib/models/item_base_model.dart new file mode 100644 index 0000000..ea77d5f --- /dev/null +++ b/lib/models/item_base_model.dart @@ -0,0 +1,363 @@ +import 'package:dart_mappable/dart_mappable.dart'; +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/book_model.dart'; +import 'package:fladder/models/boxset_model.dart'; +import 'package:fladder/models/items/media_streams_model.dart'; +import 'package:fladder/models/library_search/library_search_options.dart'; +import 'package:fladder/models/playlist_model.dart'; +import 'package:fladder/routes/build_routes/home_routes.dart'; +import 'package:fladder/routes/build_routes/route_builder.dart'; +import 'package:fladder/screens/details_screens/book_detail_screen.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/string_extensions.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart' as dto; +import 'package:fladder/models/items/episode_model.dart'; +import 'package:fladder/models/items/folder_model.dart'; +import 'package:fladder/models/items/images_models.dart'; +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/models/items/movie_model.dart'; +import 'package:fladder/models/items/overview_model.dart'; +import 'package:fladder/models/items/person_model.dart'; +import 'package:fladder/models/items/photos_model.dart'; +import 'package:fladder/models/items/season_model.dart'; +import 'package:fladder/models/items/series_model.dart'; +import 'package:fladder/screens/details_screens/details_screens.dart'; +import 'package:fladder/screens/details_screens/episode_detail_screen.dart'; +import 'package:fladder/screens/details_screens/season_detail_screen.dart'; +import 'package:fladder/screens/library_search/library_search_screen.dart'; + +part 'item_base_model.mapper.dart'; + +@MappableClass() +class ItemBaseModel with ItemBaseModelMappable { + final String name; + final String id; + final OverviewModel overview; + final String? parentId; + final String? playlistId; + final ImagesData? images; + final int? childCount; + final double? primaryRatio; + final UserData userData; + final bool? canDownload; + final bool? canDelete; + final dto.BaseItemKind? jellyType; + + const ItemBaseModel({ + required this.name, + required this.id, + required this.overview, + required this.parentId, + required this.playlistId, + required this.images, + required this.childCount, + required this.primaryRatio, + required this.userData, + required this.canDownload, + required this.canDelete, + required this.jellyType, + }); + + String get title => name; + + ItemBaseModel? setProgress(double progress) { + return copyWith(userData: userData.copyWith(progress: progress)); + } + + Widget? subTitle(SortingOptions options) => switch (options) { + SortingOptions.parentalRating => overview.parentalRating != null + ? Row( + children: [ + Icon( + IconsaxBold.star_1, + size: 14, + color: Colors.yellowAccent, + ), + const SizedBox(width: 6), + Text((overview.parentalRating ?? 0.0).toString()) + ], + ) + : null, + SortingOptions.communityRating => overview.communityRating != null + ? Row( + children: [ + Icon( + IconsaxBold.star_1, + size: 14, + color: Colors.yellowAccent, + ), + const SizedBox(width: 6), + Text((overview.communityRating ?? 0.0).toString()) + ], + ) + : null, + _ => null, + }; + + ///Used for retrieving the correct id when fetching queue + String get streamId => id; + + ItemBaseModel get parentBaseModel => copyWith(id: parentId); + + bool get emptyShow => false; + + bool get identifiable => false; + + int? get unPlayedItemCount => userData.unPlayedItemCount; + + bool get unWatched => !userData.played && userData.progress <= 0 && userData.unPlayedItemCount == 0; + + String? detailedName(BuildContext context) => null; + + String? get subText => null; + String? subTextShort(BuildContext context) => null; + String? label(BuildContext context) => null; + + ImagesData? get getPosters => images; + + ImageData? get bannerImage => images?.primary ?? getPosters?.randomBackDrop ?? getPosters?.primary; + + bool get playAble => false; + + bool get syncAble => false; + + bool get galleryItem => false; + + MediaStreamsModel? get streamModel => null; + + String playText(BuildContext context) => context.localized.play(name); + + double get progress => userData.progress; + + String playButtonLabel(BuildContext context) => + progress != 0 ? context.localized.resume(name.maxLength()) : context.localized.play(name.maxLength()); + + Widget get detailScreenWidget { + switch (this) { + case PersonModel _: + return PersonDetailScreen(person: Person(id: id, image: images?.primary)); + case SeasonModel _: + return SeasonDetailScreen(item: this); + case FolderModel _: + case PhotoAlbumModel _: + case BoxSetModel _: + case PlaylistModel _: + return LibrarySearchScreen(folderId: [id]); + case PhotoModel _: + final photo = this as PhotoModel; + return LibrarySearchScreen( + folderId: [photo.albumId ?? photo.parentId ?? ""], + photoToView: photo, + ); + case BookModel book: + return BookDetailScreen(item: book); + case MovieModel _: + return MovieDetailScreen(item: this); + case EpisodeModel _: + return EpisodeDetailScreen(item: this); + case SeriesModel series: + return SeriesDetailScreen(item: series); + default: + return EmptyItem(item: this); + } + } + + Future navigateTo(BuildContext context) async => context.routePush(DetailsRoute(id: id), extra: this); + + factory ItemBaseModel.fromBaseDto(dto.BaseItemDto item, Ref ref) { + return switch (item.type) { + BaseItemKind.photo || BaseItemKind.video => PhotoModel.fromBaseDto(item, ref), + BaseItemKind.photoalbum => PhotoAlbumModel.fromBaseDto(item, ref), + BaseItemKind.folder || + BaseItemKind.collectionfolder || + BaseItemKind.aggregatefolder => + FolderModel.fromBaseDto(item, ref), + BaseItemKind.episode => EpisodeModel.fromBaseDto(item, ref), + BaseItemKind.movie => MovieModel.fromBaseDto(item, ref), + BaseItemKind.series => SeriesModel.fromBaseDto(item, ref), + BaseItemKind.person => PersonModel.fromBaseDto(item, ref), + BaseItemKind.season => SeasonModel.fromBaseDto(item, ref), + BaseItemKind.boxset => BoxSetModel.fromBaseDto(item, ref), + BaseItemKind.book => BookModel.fromBaseDto(item, ref), + BaseItemKind.playlist => PlaylistModel.fromBaseDto(item, ref), + _ => ItemBaseModel._fromBaseDto(item, ref) + }; + } + + factory ItemBaseModel._fromBaseDto(dto.BaseItemDto item, Ref ref) { + return ItemBaseModel( + name: item.name ?? "", + id: item.id ?? "", + childCount: item.childCount, + overview: OverviewModel.fromBaseItemDto(item, ref), + userData: UserData.fromDto(item.userData), + parentId: item.parentId, + playlistId: item.playlistItemId, + images: ImagesData.fromBaseItem(item, ref), + primaryRatio: item.primaryImageAspectRatio, + canDelete: item.canDelete, + canDownload: item.canDownload, + jellyType: item.type, + ); + } + + FladderItemType get type => switch (this) { + MovieModel _ => FladderItemType.movie, + SeriesModel _ => FladderItemType.series, + SeasonModel _ => FladderItemType.season, + PhotoAlbumModel _ => FladderItemType.photoalbum, + PhotoModel model => model.internalType, + EpisodeModel _ => FladderItemType.episode, + BookModel _ => FladderItemType.book, + PlaylistModel _ => FladderItemType.playlist, + FolderModel _ => FladderItemType.folder, + ItemBaseModel _ => FladderItemType.baseType, + }; + + @override + bool operator ==(covariant ItemBaseModel other) { + if (identical(this, other)) return true; + return other.id == id; + } + + @override + int get hashCode { + return id.hashCode ^ type.hashCode; + } +} + +// Currently supported types +enum FladderItemType { + baseType( + icon: IconsaxOutline.folder_2, + selectedicon: IconsaxBold.folder_2, + ), + audio( + icon: IconsaxOutline.music, + selectedicon: IconsaxBold.music, + ), + musicAlbum( + icon: IconsaxOutline.music, + selectedicon: IconsaxBold.music, + ), + musicVideo( + icon: IconsaxOutline.music, + selectedicon: IconsaxBold.music, + ), + collectionFolder( + icon: IconsaxOutline.music, + selectedicon: IconsaxBold.music, + ), + video( + icon: IconsaxOutline.video, + selectedicon: IconsaxBold.video, + ), + movie( + icon: IconsaxOutline.video_horizontal, + selectedicon: IconsaxBold.video_horizontal, + ), + series( + icon: IconsaxOutline.video_vertical, + selectedicon: IconsaxBold.video_vertical, + ), + season( + icon: IconsaxOutline.video_vertical, + selectedicon: IconsaxBold.video_vertical, + ), + episode( + icon: IconsaxOutline.video_vertical, + selectedicon: IconsaxBold.video_vertical, + ), + photo( + icon: IconsaxOutline.picture_frame, + selectedicon: IconsaxBold.picture_frame, + ), + person( + icon: IconsaxOutline.user, + selectedicon: IconsaxBold.user, + ), + photoalbum( + icon: IconsaxOutline.gallery, + selectedicon: IconsaxBold.gallery, + ), + folder( + icon: IconsaxOutline.folder, + selectedicon: IconsaxBold.folder, + ), + boxset( + icon: IconsaxOutline.bookmark, + selectedicon: IconsaxBold.bookmark, + ), + playlist( + icon: IconsaxOutline.archive_book, + selectedicon: IconsaxBold.archive_book, + ), + book( + icon: IconsaxOutline.book, + selectedicon: IconsaxBold.book, + ); + + const FladderItemType({required this.icon, required this.selectedicon}); + + static Set get playable => { + FladderItemType.series, + FladderItemType.episode, + FladderItemType.season, + FladderItemType.movie, + FladderItemType.musicVideo, + }; + + static Set get galleryItem => { + FladderItemType.photo, + FladderItemType.video, + }; + + String label(BuildContext context) { + return switch (this) { + FladderItemType.baseType => context.localized.mediaTypeBase, + FladderItemType.audio => context.localized.audio, + FladderItemType.collectionFolder => context.localized.collectionFolder, + FladderItemType.musicAlbum => context.localized.musicAlbum, + FladderItemType.musicVideo => context.localized.video, + FladderItemType.video => context.localized.video, + FladderItemType.movie => context.localized.mediaTypeMovie, + FladderItemType.series => context.localized.mediaTypeSeries, + FladderItemType.season => context.localized.mediaTypeSeason, + FladderItemType.episode => context.localized.mediaTypeEpisode, + FladderItemType.photo => context.localized.mediaTypePhoto, + FladderItemType.person => context.localized.mediaTypePerson, + FladderItemType.photoalbum => context.localized.mediaTypePhotoAlbum, + FladderItemType.folder => context.localized.mediaTypeFolder, + FladderItemType.boxset => context.localized.mediaTypeBoxset, + FladderItemType.playlist => context.localized.mediaTypePlaylist, + FladderItemType.book => context.localized.mediaTypeBook, + }; + } + + BaseItemKind get dtoKind => switch (this) { + FladderItemType.baseType => BaseItemKind.userrootfolder, + FladderItemType.audio => BaseItemKind.audio, + FladderItemType.collectionFolder => BaseItemKind.collectionfolder, + FladderItemType.musicAlbum => BaseItemKind.musicalbum, + FladderItemType.musicVideo => BaseItemKind.video, + FladderItemType.video => BaseItemKind.video, + FladderItemType.movie => BaseItemKind.movie, + FladderItemType.series => BaseItemKind.series, + FladderItemType.season => BaseItemKind.season, + FladderItemType.episode => BaseItemKind.episode, + FladderItemType.photo => BaseItemKind.photo, + FladderItemType.person => BaseItemKind.person, + FladderItemType.photoalbum => BaseItemKind.photoalbum, + FladderItemType.folder => BaseItemKind.folder, + FladderItemType.boxset => BaseItemKind.boxset, + FladderItemType.playlist => BaseItemKind.playlist, + FladderItemType.book => BaseItemKind.book, + }; + + final IconData icon; + final IconData selectedicon; +} diff --git a/lib/models/item_base_model.mapper.dart b/lib/models/item_base_model.mapper.dart new file mode 100644 index 0000000..fe85f01 --- /dev/null +++ b/lib/models/item_base_model.mapper.dart @@ -0,0 +1,214 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member +// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter + +part of 'item_base_model.dart'; + +class ItemBaseModelMapper extends ClassMapperBase { + ItemBaseModelMapper._(); + + static ItemBaseModelMapper? _instance; + static ItemBaseModelMapper ensureInitialized() { + if (_instance == null) { + MapperContainer.globals.use(_instance = ItemBaseModelMapper._()); + OverviewModelMapper.ensureInitialized(); + UserDataMapper.ensureInitialized(); + } + return _instance!; + } + + @override + final String id = 'ItemBaseModel'; + + static String _$name(ItemBaseModel v) => v.name; + static const Field _f$name = Field('name', _$name); + static String _$id(ItemBaseModel v) => v.id; + static const Field _f$id = Field('id', _$id); + static OverviewModel _$overview(ItemBaseModel v) => v.overview; + static const Field _f$overview = + Field('overview', _$overview); + static String? _$parentId(ItemBaseModel v) => v.parentId; + static const Field _f$parentId = + Field('parentId', _$parentId); + static String? _$playlistId(ItemBaseModel v) => v.playlistId; + static const Field _f$playlistId = + Field('playlistId', _$playlistId); + static ImagesData? _$images(ItemBaseModel v) => v.images; + static const Field _f$images = + Field('images', _$images); + static int? _$childCount(ItemBaseModel v) => v.childCount; + static const Field _f$childCount = + Field('childCount', _$childCount); + static double? _$primaryRatio(ItemBaseModel v) => v.primaryRatio; + static const Field _f$primaryRatio = + Field('primaryRatio', _$primaryRatio); + static UserData _$userData(ItemBaseModel v) => v.userData; + static const Field _f$userData = + Field('userData', _$userData); + static bool? _$canDownload(ItemBaseModel v) => v.canDownload; + static const Field _f$canDownload = + Field('canDownload', _$canDownload); + static bool? _$canDelete(ItemBaseModel v) => v.canDelete; + static const Field _f$canDelete = + Field('canDelete', _$canDelete); + static dto.BaseItemKind? _$jellyType(ItemBaseModel v) => v.jellyType; + static const Field _f$jellyType = + Field('jellyType', _$jellyType); + + @override + final MappableFields fields = const { + #name: _f$name, + #id: _f$id, + #overview: _f$overview, + #parentId: _f$parentId, + #playlistId: _f$playlistId, + #images: _f$images, + #childCount: _f$childCount, + #primaryRatio: _f$primaryRatio, + #userData: _f$userData, + #canDownload: _f$canDownload, + #canDelete: _f$canDelete, + #jellyType: _f$jellyType, + }; + @override + final bool ignoreNull = true; + + static ItemBaseModel _instantiate(DecodingData data) { + return ItemBaseModel( + name: data.dec(_f$name), + id: data.dec(_f$id), + overview: data.dec(_f$overview), + parentId: data.dec(_f$parentId), + playlistId: data.dec(_f$playlistId), + images: data.dec(_f$images), + childCount: data.dec(_f$childCount), + primaryRatio: data.dec(_f$primaryRatio), + userData: data.dec(_f$userData), + canDownload: data.dec(_f$canDownload), + canDelete: data.dec(_f$canDelete), + jellyType: data.dec(_f$jellyType)); + } + + @override + final Function instantiate = _instantiate; + + static ItemBaseModel fromMap(Map map) { + return ensureInitialized().decodeMap(map); + } + + static ItemBaseModel fromJson(String json) { + return ensureInitialized().decodeJson(json); + } +} + +mixin ItemBaseModelMappable { + String toJson() { + return ItemBaseModelMapper.ensureInitialized() + .encodeJson(this as ItemBaseModel); + } + + Map toMap() { + return ItemBaseModelMapper.ensureInitialized() + .encodeMap(this as ItemBaseModel); + } + + ItemBaseModelCopyWith + get copyWith => _ItemBaseModelCopyWithImpl( + this as ItemBaseModel, $identity, $identity); + @override + String toString() { + return ItemBaseModelMapper.ensureInitialized() + .stringifyValue(this as ItemBaseModel); + } +} + +extension ItemBaseModelValueCopy<$R, $Out> + on ObjectCopyWith<$R, ItemBaseModel, $Out> { + ItemBaseModelCopyWith<$R, ItemBaseModel, $Out> get $asItemBaseModel => + $base.as((v, t, t2) => _ItemBaseModelCopyWithImpl(v, t, t2)); +} + +abstract class ItemBaseModelCopyWith<$R, $In extends ItemBaseModel, $Out> + implements ClassCopyWith<$R, $In, $Out> { + OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview; + UserDataCopyWith<$R, UserData, UserData> get userData; + $R call( + {String? name, + String? id, + OverviewModel? overview, + String? parentId, + String? playlistId, + ImagesData? images, + int? childCount, + double? primaryRatio, + UserData? userData, + bool? canDownload, + bool? canDelete, + dto.BaseItemKind? jellyType}); + ItemBaseModelCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t); +} + +class _ItemBaseModelCopyWithImpl<$R, $Out> + extends ClassCopyWithBase<$R, ItemBaseModel, $Out> + implements ItemBaseModelCopyWith<$R, ItemBaseModel, $Out> { + _ItemBaseModelCopyWithImpl(super.value, super.then, super.then2); + + @override + late final ClassMapperBase $mapper = + ItemBaseModelMapper.ensureInitialized(); + @override + OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview => + $value.overview.copyWith.$chain((v) => call(overview: v)); + @override + UserDataCopyWith<$R, UserData, UserData> get userData => + $value.userData.copyWith.$chain((v) => call(userData: v)); + @override + $R call( + {String? name, + String? id, + OverviewModel? overview, + Object? parentId = $none, + Object? playlistId = $none, + Object? images = $none, + Object? childCount = $none, + Object? primaryRatio = $none, + UserData? userData, + Object? canDownload = $none, + Object? canDelete = $none, + Object? jellyType = $none}) => + $apply(FieldCopyWithData({ + if (name != null) #name: name, + if (id != null) #id: id, + if (overview != null) #overview: overview, + if (parentId != $none) #parentId: parentId, + if (playlistId != $none) #playlistId: playlistId, + if (images != $none) #images: images, + if (childCount != $none) #childCount: childCount, + if (primaryRatio != $none) #primaryRatio: primaryRatio, + if (userData != null) #userData: userData, + if (canDownload != $none) #canDownload: canDownload, + if (canDelete != $none) #canDelete: canDelete, + if (jellyType != $none) #jellyType: jellyType + })); + @override + ItemBaseModel $make(CopyWithData data) => ItemBaseModel( + name: data.get(#name, or: $value.name), + id: data.get(#id, or: $value.id), + overview: data.get(#overview, or: $value.overview), + parentId: data.get(#parentId, or: $value.parentId), + playlistId: data.get(#playlistId, or: $value.playlistId), + images: data.get(#images, or: $value.images), + childCount: data.get(#childCount, or: $value.childCount), + primaryRatio: data.get(#primaryRatio, or: $value.primaryRatio), + userData: data.get(#userData, or: $value.userData), + canDownload: data.get(#canDownload, or: $value.canDownload), + canDelete: data.get(#canDelete, or: $value.canDelete), + jellyType: data.get(#jellyType, or: $value.jellyType)); + + @override + ItemBaseModelCopyWith<$R2, ItemBaseModel, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t) => + _ItemBaseModelCopyWithImpl($value, $cast, t); +} diff --git a/lib/models/item_editing_model.dart b/lib/models/item_editing_model.dart new file mode 100644 index 0000000..2c65493 --- /dev/null +++ b/lib/models/item_editing_model.dart @@ -0,0 +1,318 @@ +import 'dart:typed_data'; + +import 'package:collection/collection.dart'; +import 'package:fladder/models/items/series_model.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart' as jelly; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/providers/image_provider.dart'; + +class EditItemsProvider { + final List serverImages; + final List images; + final List customImages; + final EditingImageModel? selected; + final List selection; + const EditItemsProvider({ + this.serverImages = const [], + this.images = const [], + this.customImages = const [], + this.selected, + this.selection = const [], + }); + + Future setImage( + jelly.ImageType type, { + required Function(EditingImageModel? imageModel) uploadData, + required Function(EditingImageModel? imageModel) uploadUrl, + }) async { + switch (type) { + case jelly.ImageType.primary: + case jelly.ImageType.logo: + { + if (selected == null) return; + if (selected?.imageData != null) { + await uploadData(selected!.copyWith(type: type)); + } else if (selected?.url != null) { + await uploadUrl(selected!.copyWith(type: type)); + } + } + case jelly.ImageType.backdrop: + { + for (var element in selection) { + if (element.imageData != null) { + await uploadData(element.copyWith(type: type)); + } else if (element.url != null) { + await uploadUrl(element.copyWith(type: type)); + } + } + } + default: + } + return; + } + + EditItemsProvider copyWith({ + List? serverImages, + List? images, + List? customImages, + ValueGetter? selected, + List? selection, + }) { + return EditItemsProvider( + serverImages: serverImages ?? this.serverImages, + images: images ?? this.images, + customImages: customImages ?? this.customImages, + selected: selected != null ? selected() : this.selected, + selection: selection ?? this.selection, + ); + } +} + +class ItemEditingModel { + final ItemBaseModel? item; + final jelly.MetadataEditorInfo? editorInfo; + final Map? json; + final Map? editedJson; + final bool includeAllImages; + final EditItemsProvider primary; + final EditItemsProvider logo; + final EditItemsProvider backdrop; + final bool saving; + ItemEditingModel({ + this.item, + this.editorInfo, + this.json, + this.editedJson, + this.includeAllImages = false, + this.primary = const EditItemsProvider(), + this.logo = const EditItemsProvider(), + this.backdrop = const EditItemsProvider(), + this.saving = false, + }); + + Map? editAbleFields() { + return editedJson == null + ? {} + : { + "Name": editedJson?["Name"] as String?, + "OriginalTitle": editedJson?["OriginalTitle"] as String?, + "PremiereDate": editedJson?["PremiereDate"] != null ? DateTime.tryParse(editedJson!["PremiereDate"]) : null, + "DateCreated": editedJson?["DateCreated"] != null ? DateTime.tryParse(editedJson!["DateCreated"]) : null, + "ProductionYear": editedJson?["ProductionYear"] as int?, + "Path": editedJson?["Path"] as String?, + "Overview": editedJson?["Overview"] as String? ?? "", + } + ..removeWhere((key, value) => value == null); + } + + Map? editAdvancedAbleFields(Ref ref) => editedJson == null + ? {} + : { + if (item is SeriesModel) "DisplayOrder": DisplayOrder.fromMap(editedJson?["DisplayOrder"]), + if (item is SeriesModel) ...{ + "OfficialRating": { + for (String element in (editorInfo?.parentalRatingOptions?.map((e) => e.name).toSet() + ?..add(json?["OfficialRating"] as String?)) + ?.whereNotNull() + .toList() ?? + []) + element: (editedJson?["OfficialRating"] as String?) == element + }, + "CustomRating": { + for (String element in (editorInfo?.parentalRatingOptions?.map((e) => e.name).toSet() + ?..add(json?["CustomRating"] as String?)) + ?.whereNotNull() + .toList() ?? + []) + element: (editedJson?["CustomRating"] as String?) == element + }, + }, + "People": editedJson?["People"] != null + ? (editedJson!["People"] as List) + .map((e) => Person.fromBasePerson(jelly.BaseItemPerson.fromJson(e), ref)) + .toList() + : null, + "ExternalUrls": editedJson?["ExternalUrls"] != null + ? (editedJson!["ExternalUrls"] as List).map((e) => ExternalUrls.fromMap(e)).toList() + : null, + "CommunityRating": double.tryParse((editedJson?["CommunityRating"] as num?).toString()), + "SeriesName": editedJson?["SeriesName"] as String?, + "IndexNumber": editedJson?["IndexNumber"] as int?, + "RunTimeTicks": (editedJson?["RunTimeTicks"] == null) + ? null + : Duration(milliseconds: editedJson?["RunTimeTicks"] ~/ 10000), + "ParentIndexNumber": editedJson?["ParentIndexNumber"] as int?, + if (item is SeriesModel) "Status": ShowStatus.fromMap(editedJson?["Status"] as String?), + "Genres": editedJson?["Genres"] != null ? (List.from(editedJson!["Genres"])) : null, + "Tags": editedJson?["Tags"] != null ? (List.from(editedJson?["Tags"])) : null, + "Studios": editedJson?["Studios"] != null + ? (editedJson!["Studios"] as List).map((e) => Studio.fromMap(e)).toList() + : null, + "SeriesStudio": editedJson?["SeriesStudio"] as String?, + "LockData": editedJson?["LockData"] as bool? ?? false, + "LockedFields": ((editedJson?["LockData"] as bool?) == false) + ? EditorLockedFields.enabled(List.from(editedJson?["LockedFields"])) + : null, + } + ..removeWhere((key, value) => value == null); + + ItemEditingModel copyWith({ + ValueGetter? item, + ValueGetter? editorInfo, + ValueGetter?>? json, + ValueGetter?>? editedJson, + bool? includeAllImages, + EditItemsProvider? primary, + EditItemsProvider? logo, + EditItemsProvider? backdrop, + bool? saving, + }) { + return ItemEditingModel( + item: item != null ? item() : this.item, + editorInfo: editorInfo != null ? editorInfo() : this.editorInfo, + json: json != null ? json() : this.json, + editedJson: editedJson != null ? editedJson() : this.editedJson, + includeAllImages: includeAllImages ?? this.includeAllImages, + primary: primary ?? this.primary, + logo: logo ?? this.logo, + backdrop: backdrop ?? this.backdrop, + saving: saving ?? this.saving, + ); + } +} + +class EditingImageModel { + final String providerName; + final String? url; + final Uint8List? imageData; + final int? index; + final int height; + final int width; + final double communityRating; + final int voteCount; + final String language; + final jelly.ImageType type; + final jelly.RatingType ratingType; + EditingImageModel({ + required this.providerName, + this.url, + this.imageData, + this.index, + this.height = 0, + this.width = 0, + this.communityRating = 0.0, + this.voteCount = 0, + this.language = "", + this.type = jelly.ImageType.primary, + this.ratingType = jelly.RatingType.likes, + }); + + double get ratio { + if (width == 0 && height == 0) return 1; + final ratio = (width.toDouble() / height.toDouble()).clamp(0.1, 5).toDouble(); + if (ratio < 0) { + return 1; + } else { + return ratio; + } + } + + factory EditingImageModel.fromDto(jelly.RemoteImageInfo info) { + return EditingImageModel( + providerName: info.providerName ?? "", + url: info.url ?? "", + height: info.height ?? 0, + width: info.width ?? 0, + communityRating: info.communityRating ?? 0.0, + voteCount: info.voteCount ?? 0, + language: info.language ?? "", + type: info.type ?? jelly.ImageType.primary, + ratingType: info.ratingType ?? jelly.RatingType.likes, + ); + } + + factory EditingImageModel.fromImage(jelly.ImageInfo info, String itemId, Ref ref) { + return EditingImageModel( + providerName: "", + url: switch (info.imageType ?? ImageType.primary) { + ImageType.backdrop => ref.read(imageUtilityProvider).getBackdropOrigImage( + itemId, + info.imageIndex ?? 0, + info.hashCode.toString(), + ), + _ => ref.read(imageUtilityProvider).getItemsOrigImageUrl( + itemId, + type: info.imageType ?? ImageType.primary, + ), + }, + index: info.imageIndex, + height: info.height ?? 0, + width: info.width ?? 0, + type: info.imageType ?? ImageType.primary, + ); + } + + EditingImageModel copyWith({ + String? providerName, + ValueGetter? url, + ValueGetter? imageData, + ValueGetter? index, + int? height, + int? width, + double? communityRating, + int? voteCount, + String? language, + jelly.ImageType? type, + jelly.RatingType? ratingType, + }) { + return EditingImageModel( + providerName: providerName ?? this.providerName, + url: url != null ? url() : this.url, + imageData: imageData != null ? imageData() : this.imageData, + index: index != null ? index() : this.index, + height: height ?? this.height, + width: width ?? this.width, + communityRating: communityRating ?? this.communityRating, + voteCount: voteCount ?? this.voteCount, + language: language ?? this.language, + type: type ?? this.type, + ratingType: ratingType ?? this.ratingType, + ); + } + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + + return other is EditingImageModel && + other.providerName == providerName && + other.url == url && + other.imageData == imageData && + other.height == height && + other.width == width && + other.communityRating == communityRating && + other.voteCount == voteCount && + other.language == language && + other.type == type && + other.ratingType == ratingType; + } + + @override + int get hashCode { + return providerName.hashCode ^ + url.hashCode ^ + imageData.hashCode ^ + height.hashCode ^ + width.hashCode ^ + communityRating.hashCode ^ + voteCount.hashCode ^ + language.hashCode ^ + type.hashCode ^ + ratingType.hashCode; + } +} diff --git a/lib/models/items/chapters_model.dart b/lib/models/items/chapters_model.dart new file mode 100644 index 0000000..e5fce5c --- /dev/null +++ b/lib/models/items/chapters_model.dart @@ -0,0 +1,90 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:collection/collection.dart'; +import 'package:fladder/main.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart' as dto; +import 'package:fladder/providers/image_provider.dart'; + +class Chapter { + final String name; + final String imageUrl; + final Uint8List? imageData; + final Duration startPosition; + Chapter({ + required this.name, + required this.imageUrl, + this.imageData, + required this.startPosition, + }); + + ImageProvider get imageProvider { + if (imageData != null) { + return Image.memory(imageData!).image; + } + if (imageUrl.startsWith("http")) { + return CachedNetworkImageProvider( + cacheKey: name + imageUrl, + cacheManager: CustomCacheManager.instance, + imageUrl, + ); + } else { + return Image.file( + key: Key(name + imageUrl), + File(imageUrl), + ).image; + } + } + + static List chaptersFromInfo(String itemId, List chapters, Ref ref) { + return chapters + .mapIndexed((index, element) => Chapter( + name: element.name ?? "", + imageUrl: ref.read(imageUtilityProvider).getChapterUrl(itemId, index), + startPosition: Duration(milliseconds: (element.startPositionTicks ?? 0) ~/ 10000))) + .toList(); + } + + Chapter copyWith({ + String? name, + String? imageUrl, + Duration? startPosition, + }) { + return Chapter( + name: name ?? this.name, + imageUrl: imageUrl ?? this.imageUrl, + startPosition: startPosition ?? this.startPosition, + ); + } + + Map toMap() { + return { + 'name': name, + 'imageUrl': imageUrl, + 'startPosition': startPosition.inMilliseconds, + }; + } + + factory Chapter.fromMap(Map map) { + return Chapter( + name: map['name'] ?? '', + imageUrl: map['imageUrl'] ?? '', + startPosition: Duration(milliseconds: map['startPosition'] as int), + ); + } + + String toJson() => json.encode(toMap()); + + factory Chapter.fromJson(String source) => Chapter.fromMap(json.decode(source)); +} + +extension ChapterExtension on List { + Chapter? getChapterFromDuration(Duration duration) { + return lastWhereOrNull((element) => element.startPosition < duration); + } +} diff --git a/lib/models/items/episode_model.dart b/lib/models/items/episode_model.dart new file mode 100644 index 0000000..bc40726 --- /dev/null +++ b/lib/models/items/episode_model.dart @@ -0,0 +1,201 @@ +import 'package:collection/collection.dart'; +import 'package:fladder/jellyfin/enum_models.dart'; +import 'package:fladder/models/items/series_model.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/string_extensions.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart' as dto; +import 'package:fladder/models/items/chapters_model.dart'; +import 'package:fladder/models/items/images_models.dart'; +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/models/items/item_stream_model.dart'; +import 'package:fladder/models/items/media_streams_model.dart'; +import 'package:fladder/models/items/overview_model.dart'; +import 'package:dart_mappable/dart_mappable.dart'; + +part 'episode_model.mapper.dart'; + +enum EpisodeStatus { available, unaired, missing } + +@MappableClass() +class EpisodeModel extends ItemStreamModel with EpisodeModelMappable { + final String? seriesName; + final int season; + final int episode; + final List chapters; + final ItemLocation? location; + final DateTime? dateAired; + const EpisodeModel({ + required this.seriesName, + required this.season, + required this.episode, + this.chapters = const [], + this.location, + this.dateAired, + required super.name, + required super.id, + required super.overview, + required super.parentId, + required super.playlistId, + required super.images, + required super.childCount, + required super.primaryRatio, + required super.userData, + required super.parentImages, + required super.mediaStreams, + super.canDelete, + super.canDownload, + super.jellyType, + }); + EpisodeStatus get status { + return switch (location) { + ItemLocation.filesystem => EpisodeStatus.available, + ItemLocation.virtual => + (dateAired?.isBefore(DateTime.now()) == true) ? EpisodeStatus.missing : EpisodeStatus.unaired, + _ => EpisodeStatus.missing + }; + } + + @override + String? detailedName(BuildContext context) => "${subTextShort(context)} - $name"; + + @override + SeriesModel get parentBaseModel => SeriesModel( + originalTitle: '', + sortName: '', + status: "", + name: seriesName ?? "", + id: parentId ?? "", + playlistId: playlistId, + overview: overview, + parentId: parentId, + images: images, + childCount: childCount, + primaryRatio: primaryRatio, + userData: UserData(), + ); + + @override + String get streamId => parentId ?? ""; + + @override + String get title => seriesName ?? name; + + @override + MediaStreamsModel? get streamModel => mediaStreams; + + @override + ImagesData? get getPosters => parentImages; + + @override + String? get subText => name.isEmpty ? "TBA" : name; + + @override + String? subTextShort(BuildContext context) => seasonEpisodeLabel(context); + + @override + String? label(BuildContext context) => "${subTextShort(context)} - $name"; + + @override + bool get playAble => switch (status) { + EpisodeStatus.available => true, + _ => false, + }; + + @override + String playButtonLabel(BuildContext context) { + final string = seasonEpisodeLabel(context).maxLength(); + return progress != 0 ? context.localized.resume(string) : context.localized.play(string); + } + + String seasonAnnotation(BuildContext context) => context.localized.season(1)[0]; + String episodeAnnotation(BuildContext context) => context.localized.episode(1)[0]; + + String seasonEpisodeLabel(BuildContext context) { + return "${seasonAnnotation(context)}$season - ${episodeAnnotation(context)}$episode"; + } + + String seasonEpisodeLabelFull(BuildContext context) { + return "${context.localized.season(1)} $season - ${context.localized.episode(1)} $episode"; + } + + String episodeLabel(BuildContext context) { + return "${seasonEpisodeLabel(context)} - $subText"; + } + + String get fullName { + return "$episode. $subText"; + } + + @override + bool get syncAble => playAble; + + @override + factory EpisodeModel.fromBaseDto(dto.BaseItemDto item, Ref ref) => EpisodeModel( + seriesName: item.seriesName, + name: item.name ?? "", + id: item.id ?? "", + childCount: item.childCount, + overview: OverviewModel.fromBaseItemDto(item, ref), + userData: UserData.fromDto(item.userData), + parentId: item.seriesId, + playlistId: item.playlistItemId, + dateAired: item.premiereDate, + chapters: Chapter.chaptersFromInfo(item.id ?? "", item.chapters ?? [], ref), + images: ImagesData.fromBaseItem(item, ref, getOriginalSize: true), + primaryRatio: item.primaryImageAspectRatio, + season: item.parentIndexNumber ?? 0, + episode: item.indexNumber ?? 0, + location: ItemLocation.fromDto(item.locationType), + parentImages: ImagesData.fromBaseItemParent(item, ref), + canDelete: item.canDelete, + canDownload: item.canDownload, + mediaStreams: + MediaStreamsModel.fromMediaStreamsList(item.mediaSources?.firstOrNull, item.mediaStreams ?? [], ref), + jellyType: item.type, + ); + + static List episodesFromDto(List? dto, Ref ref) { + return dto?.map((e) => EpisodeModel.fromBaseDto(e, ref)).toList() ?? []; + } +} + +extension EpisodeListExtensions on List { + Map> get episodesBySeason { + Map> groupedItems = {}; + for (int i = 0; i < length; i++) { + int seasonIndex = this[i].season; + if (!groupedItems.containsKey(seasonIndex)) { + groupedItems[seasonIndex] = [this[i]]; + } else { + groupedItems[seasonIndex]?.add(this[i]); + } + } + return groupedItems; + } + + EpisodeModel? get nextUp { + final lastProgress = + lastIndexWhere((element) => element.userData.progress != 0 && element.status == EpisodeStatus.available); + final lastPlayed = + lastIndexWhere((element) => element.userData.played && element.status == EpisodeStatus.available); + + if (lastProgress == -1 && lastPlayed == -1) { + return firstWhereOrNull((element) => element.status == EpisodeStatus.available); + } else { + return getRange(lastProgress > lastPlayed ? lastProgress : lastPlayed + 1, length) + .firstWhereOrNull((element) => element.status == EpisodeStatus.available); + } + } + + bool get allPlayed { + for (var element in this) { + if (!element.userData.played) { + return false; + } + } + return true; + } +} diff --git a/lib/models/items/episode_model.mapper.dart b/lib/models/items/episode_model.mapper.dart new file mode 100644 index 0000000..bebdd8e --- /dev/null +++ b/lib/models/items/episode_model.mapper.dart @@ -0,0 +1,301 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member +// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter + +part of 'episode_model.dart'; + +class EpisodeModelMapper extends SubClassMapperBase { + EpisodeModelMapper._(); + + static EpisodeModelMapper? _instance; + static EpisodeModelMapper ensureInitialized() { + if (_instance == null) { + MapperContainer.globals.use(_instance = EpisodeModelMapper._()); + ItemStreamModelMapper.ensureInitialized().addSubMapper(_instance!); + OverviewModelMapper.ensureInitialized(); + UserDataMapper.ensureInitialized(); + } + return _instance!; + } + + @override + final String id = 'EpisodeModel'; + + static String? _$seriesName(EpisodeModel v) => v.seriesName; + static const Field _f$seriesName = + Field('seriesName', _$seriesName); + static int _$season(EpisodeModel v) => v.season; + static const Field _f$season = Field('season', _$season); + static int _$episode(EpisodeModel v) => v.episode; + static const Field _f$episode = + Field('episode', _$episode); + static List _$chapters(EpisodeModel v) => v.chapters; + static const Field> _f$chapters = + Field('chapters', _$chapters, opt: true, def: const []); + static ItemLocation? _$location(EpisodeModel v) => v.location; + static const Field _f$location = + Field('location', _$location, opt: true); + static DateTime? _$dateAired(EpisodeModel v) => v.dateAired; + static const Field _f$dateAired = + Field('dateAired', _$dateAired, opt: true); + static String _$name(EpisodeModel v) => v.name; + static const Field _f$name = Field('name', _$name); + static String _$id(EpisodeModel v) => v.id; + static const Field _f$id = Field('id', _$id); + static OverviewModel _$overview(EpisodeModel v) => v.overview; + static const Field _f$overview = + Field('overview', _$overview); + static String? _$parentId(EpisodeModel v) => v.parentId; + static const Field _f$parentId = + Field('parentId', _$parentId); + static String? _$playlistId(EpisodeModel v) => v.playlistId; + static const Field _f$playlistId = + Field('playlistId', _$playlistId); + static ImagesData? _$images(EpisodeModel v) => v.images; + static const Field _f$images = + Field('images', _$images); + static int? _$childCount(EpisodeModel v) => v.childCount; + static const Field _f$childCount = + Field('childCount', _$childCount); + static double? _$primaryRatio(EpisodeModel v) => v.primaryRatio; + static const Field _f$primaryRatio = + Field('primaryRatio', _$primaryRatio); + static UserData _$userData(EpisodeModel v) => v.userData; + static const Field _f$userData = + Field('userData', _$userData); + static ImagesData? _$parentImages(EpisodeModel v) => v.parentImages; + static const Field _f$parentImages = + Field('parentImages', _$parentImages); + static MediaStreamsModel _$mediaStreams(EpisodeModel v) => v.mediaStreams; + static const Field _f$mediaStreams = + Field('mediaStreams', _$mediaStreams); + static bool? _$canDelete(EpisodeModel v) => v.canDelete; + static const Field _f$canDelete = + Field('canDelete', _$canDelete, opt: true); + static bool? _$canDownload(EpisodeModel v) => v.canDownload; + static const Field _f$canDownload = + Field('canDownload', _$canDownload, opt: true); + static dto.BaseItemKind? _$jellyType(EpisodeModel v) => v.jellyType; + static const Field _f$jellyType = + Field('jellyType', _$jellyType, opt: true); + + @override + final MappableFields fields = const { + #seriesName: _f$seriesName, + #season: _f$season, + #episode: _f$episode, + #chapters: _f$chapters, + #location: _f$location, + #dateAired: _f$dateAired, + #name: _f$name, + #id: _f$id, + #overview: _f$overview, + #parentId: _f$parentId, + #playlistId: _f$playlistId, + #images: _f$images, + #childCount: _f$childCount, + #primaryRatio: _f$primaryRatio, + #userData: _f$userData, + #parentImages: _f$parentImages, + #mediaStreams: _f$mediaStreams, + #canDelete: _f$canDelete, + #canDownload: _f$canDownload, + #jellyType: _f$jellyType, + }; + @override + final bool ignoreNull = true; + + @override + final String discriminatorKey = 'type'; + @override + final dynamic discriminatorValue = 'EpisodeModel'; + @override + late final ClassMapperBase superMapper = + ItemStreamModelMapper.ensureInitialized(); + + static EpisodeModel _instantiate(DecodingData data) { + return EpisodeModel( + seriesName: data.dec(_f$seriesName), + season: data.dec(_f$season), + episode: data.dec(_f$episode), + chapters: data.dec(_f$chapters), + location: data.dec(_f$location), + dateAired: data.dec(_f$dateAired), + name: data.dec(_f$name), + id: data.dec(_f$id), + overview: data.dec(_f$overview), + parentId: data.dec(_f$parentId), + playlistId: data.dec(_f$playlistId), + images: data.dec(_f$images), + childCount: data.dec(_f$childCount), + primaryRatio: data.dec(_f$primaryRatio), + userData: data.dec(_f$userData), + parentImages: data.dec(_f$parentImages), + mediaStreams: data.dec(_f$mediaStreams), + canDelete: data.dec(_f$canDelete), + canDownload: data.dec(_f$canDownload), + jellyType: data.dec(_f$jellyType)); + } + + @override + final Function instantiate = _instantiate; + + static EpisodeModel fromMap(Map map) { + return ensureInitialized().decodeMap(map); + } + + static EpisodeModel fromJson(String json) { + return ensureInitialized().decodeJson(json); + } +} + +mixin EpisodeModelMappable { + String toJson() { + return EpisodeModelMapper.ensureInitialized() + .encodeJson(this as EpisodeModel); + } + + Map toMap() { + return EpisodeModelMapper.ensureInitialized() + .encodeMap(this as EpisodeModel); + } + + EpisodeModelCopyWith get copyWith => + _EpisodeModelCopyWithImpl(this as EpisodeModel, $identity, $identity); + @override + String toString() { + return EpisodeModelMapper.ensureInitialized() + .stringifyValue(this as EpisodeModel); + } +} + +extension EpisodeModelValueCopy<$R, $Out> + on ObjectCopyWith<$R, EpisodeModel, $Out> { + EpisodeModelCopyWith<$R, EpisodeModel, $Out> get $asEpisodeModel => + $base.as((v, t, t2) => _EpisodeModelCopyWithImpl(v, t, t2)); +} + +abstract class EpisodeModelCopyWith<$R, $In extends EpisodeModel, $Out> + implements ItemStreamModelCopyWith<$R, $In, $Out> { + ListCopyWith<$R, Chapter, ObjectCopyWith<$R, Chapter, Chapter>> get chapters; + @override + OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview; + @override + UserDataCopyWith<$R, UserData, UserData> get userData; + @override + $R call( + {String? seriesName, + int? season, + int? episode, + List? chapters, + ItemLocation? location, + DateTime? dateAired, + String? name, + String? id, + OverviewModel? overview, + String? parentId, + String? playlistId, + ImagesData? images, + int? childCount, + double? primaryRatio, + UserData? userData, + ImagesData? parentImages, + MediaStreamsModel? mediaStreams, + bool? canDelete, + bool? canDownload, + dto.BaseItemKind? jellyType}); + EpisodeModelCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t); +} + +class _EpisodeModelCopyWithImpl<$R, $Out> + extends ClassCopyWithBase<$R, EpisodeModel, $Out> + implements EpisodeModelCopyWith<$R, EpisodeModel, $Out> { + _EpisodeModelCopyWithImpl(super.value, super.then, super.then2); + + @override + late final ClassMapperBase $mapper = + EpisodeModelMapper.ensureInitialized(); + @override + ListCopyWith<$R, Chapter, ObjectCopyWith<$R, Chapter, Chapter>> + get chapters => ListCopyWith($value.chapters, + (v, t) => ObjectCopyWith(v, $identity, t), (v) => call(chapters: v)); + @override + OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview => + $value.overview.copyWith.$chain((v) => call(overview: v)); + @override + UserDataCopyWith<$R, UserData, UserData> get userData => + $value.userData.copyWith.$chain((v) => call(userData: v)); + @override + $R call( + {Object? seriesName = $none, + int? season, + int? episode, + List? chapters, + Object? location = $none, + Object? dateAired = $none, + String? name, + String? id, + OverviewModel? overview, + Object? parentId = $none, + Object? playlistId = $none, + Object? images = $none, + Object? childCount = $none, + Object? primaryRatio = $none, + UserData? userData, + Object? parentImages = $none, + MediaStreamsModel? mediaStreams, + Object? canDelete = $none, + Object? canDownload = $none, + Object? jellyType = $none}) => + $apply(FieldCopyWithData({ + if (seriesName != $none) #seriesName: seriesName, + if (season != null) #season: season, + if (episode != null) #episode: episode, + if (chapters != null) #chapters: chapters, + if (location != $none) #location: location, + if (dateAired != $none) #dateAired: dateAired, + if (name != null) #name: name, + if (id != null) #id: id, + if (overview != null) #overview: overview, + if (parentId != $none) #parentId: parentId, + if (playlistId != $none) #playlistId: playlistId, + if (images != $none) #images: images, + if (childCount != $none) #childCount: childCount, + if (primaryRatio != $none) #primaryRatio: primaryRatio, + if (userData != null) #userData: userData, + if (parentImages != $none) #parentImages: parentImages, + if (mediaStreams != null) #mediaStreams: mediaStreams, + if (canDelete != $none) #canDelete: canDelete, + if (canDownload != $none) #canDownload: canDownload, + if (jellyType != $none) #jellyType: jellyType + })); + @override + EpisodeModel $make(CopyWithData data) => EpisodeModel( + seriesName: data.get(#seriesName, or: $value.seriesName), + season: data.get(#season, or: $value.season), + episode: data.get(#episode, or: $value.episode), + chapters: data.get(#chapters, or: $value.chapters), + location: data.get(#location, or: $value.location), + dateAired: data.get(#dateAired, or: $value.dateAired), + name: data.get(#name, or: $value.name), + id: data.get(#id, or: $value.id), + overview: data.get(#overview, or: $value.overview), + parentId: data.get(#parentId, or: $value.parentId), + playlistId: data.get(#playlistId, or: $value.playlistId), + images: data.get(#images, or: $value.images), + childCount: data.get(#childCount, or: $value.childCount), + primaryRatio: data.get(#primaryRatio, or: $value.primaryRatio), + userData: data.get(#userData, or: $value.userData), + parentImages: data.get(#parentImages, or: $value.parentImages), + mediaStreams: data.get(#mediaStreams, or: $value.mediaStreams), + canDelete: data.get(#canDelete, or: $value.canDelete), + canDownload: data.get(#canDownload, or: $value.canDownload), + jellyType: data.get(#jellyType, or: $value.jellyType)); + + @override + EpisodeModelCopyWith<$R2, EpisodeModel, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t) => + _EpisodeModelCopyWithImpl($value, $cast, t); +} diff --git a/lib/models/items/folder_model.dart b/lib/models/items/folder_model.dart new file mode 100644 index 0000000..212a8d2 --- /dev/null +++ b/lib/models/items/folder_model.dart @@ -0,0 +1,50 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/images_models.dart'; +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/models/items/overview_model.dart'; + +import 'package:dart_mappable/dart_mappable.dart'; + +part 'folder_model.mapper.dart'; + +@MappableClass() +class FolderModel extends ItemBaseModel with FolderModelMappable { + final List items; + + const FolderModel({ + required this.items, + required super.overview, + required super.parentId, + required super.playlistId, + required super.images, + required super.childCount, + required super.primaryRatio, + required super.userData, + required super.name, + required super.id, + super.canDownload, + super.canDelete, + super.jellyType, + }); + + factory FolderModel.fromBaseDto(BaseItemDto item, Ref ref) { + return FolderModel( + name: item.name ?? "", + id: item.id ?? "", + childCount: item.childCount, + overview: OverviewModel.fromBaseItemDto(item, ref), + userData: UserData.fromDto(item.userData), + parentId: item.parentId, + playlistId: item.playlistItemId, + images: ImagesData.fromBaseItem(item, ref), + primaryRatio: item.primaryImageAspectRatio, + items: [], + canDelete: item.canDelete, + canDownload: item.canDownload, + ); + } +} diff --git a/lib/models/items/folder_model.mapper.dart b/lib/models/items/folder_model.mapper.dart new file mode 100644 index 0000000..f36f7fd --- /dev/null +++ b/lib/models/items/folder_model.mapper.dart @@ -0,0 +1,242 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member +// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter + +part of 'folder_model.dart'; + +class FolderModelMapper extends SubClassMapperBase { + FolderModelMapper._(); + + static FolderModelMapper? _instance; + static FolderModelMapper ensureInitialized() { + if (_instance == null) { + MapperContainer.globals.use(_instance = FolderModelMapper._()); + ItemBaseModelMapper.ensureInitialized().addSubMapper(_instance!); + ItemBaseModelMapper.ensureInitialized(); + OverviewModelMapper.ensureInitialized(); + UserDataMapper.ensureInitialized(); + } + return _instance!; + } + + @override + final String id = 'FolderModel'; + + static List _$items(FolderModel v) => v.items; + static const Field> _f$items = + Field('items', _$items); + static OverviewModel _$overview(FolderModel v) => v.overview; + static const Field _f$overview = + Field('overview', _$overview); + static String? _$parentId(FolderModel v) => v.parentId; + static const Field _f$parentId = + Field('parentId', _$parentId); + static String? _$playlistId(FolderModel v) => v.playlistId; + static const Field _f$playlistId = + Field('playlistId', _$playlistId); + static ImagesData? _$images(FolderModel v) => v.images; + static const Field _f$images = + Field('images', _$images); + static int? _$childCount(FolderModel v) => v.childCount; + static const Field _f$childCount = + Field('childCount', _$childCount); + static double? _$primaryRatio(FolderModel v) => v.primaryRatio; + static const Field _f$primaryRatio = + Field('primaryRatio', _$primaryRatio); + static UserData _$userData(FolderModel v) => v.userData; + static const Field _f$userData = + Field('userData', _$userData); + static String _$name(FolderModel v) => v.name; + static const Field _f$name = Field('name', _$name); + static String _$id(FolderModel v) => v.id; + static const Field _f$id = Field('id', _$id); + static bool? _$canDownload(FolderModel v) => v.canDownload; + static const Field _f$canDownload = + Field('canDownload', _$canDownload, opt: true); + static bool? _$canDelete(FolderModel v) => v.canDelete; + static const Field _f$canDelete = + Field('canDelete', _$canDelete, opt: true); + static BaseItemKind? _$jellyType(FolderModel v) => v.jellyType; + static const Field _f$jellyType = + Field('jellyType', _$jellyType, opt: true); + + @override + final MappableFields fields = const { + #items: _f$items, + #overview: _f$overview, + #parentId: _f$parentId, + #playlistId: _f$playlistId, + #images: _f$images, + #childCount: _f$childCount, + #primaryRatio: _f$primaryRatio, + #userData: _f$userData, + #name: _f$name, + #id: _f$id, + #canDownload: _f$canDownload, + #canDelete: _f$canDelete, + #jellyType: _f$jellyType, + }; + @override + final bool ignoreNull = true; + + @override + final String discriminatorKey = 'type'; + @override + final dynamic discriminatorValue = 'FolderModel'; + @override + late final ClassMapperBase superMapper = + ItemBaseModelMapper.ensureInitialized(); + + static FolderModel _instantiate(DecodingData data) { + return FolderModel( + items: data.dec(_f$items), + overview: data.dec(_f$overview), + parentId: data.dec(_f$parentId), + playlistId: data.dec(_f$playlistId), + images: data.dec(_f$images), + childCount: data.dec(_f$childCount), + primaryRatio: data.dec(_f$primaryRatio), + userData: data.dec(_f$userData), + name: data.dec(_f$name), + id: data.dec(_f$id), + canDownload: data.dec(_f$canDownload), + canDelete: data.dec(_f$canDelete), + jellyType: data.dec(_f$jellyType)); + } + + @override + final Function instantiate = _instantiate; + + static FolderModel fromMap(Map map) { + return ensureInitialized().decodeMap(map); + } + + static FolderModel fromJson(String json) { + return ensureInitialized().decodeJson(json); + } +} + +mixin FolderModelMappable { + String toJson() { + return FolderModelMapper.ensureInitialized() + .encodeJson(this as FolderModel); + } + + Map toMap() { + return FolderModelMapper.ensureInitialized() + .encodeMap(this as FolderModel); + } + + FolderModelCopyWith get copyWith => + _FolderModelCopyWithImpl(this as FolderModel, $identity, $identity); + @override + String toString() { + return FolderModelMapper.ensureInitialized() + .stringifyValue(this as FolderModel); + } +} + +extension FolderModelValueCopy<$R, $Out> + on ObjectCopyWith<$R, FolderModel, $Out> { + FolderModelCopyWith<$R, FolderModel, $Out> get $asFolderModel => + $base.as((v, t, t2) => _FolderModelCopyWithImpl(v, t, t2)); +} + +abstract class FolderModelCopyWith<$R, $In extends FolderModel, $Out> + implements ItemBaseModelCopyWith<$R, $In, $Out> { + ListCopyWith<$R, ItemBaseModel, + ItemBaseModelCopyWith<$R, ItemBaseModel, ItemBaseModel>> get items; + @override + OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview; + @override + UserDataCopyWith<$R, UserData, UserData> get userData; + @override + $R call( + {List? items, + OverviewModel? overview, + String? parentId, + String? playlistId, + ImagesData? images, + int? childCount, + double? primaryRatio, + UserData? userData, + String? name, + String? id, + bool? canDownload, + bool? canDelete, + BaseItemKind? jellyType}); + FolderModelCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t); +} + +class _FolderModelCopyWithImpl<$R, $Out> + extends ClassCopyWithBase<$R, FolderModel, $Out> + implements FolderModelCopyWith<$R, FolderModel, $Out> { + _FolderModelCopyWithImpl(super.value, super.then, super.then2); + + @override + late final ClassMapperBase $mapper = + FolderModelMapper.ensureInitialized(); + @override + ListCopyWith<$R, ItemBaseModel, + ItemBaseModelCopyWith<$R, ItemBaseModel, ItemBaseModel>> + get items => ListCopyWith( + $value.items, (v, t) => v.copyWith.$chain(t), (v) => call(items: v)); + @override + OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview => + $value.overview.copyWith.$chain((v) => call(overview: v)); + @override + UserDataCopyWith<$R, UserData, UserData> get userData => + $value.userData.copyWith.$chain((v) => call(userData: v)); + @override + $R call( + {List? items, + OverviewModel? overview, + Object? parentId = $none, + Object? playlistId = $none, + Object? images = $none, + Object? childCount = $none, + Object? primaryRatio = $none, + UserData? userData, + String? name, + String? id, + Object? canDownload = $none, + Object? canDelete = $none, + Object? jellyType = $none}) => + $apply(FieldCopyWithData({ + if (items != null) #items: items, + if (overview != null) #overview: overview, + if (parentId != $none) #parentId: parentId, + if (playlistId != $none) #playlistId: playlistId, + if (images != $none) #images: images, + if (childCount != $none) #childCount: childCount, + if (primaryRatio != $none) #primaryRatio: primaryRatio, + if (userData != null) #userData: userData, + if (name != null) #name: name, + if (id != null) #id: id, + if (canDownload != $none) #canDownload: canDownload, + if (canDelete != $none) #canDelete: canDelete, + if (jellyType != $none) #jellyType: jellyType + })); + @override + FolderModel $make(CopyWithData data) => FolderModel( + items: data.get(#items, or: $value.items), + overview: data.get(#overview, or: $value.overview), + parentId: data.get(#parentId, or: $value.parentId), + playlistId: data.get(#playlistId, or: $value.playlistId), + images: data.get(#images, or: $value.images), + childCount: data.get(#childCount, or: $value.childCount), + primaryRatio: data.get(#primaryRatio, or: $value.primaryRatio), + userData: data.get(#userData, or: $value.userData), + name: data.get(#name, or: $value.name), + id: data.get(#id, or: $value.id), + canDownload: data.get(#canDownload, or: $value.canDownload), + canDelete: data.get(#canDelete, or: $value.canDelete), + jellyType: data.get(#jellyType, or: $value.jellyType)); + + @override + FolderModelCopyWith<$R2, FolderModel, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t) => + _FolderModelCopyWithImpl($value, $cast, t); +} diff --git a/lib/models/items/images_models.dart b/lib/models/items/images_models.dart new file mode 100644 index 0000000..a6ec90e --- /dev/null +++ b/lib/models/items/images_models.dart @@ -0,0 +1,286 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:collection/collection.dart'; +import 'package:fladder/main.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.dart' as enums; +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart' as dto; +import 'package:fladder/providers/image_provider.dart'; +import 'package:fladder/util/jelly_id.dart'; + +class ImagesData { + final ImageData? primary; + final List? backDrop; + final ImageData? logo; + ImagesData({ + this.primary, + this.backDrop, + this.logo, + }); + + bool get isEmpty { + if (primary == null && backDrop == null) return true; + return false; + } + + ImageData? get firstOrNull { + return primary ?? backDrop?[0]; + } + + ImageData? get randomBackDrop => (backDrop?..shuffle())?.firstOrNull ?? primary; + + factory ImagesData.fromBaseItem( + dto.BaseItemDto item, + Ref ref, { + Size backDrop = const Size(2000, 2000), + Size logo = const Size(1000, 1000), + Size primary = const Size(600, 600), + bool getOriginalSize = false, + int quality = 90, + }) { + final newImgesData = ImagesData( + primary: item.imageTags?['Primary'] != null + ? ImageData( + path: getOriginalSize + ? ref.read(imageUtilityProvider).getItemsOrigImageUrl( + item.id!, + type: enums.ImageType.primary, + ) + : ref.read(imageUtilityProvider).getItemsImageUrl( + (item.id!), + type: enums.ImageType.primary, + maxHeight: primary.height.toInt(), + maxWidth: primary.width.toInt(), + quality: quality, + ), + key: item.imageTags?['Primary'], + hash: item.imageBlurHashes?.primary?[item.imageTags?['Primary']] as String? ?? "", + ) + : null, + logo: item.imageTags?['Logo'] != null + ? ImageData( + path: getOriginalSize + ? ref.read(imageUtilityProvider).getItemsOrigImageUrl( + item.id!, + type: enums.ImageType.logo, + ) + : ref.read(imageUtilityProvider).getItemsImageUrl( + (item.id!), + type: enums.ImageType.logo, + maxHeight: logo.height.toInt(), + maxWidth: logo.width.toInt(), + quality: quality, + ), + key: item.imageTags?['Logo'], + hash: item.imageBlurHashes?.logo?[item.imageTags?['Logo']] as String? ?? "") + : null, + backDrop: (item.backdropImageTags ?? []).mapIndexed( + (index, backdrop) { + final image = ImageData( + path: getOriginalSize + ? ref.read(imageUtilityProvider).getBackdropOrigImage( + item.id!, + index, + backdrop, + ) + : ref.read(imageUtilityProvider).getBackdropImage( + (item.id!), + index, + backdrop, + maxHeight: backDrop.height.toInt(), + maxWidth: backDrop.width.toInt(), + quality: quality, + ), + key: backdrop, + hash: item.imageBlurHashes?.backdrop?[backdrop] ?? jellyId, + ); + return image; + }, + ).toList(), + ); + return newImgesData; + } + + static ImagesData? fromBaseItemParent( + dto.BaseItemDto item, + Ref ref, { + Size backDrop = const Size(2000, 2000), + Size logo = const Size(1000, 1000), + Size primary = const Size(600, 600), + int quality = 90, + }) { + if (item.seriesId == null && item.parentId == null) return null; + final newImgesData = ImagesData( + primary: (item.seriesPrimaryImageTag != null) + ? ImageData( + path: ref.read(imageUtilityProvider).getItemsImageUrl( + (item.seriesId!), + type: enums.ImageType.primary, + maxHeight: primary.height.toInt(), + maxWidth: primary.width.toInt(), + quality: quality, + ), + key: item.seriesPrimaryImageTag ?? "", + hash: item.imageBlurHashes?.primary?[item.seriesPrimaryImageTag] as String? ?? "") + : null, + logo: (item.parentLogoImageTag != null) + ? ImageData( + path: ref.read(imageUtilityProvider).getItemsImageUrl( + (item.seriesId!), + type: enums.ImageType.logo, + maxHeight: logo.height.toInt(), + maxWidth: logo.width.toInt(), + quality: quality, + ), + key: item.parentLogoImageTag ?? "", + hash: item.imageBlurHashes?.logo?[item.parentLogoImageTag] as String? ?? "") + : null, + backDrop: (item.backdropImageTags ?? []).mapIndexed( + (index, backdrop) { + final image = ImageData( + path: ref.read(imageUtilityProvider).getBackdropImage( + ((item.seriesId ?? item.parentId)!), + index, + backdrop, + maxHeight: backDrop.height.toInt(), + maxWidth: backDrop.width.toInt(), + quality: quality, + ), + key: backdrop, + hash: item.imageBlurHashes?.backdrop?[backdrop], + ); + return image; + }, + ).toList(), + ); + return newImgesData; + } + + static ImagesData? fromPersonDto( + dto.BaseItemPerson item, + Ref ref, { + Size backDrop = const Size(2000, 2000), + Size logo = const Size(1000, 1000), + Size primary = const Size(2000, 2000), + int quality = 90, + }) { + return ImagesData( + primary: (item.primaryImageTag != null && item.imageBlurHashes != null) + ? ImageData( + path: ref.read(imageUtilityProvider).getItemsImageUrl( + item.id ?? "", + type: enums.ImageType.primary, + maxHeight: primary.height.toInt(), + maxWidth: primary.width.toInt(), + quality: quality, + ), + key: item.primaryImageTag ?? "", + hash: item.imageBlurHashes?.primary?[item.primaryImageTag] as String? ?? jellyId) + : null, + logo: null, + backDrop: null, + ); + } + + @override + String toString() => 'ImagesData(primary: $primary, backDrop: $backDrop, logo: $logo)'; + + ImagesData copyWith({ + ValueGetter? primary, + ValueGetter?>? backDrop, + ValueGetter? logo, + }) { + return ImagesData( + primary: primary != null ? primary() : this.primary, + backDrop: backDrop != null ? backDrop() : this.backDrop, + logo: logo != null ? logo() : this.logo, + ); + } + + Map toMap() { + return { + 'primary': primary?.toMap(), + 'backDrop': backDrop?.map((x) => x.toMap()).toList(), + 'logo': logo?.toMap(), + }; + } + + factory ImagesData.fromMap(Map map) { + return ImagesData( + primary: map['primary'] != null ? ImageData.fromMap(map['primary']) : null, + backDrop: + map['backDrop'] != null ? List.from(map['backDrop']?.map((x) => ImageData.fromMap(x))) : null, + logo: map['logo'] != null ? ImageData.fromMap(map['logo']) : null, + ); + } + + String toJson() => json.encode(toMap()); + + factory ImagesData.fromJson(String source) => ImagesData.fromMap(json.decode(source)); +} + +class ImageData { + final String path; + final String hash; + final String key; + ImageData({ + this.path = '', + this.hash = '', + this.key = '', + }); + + ImageProvider get imageProvider { + if (path.startsWith("http")) { + return CachedNetworkImageProvider( + cacheKey: key, + cacheManager: CustomCacheManager.instance, + path, + ); + } else { + return Image.file( + key: Key(key), + File(path), + ).image; + } + } + + @override + String toString() => 'ImageData(path: $path, hash: $hash, key: $key)'; + + ImageData copyWith({ + String? path, + String? hash, + String? key, + }) { + return ImageData( + path: path ?? this.path, + hash: hash ?? this.hash, + key: key ?? this.key, + ); + } + + Map toMap() { + return { + 'path': path, + 'hash': hash, + 'key': key, + }; + } + + factory ImageData.fromMap(Map map) { + return ImageData( + path: map['path'] ?? '', + hash: map['hash'] ?? '', + key: map['key'] ?? '', + ); + } + + String toJson() => json.encode(toMap()); + + factory ImageData.fromJson(String source) => ImageData.fromMap(json.decode(source)); +} diff --git a/lib/models/items/intro_skip_model.dart b/lib/models/items/intro_skip_model.dart new file mode 100644 index 0000000..d8a5de2 --- /dev/null +++ b/lib/models/items/intro_skip_model.dart @@ -0,0 +1,47 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first, invalid_annotation_target +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'intro_skip_model.freezed.dart'; +part 'intro_skip_model.g.dart'; + +@freezed +class IntroOutSkipModel with _$IntroOutSkipModel { + const IntroOutSkipModel._(); + factory IntroOutSkipModel({ + IntroSkipModel? intro, + IntroSkipModel? credits, + }) = _IntroOutSkipModel; + + factory IntroOutSkipModel.fromJson(Map json) => _$IntroOutSkipModelFromJson(json); + + bool introInRange(Duration position) { + if (intro == null) return false; + return (position.compareTo(intro!.showTime) >= 0 && position.compareTo(intro!.hideTime) <= 0); + } + + bool creditsInRange(Duration position) { + if (credits == null) return false; + return (position.compareTo(credits!.showTime) >= 0 && position.compareTo(credits!.hideTime) <= 0); + } +} + +@freezed +class IntroSkipModel with _$IntroSkipModel { + factory IntroSkipModel({ + @JsonKey(name: "EpisodeId") required String id, + @JsonKey(name: "Valid") required bool valid, + @JsonKey(name: "IntroStart", fromJson: _durationFromMilliseconds, toJson: _durationToMilliseconds) + required Duration start, + @JsonKey(name: "IntroEnd", fromJson: _durationFromMilliseconds, toJson: _durationToMilliseconds) + required Duration end, + @JsonKey(name: "ShowSkipPromptAt", fromJson: _durationFromMilliseconds, toJson: _durationToMilliseconds) + required Duration showTime, + @JsonKey(name: "HideSkipPromptAt", fromJson: _durationFromMilliseconds, toJson: _durationToMilliseconds) + required Duration hideTime, + }) = _IntroSkipModel; + + factory IntroSkipModel.fromJson(Map json) => _$IntroSkipModelFromJson(json); +} + +Duration _durationFromMilliseconds(num milliseconds) => Duration(milliseconds: (milliseconds * 1000).toInt()); +num _durationToMilliseconds(Duration duration) => duration.inMilliseconds.toDouble() / 1000.0; diff --git a/lib/models/items/intro_skip_model.freezed.dart b/lib/models/items/intro_skip_model.freezed.dart new file mode 100644 index 0000000..41245bf --- /dev/null +++ b/lib/models/items/intro_skip_model.freezed.dart @@ -0,0 +1,565 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'intro_skip_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +IntroOutSkipModel _$IntroOutSkipModelFromJson(Map json) { + return _IntroOutSkipModel.fromJson(json); +} + +/// @nodoc +mixin _$IntroOutSkipModel { + IntroSkipModel? get intro => throw _privateConstructorUsedError; + IntroSkipModel? get credits => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $IntroOutSkipModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $IntroOutSkipModelCopyWith<$Res> { + factory $IntroOutSkipModelCopyWith( + IntroOutSkipModel value, $Res Function(IntroOutSkipModel) then) = + _$IntroOutSkipModelCopyWithImpl<$Res, IntroOutSkipModel>; + @useResult + $Res call({IntroSkipModel? intro, IntroSkipModel? credits}); + + $IntroSkipModelCopyWith<$Res>? get intro; + $IntroSkipModelCopyWith<$Res>? get credits; +} + +/// @nodoc +class _$IntroOutSkipModelCopyWithImpl<$Res, $Val extends IntroOutSkipModel> + implements $IntroOutSkipModelCopyWith<$Res> { + _$IntroOutSkipModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? intro = freezed, + Object? credits = freezed, + }) { + return _then(_value.copyWith( + intro: freezed == intro + ? _value.intro + : intro // ignore: cast_nullable_to_non_nullable + as IntroSkipModel?, + credits: freezed == credits + ? _value.credits + : credits // ignore: cast_nullable_to_non_nullable + as IntroSkipModel?, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $IntroSkipModelCopyWith<$Res>? get intro { + if (_value.intro == null) { + return null; + } + + return $IntroSkipModelCopyWith<$Res>(_value.intro!, (value) { + return _then(_value.copyWith(intro: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $IntroSkipModelCopyWith<$Res>? get credits { + if (_value.credits == null) { + return null; + } + + return $IntroSkipModelCopyWith<$Res>(_value.credits!, (value) { + return _then(_value.copyWith(credits: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$IntroOutSkipModelImplCopyWith<$Res> + implements $IntroOutSkipModelCopyWith<$Res> { + factory _$$IntroOutSkipModelImplCopyWith(_$IntroOutSkipModelImpl value, + $Res Function(_$IntroOutSkipModelImpl) then) = + __$$IntroOutSkipModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({IntroSkipModel? intro, IntroSkipModel? credits}); + + @override + $IntroSkipModelCopyWith<$Res>? get intro; + @override + $IntroSkipModelCopyWith<$Res>? get credits; +} + +/// @nodoc +class __$$IntroOutSkipModelImplCopyWithImpl<$Res> + extends _$IntroOutSkipModelCopyWithImpl<$Res, _$IntroOutSkipModelImpl> + implements _$$IntroOutSkipModelImplCopyWith<$Res> { + __$$IntroOutSkipModelImplCopyWithImpl(_$IntroOutSkipModelImpl _value, + $Res Function(_$IntroOutSkipModelImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? intro = freezed, + Object? credits = freezed, + }) { + return _then(_$IntroOutSkipModelImpl( + intro: freezed == intro + ? _value.intro + : intro // ignore: cast_nullable_to_non_nullable + as IntroSkipModel?, + credits: freezed == credits + ? _value.credits + : credits // ignore: cast_nullable_to_non_nullable + as IntroSkipModel?, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$IntroOutSkipModelImpl extends _IntroOutSkipModel { + _$IntroOutSkipModelImpl({this.intro, this.credits}) : super._(); + + factory _$IntroOutSkipModelImpl.fromJson(Map json) => + _$$IntroOutSkipModelImplFromJson(json); + + @override + final IntroSkipModel? intro; + @override + final IntroSkipModel? credits; + + @override + String toString() { + return 'IntroOutSkipModel(intro: $intro, credits: $credits)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$IntroOutSkipModelImpl && + (identical(other.intro, intro) || other.intro == intro) && + (identical(other.credits, credits) || other.credits == credits)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, intro, credits); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$IntroOutSkipModelImplCopyWith<_$IntroOutSkipModelImpl> get copyWith => + __$$IntroOutSkipModelImplCopyWithImpl<_$IntroOutSkipModelImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$IntroOutSkipModelImplToJson( + this, + ); + } +} + +abstract class _IntroOutSkipModel extends IntroOutSkipModel { + factory _IntroOutSkipModel( + {final IntroSkipModel? intro, + final IntroSkipModel? credits}) = _$IntroOutSkipModelImpl; + _IntroOutSkipModel._() : super._(); + + factory _IntroOutSkipModel.fromJson(Map json) = + _$IntroOutSkipModelImpl.fromJson; + + @override + IntroSkipModel? get intro; + @override + IntroSkipModel? get credits; + @override + @JsonKey(ignore: true) + _$$IntroOutSkipModelImplCopyWith<_$IntroOutSkipModelImpl> get copyWith => + throw _privateConstructorUsedError; +} + +IntroSkipModel _$IntroSkipModelFromJson(Map json) { + return _IntroSkipModel.fromJson(json); +} + +/// @nodoc +mixin _$IntroSkipModel { + @JsonKey(name: "EpisodeId") + String get id => throw _privateConstructorUsedError; + @JsonKey(name: "Valid") + bool get valid => throw _privateConstructorUsedError; + @JsonKey( + name: "IntroStart", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + Duration get start => throw _privateConstructorUsedError; + @JsonKey( + name: "IntroEnd", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + Duration get end => throw _privateConstructorUsedError; + @JsonKey( + name: "ShowSkipPromptAt", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + Duration get showTime => throw _privateConstructorUsedError; + @JsonKey( + name: "HideSkipPromptAt", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + Duration get hideTime => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $IntroSkipModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $IntroSkipModelCopyWith<$Res> { + factory $IntroSkipModelCopyWith( + IntroSkipModel value, $Res Function(IntroSkipModel) then) = + _$IntroSkipModelCopyWithImpl<$Res, IntroSkipModel>; + @useResult + $Res call( + {@JsonKey(name: "EpisodeId") String id, + @JsonKey(name: "Valid") bool valid, + @JsonKey( + name: "IntroStart", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + Duration start, + @JsonKey( + name: "IntroEnd", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + Duration end, + @JsonKey( + name: "ShowSkipPromptAt", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + Duration showTime, + @JsonKey( + name: "HideSkipPromptAt", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + Duration hideTime}); +} + +/// @nodoc +class _$IntroSkipModelCopyWithImpl<$Res, $Val extends IntroSkipModel> + implements $IntroSkipModelCopyWith<$Res> { + _$IntroSkipModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? valid = null, + Object? start = null, + Object? end = null, + Object? showTime = null, + Object? hideTime = null, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + valid: null == valid + ? _value.valid + : valid // ignore: cast_nullable_to_non_nullable + as bool, + start: null == start + ? _value.start + : start // ignore: cast_nullable_to_non_nullable + as Duration, + end: null == end + ? _value.end + : end // ignore: cast_nullable_to_non_nullable + as Duration, + showTime: null == showTime + ? _value.showTime + : showTime // ignore: cast_nullable_to_non_nullable + as Duration, + hideTime: null == hideTime + ? _value.hideTime + : hideTime // ignore: cast_nullable_to_non_nullable + as Duration, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$IntroSkipModelImplCopyWith<$Res> + implements $IntroSkipModelCopyWith<$Res> { + factory _$$IntroSkipModelImplCopyWith(_$IntroSkipModelImpl value, + $Res Function(_$IntroSkipModelImpl) then) = + __$$IntroSkipModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@JsonKey(name: "EpisodeId") String id, + @JsonKey(name: "Valid") bool valid, + @JsonKey( + name: "IntroStart", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + Duration start, + @JsonKey( + name: "IntroEnd", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + Duration end, + @JsonKey( + name: "ShowSkipPromptAt", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + Duration showTime, + @JsonKey( + name: "HideSkipPromptAt", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + Duration hideTime}); +} + +/// @nodoc +class __$$IntroSkipModelImplCopyWithImpl<$Res> + extends _$IntroSkipModelCopyWithImpl<$Res, _$IntroSkipModelImpl> + implements _$$IntroSkipModelImplCopyWith<$Res> { + __$$IntroSkipModelImplCopyWithImpl( + _$IntroSkipModelImpl _value, $Res Function(_$IntroSkipModelImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? valid = null, + Object? start = null, + Object? end = null, + Object? showTime = null, + Object? hideTime = null, + }) { + return _then(_$IntroSkipModelImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + valid: null == valid + ? _value.valid + : valid // ignore: cast_nullable_to_non_nullable + as bool, + start: null == start + ? _value.start + : start // ignore: cast_nullable_to_non_nullable + as Duration, + end: null == end + ? _value.end + : end // ignore: cast_nullable_to_non_nullable + as Duration, + showTime: null == showTime + ? _value.showTime + : showTime // ignore: cast_nullable_to_non_nullable + as Duration, + hideTime: null == hideTime + ? _value.hideTime + : hideTime // ignore: cast_nullable_to_non_nullable + as Duration, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$IntroSkipModelImpl implements _IntroSkipModel { + _$IntroSkipModelImpl( + {@JsonKey(name: "EpisodeId") required this.id, + @JsonKey(name: "Valid") required this.valid, + @JsonKey( + name: "IntroStart", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + required this.start, + @JsonKey( + name: "IntroEnd", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + required this.end, + @JsonKey( + name: "ShowSkipPromptAt", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + required this.showTime, + @JsonKey( + name: "HideSkipPromptAt", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + required this.hideTime}); + + factory _$IntroSkipModelImpl.fromJson(Map json) => + _$$IntroSkipModelImplFromJson(json); + + @override + @JsonKey(name: "EpisodeId") + final String id; + @override + @JsonKey(name: "Valid") + final bool valid; + @override + @JsonKey( + name: "IntroStart", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + final Duration start; + @override + @JsonKey( + name: "IntroEnd", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + final Duration end; + @override + @JsonKey( + name: "ShowSkipPromptAt", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + final Duration showTime; + @override + @JsonKey( + name: "HideSkipPromptAt", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + final Duration hideTime; + + @override + String toString() { + return 'IntroSkipModel(id: $id, valid: $valid, start: $start, end: $end, showTime: $showTime, hideTime: $hideTime)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$IntroSkipModelImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.valid, valid) || other.valid == valid) && + (identical(other.start, start) || other.start == start) && + (identical(other.end, end) || other.end == end) && + (identical(other.showTime, showTime) || + other.showTime == showTime) && + (identical(other.hideTime, hideTime) || + other.hideTime == hideTime)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => + Object.hash(runtimeType, id, valid, start, end, showTime, hideTime); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$IntroSkipModelImplCopyWith<_$IntroSkipModelImpl> get copyWith => + __$$IntroSkipModelImplCopyWithImpl<_$IntroSkipModelImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$IntroSkipModelImplToJson( + this, + ); + } +} + +abstract class _IntroSkipModel implements IntroSkipModel { + factory _IntroSkipModel( + {@JsonKey(name: "EpisodeId") required final String id, + @JsonKey(name: "Valid") required final bool valid, + @JsonKey( + name: "IntroStart", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + required final Duration start, + @JsonKey( + name: "IntroEnd", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + required final Duration end, + @JsonKey( + name: "ShowSkipPromptAt", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + required final Duration showTime, + @JsonKey( + name: "HideSkipPromptAt", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + required final Duration hideTime}) = _$IntroSkipModelImpl; + + factory _IntroSkipModel.fromJson(Map json) = + _$IntroSkipModelImpl.fromJson; + + @override + @JsonKey(name: "EpisodeId") + String get id; + @override + @JsonKey(name: "Valid") + bool get valid; + @override + @JsonKey( + name: "IntroStart", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + Duration get start; + @override + @JsonKey( + name: "IntroEnd", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + Duration get end; + @override + @JsonKey( + name: "ShowSkipPromptAt", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + Duration get showTime; + @override + @JsonKey( + name: "HideSkipPromptAt", + fromJson: _durationFromMilliseconds, + toJson: _durationToMilliseconds) + Duration get hideTime; + @override + @JsonKey(ignore: true) + _$$IntroSkipModelImplCopyWith<_$IntroSkipModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/items/intro_skip_model.g.dart b/lib/models/items/intro_skip_model.g.dart new file mode 100644 index 0000000..01e89f6 --- /dev/null +++ b/lib/models/items/intro_skip_model.g.dart @@ -0,0 +1,46 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'intro_skip_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$IntroOutSkipModelImpl _$$IntroOutSkipModelImplFromJson( + Map json) => + _$IntroOutSkipModelImpl( + intro: json['intro'] == null + ? null + : IntroSkipModel.fromJson(json['intro'] as Map), + credits: json['credits'] == null + ? null + : IntroSkipModel.fromJson(json['credits'] as Map), + ); + +Map _$$IntroOutSkipModelImplToJson( + _$IntroOutSkipModelImpl instance) => + { + 'intro': instance.intro, + 'credits': instance.credits, + }; + +_$IntroSkipModelImpl _$$IntroSkipModelImplFromJson(Map json) => + _$IntroSkipModelImpl( + id: json['EpisodeId'] as String, + valid: json['Valid'] as bool, + start: _durationFromMilliseconds(json['IntroStart'] as num), + end: _durationFromMilliseconds(json['IntroEnd'] as num), + showTime: _durationFromMilliseconds(json['ShowSkipPromptAt'] as num), + hideTime: _durationFromMilliseconds(json['HideSkipPromptAt'] as num), + ); + +Map _$$IntroSkipModelImplToJson( + _$IntroSkipModelImpl instance) => + { + 'EpisodeId': instance.id, + 'Valid': instance.valid, + 'IntroStart': _durationToMilliseconds(instance.start), + 'IntroEnd': _durationToMilliseconds(instance.end), + 'ShowSkipPromptAt': _durationToMilliseconds(instance.showTime), + 'HideSkipPromptAt': _durationToMilliseconds(instance.hideTime), + }; diff --git a/lib/models/items/item_properties_model.dart b/lib/models/items/item_properties_model.dart new file mode 100644 index 0000000..ed5742c --- /dev/null +++ b/lib/models/items/item_properties_model.dart @@ -0,0 +1,21 @@ +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart' as dto; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'item_properties_model.freezed.dart'; + +@Freezed(fromJson: false, toJson: false) +class ItemPropertiesModel with _$ItemPropertiesModel { + const ItemPropertiesModel._(); + + factory ItemPropertiesModel._internal({ + required bool canDelete, + required bool canDownload, + }) = _ItemPropertiesModel; + + factory ItemPropertiesModel.fromBaseDto(dto.BaseItemDto dtoItem) { + return ItemPropertiesModel._internal( + canDelete: dtoItem.canDelete ?? false, + canDownload: dtoItem.canDownload ?? false, + ); + } +} diff --git a/lib/models/items/item_properties_model.freezed.dart b/lib/models/items/item_properties_model.freezed.dart new file mode 100644 index 0000000..016f309 --- /dev/null +++ b/lib/models/items/item_properties_model.freezed.dart @@ -0,0 +1,156 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'item_properties_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$ItemPropertiesModel { + bool get canDelete => throw _privateConstructorUsedError; + bool get canDownload => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $ItemPropertiesModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ItemPropertiesModelCopyWith<$Res> { + factory $ItemPropertiesModelCopyWith( + ItemPropertiesModel value, $Res Function(ItemPropertiesModel) then) = + _$ItemPropertiesModelCopyWithImpl<$Res, ItemPropertiesModel>; + @useResult + $Res call({bool canDelete, bool canDownload}); +} + +/// @nodoc +class _$ItemPropertiesModelCopyWithImpl<$Res, $Val extends ItemPropertiesModel> + implements $ItemPropertiesModelCopyWith<$Res> { + _$ItemPropertiesModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? canDelete = null, + Object? canDownload = null, + }) { + return _then(_value.copyWith( + canDelete: null == canDelete + ? _value.canDelete + : canDelete // ignore: cast_nullable_to_non_nullable + as bool, + canDownload: null == canDownload + ? _value.canDownload + : canDownload // ignore: cast_nullable_to_non_nullable + as bool, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$ItemPropertiesModelImplCopyWith<$Res> + implements $ItemPropertiesModelCopyWith<$Res> { + factory _$$ItemPropertiesModelImplCopyWith(_$ItemPropertiesModelImpl value, + $Res Function(_$ItemPropertiesModelImpl) then) = + __$$ItemPropertiesModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({bool canDelete, bool canDownload}); +} + +/// @nodoc +class __$$ItemPropertiesModelImplCopyWithImpl<$Res> + extends _$ItemPropertiesModelCopyWithImpl<$Res, _$ItemPropertiesModelImpl> + implements _$$ItemPropertiesModelImplCopyWith<$Res> { + __$$ItemPropertiesModelImplCopyWithImpl(_$ItemPropertiesModelImpl _value, + $Res Function(_$ItemPropertiesModelImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? canDelete = null, + Object? canDownload = null, + }) { + return _then(_$ItemPropertiesModelImpl( + canDelete: null == canDelete + ? _value.canDelete + : canDelete // ignore: cast_nullable_to_non_nullable + as bool, + canDownload: null == canDownload + ? _value.canDownload + : canDownload // ignore: cast_nullable_to_non_nullable + as bool, + )); + } +} + +/// @nodoc + +class _$ItemPropertiesModelImpl extends _ItemPropertiesModel { + _$ItemPropertiesModelImpl( + {required this.canDelete, required this.canDownload}) + : super._(); + + @override + final bool canDelete; + @override + final bool canDownload; + + @override + String toString() { + return 'ItemPropertiesModel._internal(canDelete: $canDelete, canDownload: $canDownload)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ItemPropertiesModelImpl && + (identical(other.canDelete, canDelete) || + other.canDelete == canDelete) && + (identical(other.canDownload, canDownload) || + other.canDownload == canDownload)); + } + + @override + int get hashCode => Object.hash(runtimeType, canDelete, canDownload); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ItemPropertiesModelImplCopyWith<_$ItemPropertiesModelImpl> get copyWith => + __$$ItemPropertiesModelImplCopyWithImpl<_$ItemPropertiesModelImpl>( + this, _$identity); +} + +abstract class _ItemPropertiesModel extends ItemPropertiesModel { + factory _ItemPropertiesModel( + {required final bool canDelete, + required final bool canDownload}) = _$ItemPropertiesModelImpl; + _ItemPropertiesModel._() : super._(); + + @override + bool get canDelete; + @override + bool get canDownload; + @override + @JsonKey(ignore: true) + _$$ItemPropertiesModelImplCopyWith<_$ItemPropertiesModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/items/item_shared_models.dart b/lib/models/items/item_shared_models.dart new file mode 100644 index 0000000..d3cc130 --- /dev/null +++ b/lib/models/items/item_shared_models.dart @@ -0,0 +1,380 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +import 'dart:convert'; + +import 'package:collection/collection.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart' as dto; +import 'package:fladder/models/items/images_models.dart'; + +import 'package:dart_mappable/dart_mappable.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'item_shared_models.mapper.dart'; + +@MappableClass() +class UserData with UserDataMappable { + final bool isFavourite; + final int playCount; + final int? unPlayedItemCount; + final int playbackPositionTicks; + final double progress; + final bool played; + final DateTime? lastPlayed; + const UserData({ + this.isFavourite = false, + this.playCount = 0, + this.unPlayedItemCount, + this.playbackPositionTicks = 0, + this.progress = 0, + this.lastPlayed, + this.played = false, + }); + + factory UserData.fromDto(dto.UserItemDataDto? dto) { + if (dto == null) { + return UserData(); + } + return UserData( + isFavourite: dto.isFavorite ?? false, + playCount: dto.playCount ?? 0, + playbackPositionTicks: dto.playbackPositionTicks ?? 0, + played: dto.played ?? false, + unPlayedItemCount: dto.unplayedItemCount ?? 0, + lastPlayed: dto.lastPlayedDate, + progress: dto.playedPercentage ?? 0, + ); + } + + Duration get playBackPosition => Duration(milliseconds: playbackPositionTicks ~/ 10000); + + factory UserData.fromMap(Map map) => UserDataMapper.fromMap(map); + factory UserData.fromJson(String json) => UserDataMapper.fromJson(json); +} + +class UserDataJsonSerializer extends JsonConverter { + const UserDataJsonSerializer(); + + @override + UserData fromJson(String json) { + return UserData.fromJson(json); + } + + @override + String toJson(UserData object) { + return object.toJson(); + } +} + +enum EditorLockedFields { + name("Name"), + overView("Overview"), + genres("Genres"), + officialRating("OfficialRating"), + cast("Cast"), + productionLocations("ProductionLocations"), + runTime("Runtime"), + studios("Studios"), + tags("Tags"), + ; + + const EditorLockedFields(this.value); + + static Map enabled(List fromStrings) => Map.fromEntries( + EditorLockedFields.values.map( + (e) => MapEntry(e, fromStrings.contains(e.value)), + ), + ); + + final String value; +} + +enum DisplayOrder { + empty(""), + aired("aired"), + originalAirDate("originalAirDate"), + absolute("absolute"), + dvd("dvd"), + digital("digital"), + storyArc("storyArc"), + production("production"), + tv("tv"), + ; + + const DisplayOrder(this.value); + + static DisplayOrder? fromMap(String? value) { + return DisplayOrder.values.firstWhereOrNull((element) => element.value == value) ?? DisplayOrder.empty; + } + + final String value; +} + +enum ShowStatus { + empty(""), + ended("Ended"), + continuing("Continuing"); + + const ShowStatus(this.value); + + static ShowStatus? fromMap(String? value) { + return ShowStatus.values.firstWhereOrNull((element) => element.value == value) ?? ShowStatus.empty; + } + + final String value; +} + +class ExternalUrls { + final String name; + final String url; + ExternalUrls({ + required this.name, + required this.url, + }); + + static List fromDto(List dto) { + return dto.map((e) => ExternalUrls(name: e.name ?? "", url: e.url ?? "")).toList(); + } + + Map toMap() { + return { + 'Name': name, + 'Url': url, + }; + } + + factory ExternalUrls.fromMap(Map map) { + return ExternalUrls( + name: map['Name'] ?? '', + url: map['Url'] ?? '', + ); + } + + String toJson() => json.encode(toMap()); + + factory ExternalUrls.fromJson(String source) => ExternalUrls.fromMap(json.decode(source)); +} + +class GenreItems { + final String id; + final String name; + GenreItems({ + required this.id, + required this.name, + }); + + @override + String toString() => 'GenreItems(id: $id, name: $name)'; +} + +class Person { + final String id; + final String name; + final ImageData? image; + final String role; + final PersonKind? type; + Person({ + required this.id, + this.name = "", + this.image, + this.role = "", + this.type, + }); + + static Person fromBaseDto(dto.BaseItemDto item, Ref ref) { + return Person( + id: item.id ?? "", + name: item.name ?? "", + image: ImagesData.fromBaseItem(item, ref).primary, + ); + } + + static Person fromBasePerson(dto.BaseItemPerson person, Ref ref) { + return Person( + id: person.id ?? "", + name: person.name ?? "", + image: ImagesData.fromPersonDto(person, ref)?.primary, + role: person.role ?? "", + type: person.type); + } + + dto.BaseItemPerson toPerson() { + return dto.BaseItemPerson( + id: id, + name: name, + type: type, + role: role, + ); + } + + static List peopleFromDto(List? people, Ref ref) { + return people + ?.mapIndexed( + (index, person) => fromBasePerson(person, ref), + ) + .toList() ?? + []; + } + + @override + String toString() { + return 'People(id: $id, name: $name, imageUrl: $image, role: $role, type: $type)'; + } +} + +class Studio { + final String id; + final String name; + Studio({ + required this.id, + required this.name, + }); + + Studio copyWith({ + String? id, + String? name, + ValueGetter? image, + }) { + return Studio( + id: id ?? this.id, + name: name ?? this.name, + ); + } + + @override + String toString() => 'Studio(name: $name, id: $id)'; + + Map toMap() { + return { + 'id': id, + 'name': name, + }; + } + + factory Studio.fromMap(Map map) { + return Studio( + id: map['id'] ?? map['Id'] ?? '', + name: map['name'] ?? map['Name'] ?? '', + ); + } + + String toJson() => json.encode(toMap()); + + factory Studio.fromJson(String source) => Studio.fromMap(json.decode(source)); + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + + return other is Studio && other.id == id && other.name == name; + } + + @override + int get hashCode => id.hashCode ^ name.hashCode; +} + +// class UserData { +// final bool isFavourite; +// final int playCount; +// final int? unPlayedItemCount; +// final int playbackPositionTicks; +// final double progress; +// final bool played; +// UserData({ +// this.isFavourite = false, +// this.playCount = 0, +// this.unPlayedItemCount, +// this.playbackPositionTicks = 0, +// this.progress = 0, +// this.played = false, +// }); + +// factory UserData.fromDto(dto.UserItemDataDto? dto) { +// if (dto == null) { +// return UserData(); +// } +// return UserData( +// isFavourite: dto.isFavorite ?? false, +// playCount: dto.playCount ?? 0, +// playbackPositionTicks: dto.playbackPositionTicks ?? 0, +// played: dto.played ?? false, +// unPlayedItemCount: dto.unplayedItemCount ?? 0, +// progress: dto.playedPercentage ?? 0, +// ); +// } + +// Duration get playBackPosition => Duration(milliseconds: playbackPositionTicks ~/ 10000); + +// @override +// String toString() { +// return 'UserData(isFavourite: $isFavourite, playCount: $playCount, unPlayedItemCount: $unPlayedItemCount, playbackPositionTicks: $playbackPositionTicks, progress: $progress, played: $played)'; +// } + +// UserData copyWith({ +// bool? isFavourite, +// int? playCount, +// int? unPlayedItemCount, +// int? playbackPositionTicks, +// double? progress, +// bool? played, +// }) { +// return UserData( +// isFavourite: isFavourite ?? this.isFavourite, +// playCount: playCount ?? this.playCount, +// unPlayedItemCount: unPlayedItemCount ?? this.unPlayedItemCount, +// playbackPositionTicks: playbackPositionTicks ?? this.playbackPositionTicks, +// progress: progress ?? this.progress, +// played: played ?? this.played, +// ); +// } + +// Map toMap() { +// return { +// 'isFavourite': isFavourite, +// 'playCount': playCount, +// 'unPlayedItemCount': unPlayedItemCount, +// 'playbackPositionTicks': playbackPositionTicks, +// 'progress': progress, +// 'played': played, +// }; +// } + +// factory UserData.fromMap(Map map) { +// return UserData( +// isFavourite: (map['isFavourite'] ?? false) as bool, +// playCount: (map['playCount'] ?? 0) as int, +// unPlayedItemCount: (map['unPlayedItemCount'] ?? 0) as int, +// playbackPositionTicks: (map['playbackPositionTicks'] ?? 0) as int, +// progress: (map['progress'] ?? 0.0) as double, +// played: (map['played'] ?? false) as bool, +// ); +// } + +// String toJson() => json.encode(toMap()); + +// factory UserData.fromJson(String source) => UserData.fromMap(json.decode(source) as Map); + +// @override +// bool operator ==(covariant UserData other) { +// if (identical(this, other)) return true; + +// return other.isFavourite == isFavourite && +// other.playCount == playCount && +// other.unPlayedItemCount == unPlayedItemCount && +// other.playbackPositionTicks == playbackPositionTicks && +// other.progress == progress && +// other.played == played; +// } + +// @override +// int get hashCode { +// return isFavourite.hashCode ^ +// playCount.hashCode ^ +// unPlayedItemCount.hashCode ^ +// playbackPositionTicks.hashCode ^ +// progress.hashCode ^ +// played.hashCode; +// } +// } diff --git a/lib/models/items/item_shared_models.mapper.dart b/lib/models/items/item_shared_models.mapper.dart new file mode 100644 index 0000000..9a17f2b --- /dev/null +++ b/lib/models/items/item_shared_models.mapper.dart @@ -0,0 +1,162 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member +// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter + +part of 'item_shared_models.dart'; + +class UserDataMapper extends ClassMapperBase { + UserDataMapper._(); + + static UserDataMapper? _instance; + static UserDataMapper ensureInitialized() { + if (_instance == null) { + MapperContainer.globals.use(_instance = UserDataMapper._()); + } + return _instance!; + } + + @override + final String id = 'UserData'; + + static bool _$isFavourite(UserData v) => v.isFavourite; + static const Field _f$isFavourite = + Field('isFavourite', _$isFavourite, opt: true, def: false); + static int _$playCount(UserData v) => v.playCount; + static const Field _f$playCount = + Field('playCount', _$playCount, opt: true, def: 0); + static int? _$unPlayedItemCount(UserData v) => v.unPlayedItemCount; + static const Field _f$unPlayedItemCount = + Field('unPlayedItemCount', _$unPlayedItemCount, opt: true); + static int _$playbackPositionTicks(UserData v) => v.playbackPositionTicks; + static const Field _f$playbackPositionTicks = Field( + 'playbackPositionTicks', _$playbackPositionTicks, + opt: true, def: 0); + static double _$progress(UserData v) => v.progress; + static const Field _f$progress = + Field('progress', _$progress, opt: true, def: 0); + static DateTime? _$lastPlayed(UserData v) => v.lastPlayed; + static const Field _f$lastPlayed = + Field('lastPlayed', _$lastPlayed, opt: true); + static bool _$played(UserData v) => v.played; + static const Field _f$played = + Field('played', _$played, opt: true, def: false); + + @override + final MappableFields fields = const { + #isFavourite: _f$isFavourite, + #playCount: _f$playCount, + #unPlayedItemCount: _f$unPlayedItemCount, + #playbackPositionTicks: _f$playbackPositionTicks, + #progress: _f$progress, + #lastPlayed: _f$lastPlayed, + #played: _f$played, + }; + @override + final bool ignoreNull = true; + + static UserData _instantiate(DecodingData data) { + return UserData( + isFavourite: data.dec(_f$isFavourite), + playCount: data.dec(_f$playCount), + unPlayedItemCount: data.dec(_f$unPlayedItemCount), + playbackPositionTicks: data.dec(_f$playbackPositionTicks), + progress: data.dec(_f$progress), + lastPlayed: data.dec(_f$lastPlayed), + played: data.dec(_f$played)); + } + + @override + final Function instantiate = _instantiate; + + static UserData fromMap(Map map) { + return ensureInitialized().decodeMap(map); + } + + static UserData fromJson(String json) { + return ensureInitialized().decodeJson(json); + } +} + +mixin UserDataMappable { + String toJson() { + return UserDataMapper.ensureInitialized() + .encodeJson(this as UserData); + } + + Map toMap() { + return UserDataMapper.ensureInitialized() + .encodeMap(this as UserData); + } + + UserDataCopyWith get copyWith => + _UserDataCopyWithImpl(this as UserData, $identity, $identity); + @override + String toString() { + return UserDataMapper.ensureInitialized().stringifyValue(this as UserData); + } +} + +extension UserDataValueCopy<$R, $Out> on ObjectCopyWith<$R, UserData, $Out> { + UserDataCopyWith<$R, UserData, $Out> get $asUserData => + $base.as((v, t, t2) => _UserDataCopyWithImpl(v, t, t2)); +} + +abstract class UserDataCopyWith<$R, $In extends UserData, $Out> + implements ClassCopyWith<$R, $In, $Out> { + $R call( + {bool? isFavourite, + int? playCount, + int? unPlayedItemCount, + int? playbackPositionTicks, + double? progress, + DateTime? lastPlayed, + bool? played}); + UserDataCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t); +} + +class _UserDataCopyWithImpl<$R, $Out> + extends ClassCopyWithBase<$R, UserData, $Out> + implements UserDataCopyWith<$R, UserData, $Out> { + _UserDataCopyWithImpl(super.value, super.then, super.then2); + + @override + late final ClassMapperBase $mapper = + UserDataMapper.ensureInitialized(); + @override + $R call( + {bool? isFavourite, + int? playCount, + Object? unPlayedItemCount = $none, + int? playbackPositionTicks, + double? progress, + Object? lastPlayed = $none, + bool? played}) => + $apply(FieldCopyWithData({ + if (isFavourite != null) #isFavourite: isFavourite, + if (playCount != null) #playCount: playCount, + if (unPlayedItemCount != $none) #unPlayedItemCount: unPlayedItemCount, + if (playbackPositionTicks != null) + #playbackPositionTicks: playbackPositionTicks, + if (progress != null) #progress: progress, + if (lastPlayed != $none) #lastPlayed: lastPlayed, + if (played != null) #played: played + })); + @override + UserData $make(CopyWithData data) => UserData( + isFavourite: data.get(#isFavourite, or: $value.isFavourite), + playCount: data.get(#playCount, or: $value.playCount), + unPlayedItemCount: + data.get(#unPlayedItemCount, or: $value.unPlayedItemCount), + playbackPositionTicks: + data.get(#playbackPositionTicks, or: $value.playbackPositionTicks), + progress: data.get(#progress, or: $value.progress), + lastPlayed: data.get(#lastPlayed, or: $value.lastPlayed), + played: data.get(#played, or: $value.played)); + + @override + UserDataCopyWith<$R2, UserData, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t) => + _UserDataCopyWithImpl($value, $cast, t); +} diff --git a/lib/models/items/item_stream_model.dart b/lib/models/items/item_stream_model.dart new file mode 100644 index 0000000..fcc84a8 --- /dev/null +++ b/lib/models/items/item_stream_model.dart @@ -0,0 +1,67 @@ +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart' as dto; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/episode_model.dart'; +import 'package:fladder/models/items/images_models.dart'; +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/models/items/media_streams_model.dart'; +import 'package:fladder/models/items/movie_model.dart'; +import 'package:fladder/models/items/overview_model.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:dart_mappable/dart_mappable.dart'; + +part 'item_stream_model.mapper.dart'; + +@MappableClass() +class ItemStreamModel extends ItemBaseModel with ItemStreamModelMappable { + final ImagesData? parentImages; + final MediaStreamsModel mediaStreams; + const ItemStreamModel({ + required this.parentImages, + required this.mediaStreams, + required super.name, + required super.id, + required super.overview, + required super.parentId, + required super.playlistId, + required super.images, + required super.childCount, + required super.primaryRatio, + required super.userData, + required super.canDelete, + required super.canDownload, + super.jellyType, + }); + factory ItemStreamModel.fromBaseDto(dto.BaseItemDto item, Ref ref) { + return switch (item.type) { + BaseItemKind.episode => EpisodeModel.fromBaseDto(item, ref), + BaseItemKind.movie => MovieModel.fromBaseDto(item, ref), + _ => ItemStreamModel._fromBaseDto(item, ref) + }; + } + + factory ItemStreamModel._fromBaseDto(dto.BaseItemDto item, Ref ref) { + return ItemStreamModel( + name: item.name ?? "", + id: item.id ?? "", + childCount: item.childCount, + overview: OverviewModel.fromBaseItemDto(item, ref), + userData: UserData.fromDto(item.userData), + parentId: item.parentId, + playlistId: item.playlistItemId, + images: ImagesData.fromBaseItem(item, ref), + primaryRatio: item.primaryImageAspectRatio, + parentImages: ImagesData.fromBaseItemParent(item, ref), + canDelete: item.canDelete, + canDownload: item.canDownload, + mediaStreams: + MediaStreamsModel.fromMediaStreamsList(item.mediaSources?.firstOrNull, item.mediaStreams ?? [], ref), + ); + } + + String? get videoPropertiesLabel { + if (mediaStreams.displayProfile == null && mediaStreams.resolution == null) return null; + return "${mediaStreams.displayProfile?.value}"; + } +} diff --git a/lib/models/items/item_stream_model.mapper.dart b/lib/models/items/item_stream_model.mapper.dart new file mode 100644 index 0000000..d83984c --- /dev/null +++ b/lib/models/items/item_stream_model.mapper.dart @@ -0,0 +1,245 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member +// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter + +part of 'item_stream_model.dart'; + +class ItemStreamModelMapper extends SubClassMapperBase { + ItemStreamModelMapper._(); + + static ItemStreamModelMapper? _instance; + static ItemStreamModelMapper ensureInitialized() { + if (_instance == null) { + MapperContainer.globals.use(_instance = ItemStreamModelMapper._()); + ItemBaseModelMapper.ensureInitialized().addSubMapper(_instance!); + OverviewModelMapper.ensureInitialized(); + UserDataMapper.ensureInitialized(); + } + return _instance!; + } + + @override + final String id = 'ItemStreamModel'; + + static ImagesData? _$parentImages(ItemStreamModel v) => v.parentImages; + static const Field _f$parentImages = + Field('parentImages', _$parentImages); + static MediaStreamsModel _$mediaStreams(ItemStreamModel v) => v.mediaStreams; + static const Field _f$mediaStreams = + Field('mediaStreams', _$mediaStreams); + static String _$name(ItemStreamModel v) => v.name; + static const Field _f$name = Field('name', _$name); + static String _$id(ItemStreamModel v) => v.id; + static const Field _f$id = Field('id', _$id); + static OverviewModel _$overview(ItemStreamModel v) => v.overview; + static const Field _f$overview = + Field('overview', _$overview); + static String? _$parentId(ItemStreamModel v) => v.parentId; + static const Field _f$parentId = + Field('parentId', _$parentId); + static String? _$playlistId(ItemStreamModel v) => v.playlistId; + static const Field _f$playlistId = + Field('playlistId', _$playlistId); + static ImagesData? _$images(ItemStreamModel v) => v.images; + static const Field _f$images = + Field('images', _$images); + static int? _$childCount(ItemStreamModel v) => v.childCount; + static const Field _f$childCount = + Field('childCount', _$childCount); + static double? _$primaryRatio(ItemStreamModel v) => v.primaryRatio; + static const Field _f$primaryRatio = + Field('primaryRatio', _$primaryRatio); + static UserData _$userData(ItemStreamModel v) => v.userData; + static const Field _f$userData = + Field('userData', _$userData); + static bool? _$canDelete(ItemStreamModel v) => v.canDelete; + static const Field _f$canDelete = + Field('canDelete', _$canDelete); + static bool? _$canDownload(ItemStreamModel v) => v.canDownload; + static const Field _f$canDownload = + Field('canDownload', _$canDownload); + static dto.BaseItemKind? _$jellyType(ItemStreamModel v) => v.jellyType; + static const Field _f$jellyType = + Field('jellyType', _$jellyType, opt: true); + + @override + final MappableFields fields = const { + #parentImages: _f$parentImages, + #mediaStreams: _f$mediaStreams, + #name: _f$name, + #id: _f$id, + #overview: _f$overview, + #parentId: _f$parentId, + #playlistId: _f$playlistId, + #images: _f$images, + #childCount: _f$childCount, + #primaryRatio: _f$primaryRatio, + #userData: _f$userData, + #canDelete: _f$canDelete, + #canDownload: _f$canDownload, + #jellyType: _f$jellyType, + }; + @override + final bool ignoreNull = true; + + @override + final String discriminatorKey = 'type'; + @override + final dynamic discriminatorValue = 'ItemStreamModel'; + @override + late final ClassMapperBase superMapper = + ItemBaseModelMapper.ensureInitialized(); + + static ItemStreamModel _instantiate(DecodingData data) { + return ItemStreamModel( + parentImages: data.dec(_f$parentImages), + mediaStreams: data.dec(_f$mediaStreams), + name: data.dec(_f$name), + id: data.dec(_f$id), + overview: data.dec(_f$overview), + parentId: data.dec(_f$parentId), + playlistId: data.dec(_f$playlistId), + images: data.dec(_f$images), + childCount: data.dec(_f$childCount), + primaryRatio: data.dec(_f$primaryRatio), + userData: data.dec(_f$userData), + canDelete: data.dec(_f$canDelete), + canDownload: data.dec(_f$canDownload), + jellyType: data.dec(_f$jellyType)); + } + + @override + final Function instantiate = _instantiate; + + static ItemStreamModel fromMap(Map map) { + return ensureInitialized().decodeMap(map); + } + + static ItemStreamModel fromJson(String json) { + return ensureInitialized().decodeJson(json); + } +} + +mixin ItemStreamModelMappable { + String toJson() { + return ItemStreamModelMapper.ensureInitialized() + .encodeJson(this as ItemStreamModel); + } + + Map toMap() { + return ItemStreamModelMapper.ensureInitialized() + .encodeMap(this as ItemStreamModel); + } + + ItemStreamModelCopyWith + get copyWith => _ItemStreamModelCopyWithImpl( + this as ItemStreamModel, $identity, $identity); + @override + String toString() { + return ItemStreamModelMapper.ensureInitialized() + .stringifyValue(this as ItemStreamModel); + } +} + +extension ItemStreamModelValueCopy<$R, $Out> + on ObjectCopyWith<$R, ItemStreamModel, $Out> { + ItemStreamModelCopyWith<$R, ItemStreamModel, $Out> get $asItemStreamModel => + $base.as((v, t, t2) => _ItemStreamModelCopyWithImpl(v, t, t2)); +} + +abstract class ItemStreamModelCopyWith<$R, $In extends ItemStreamModel, $Out> + implements ItemBaseModelCopyWith<$R, $In, $Out> { + @override + OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview; + @override + UserDataCopyWith<$R, UserData, UserData> get userData; + @override + $R call( + {ImagesData? parentImages, + MediaStreamsModel? mediaStreams, + String? name, + String? id, + OverviewModel? overview, + String? parentId, + String? playlistId, + ImagesData? images, + int? childCount, + double? primaryRatio, + UserData? userData, + bool? canDelete, + bool? canDownload, + dto.BaseItemKind? jellyType}); + ItemStreamModelCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t); +} + +class _ItemStreamModelCopyWithImpl<$R, $Out> + extends ClassCopyWithBase<$R, ItemStreamModel, $Out> + implements ItemStreamModelCopyWith<$R, ItemStreamModel, $Out> { + _ItemStreamModelCopyWithImpl(super.value, super.then, super.then2); + + @override + late final ClassMapperBase $mapper = + ItemStreamModelMapper.ensureInitialized(); + @override + OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview => + $value.overview.copyWith.$chain((v) => call(overview: v)); + @override + UserDataCopyWith<$R, UserData, UserData> get userData => + $value.userData.copyWith.$chain((v) => call(userData: v)); + @override + $R call( + {Object? parentImages = $none, + MediaStreamsModel? mediaStreams, + String? name, + String? id, + OverviewModel? overview, + Object? parentId = $none, + Object? playlistId = $none, + Object? images = $none, + Object? childCount = $none, + Object? primaryRatio = $none, + UserData? userData, + Object? canDelete = $none, + Object? canDownload = $none, + Object? jellyType = $none}) => + $apply(FieldCopyWithData({ + if (parentImages != $none) #parentImages: parentImages, + if (mediaStreams != null) #mediaStreams: mediaStreams, + if (name != null) #name: name, + if (id != null) #id: id, + if (overview != null) #overview: overview, + if (parentId != $none) #parentId: parentId, + if (playlistId != $none) #playlistId: playlistId, + if (images != $none) #images: images, + if (childCount != $none) #childCount: childCount, + if (primaryRatio != $none) #primaryRatio: primaryRatio, + if (userData != null) #userData: userData, + if (canDelete != $none) #canDelete: canDelete, + if (canDownload != $none) #canDownload: canDownload, + if (jellyType != $none) #jellyType: jellyType + })); + @override + ItemStreamModel $make(CopyWithData data) => ItemStreamModel( + parentImages: data.get(#parentImages, or: $value.parentImages), + mediaStreams: data.get(#mediaStreams, or: $value.mediaStreams), + name: data.get(#name, or: $value.name), + id: data.get(#id, or: $value.id), + overview: data.get(#overview, or: $value.overview), + parentId: data.get(#parentId, or: $value.parentId), + playlistId: data.get(#playlistId, or: $value.playlistId), + images: data.get(#images, or: $value.images), + childCount: data.get(#childCount, or: $value.childCount), + primaryRatio: data.get(#primaryRatio, or: $value.primaryRatio), + userData: data.get(#userData, or: $value.userData), + canDelete: data.get(#canDelete, or: $value.canDelete), + canDownload: data.get(#canDownload, or: $value.canDownload), + jellyType: data.get(#jellyType, or: $value.jellyType)); + + @override + ItemStreamModelCopyWith<$R2, ItemStreamModel, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t) => + _ItemStreamModelCopyWithImpl($value, $cast, t); +} diff --git a/lib/models/items/media_streams_model.dart b/lib/models/items/media_streams_model.dart new file mode 100644 index 0000000..5f72277 --- /dev/null +++ b/lib/models/items/media_streams_model.dart @@ -0,0 +1,372 @@ +import 'dart:convert'; + +import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.dart'; +import 'package:flutter/material.dart'; + +// ignore_for_file: public_member_api_docs, sort_constructors_first +import 'package:collection/collection.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart' as dto; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/util/video_properties.dart'; + +class MediaStreamsModel { + final int? defaultAudioStreamIndex; + final int? defaultSubStreamIndex; + final List videoStreams; + final List audioStreams; + final List subStreams; + MediaStreamsModel({ + this.defaultAudioStreamIndex, + this.defaultSubStreamIndex, + required this.videoStreams, + required this.audioStreams, + required this.subStreams, + }); + + bool get isNull { + return defaultAudioStreamIndex == null || + defaultSubStreamIndex == null || + audioStreams.isEmpty || + subStreams.isEmpty; + } + + bool get isNotEmpty { + return audioStreams.isNotEmpty && subStreams.isNotEmpty; + } + + AudioStreamModel? get currentAudioStream { + if (defaultAudioStreamIndex == -1) { + return AudioStreamModel.no(); + } + return audioStreams.firstWhereOrNull((element) => element.index == defaultAudioStreamIndex) ?? + audioStreams.firstOrNull; + } + + SubStreamModel? get currentSubStream { + if (defaultSubStreamIndex == -1) { + return SubStreamModel.no(); + } + return subStreams.firstWhereOrNull((element) => element.index == defaultSubStreamIndex) ?? subStreams.firstOrNull; + } + + DisplayProfile? get displayProfile { + return DisplayProfile.fromVideoStreams(videoStreams); + } + + Resolution? get resolution { + return Resolution.fromVideoStream(videoStreams.firstOrNull); + } + + String? get resolutionText { + final stream = videoStreams.firstOrNull; + if (stream == null) return null; + return "${stream.width}x${stream.height}"; + } + + Widget? audioIcon( + BuildContext context, + Function()? onTap, + ) { + final audioStream = audioStreams.firstWhereOrNull((element) => element.isDefault) ?? audioStreams.firstOrNull; + if (audioStream == null) return null; + return DefaultVideoInformationBox( + onTap: onTap, + child: Text( + audioStream.title, + ), + ); + } + + Widget subtitleIcon( + BuildContext context, + Function()? onTap, + ) { + return DefaultVideoInformationBox( + onTap: onTap, + child: Icon( + subStreams.isNotEmpty ? Icons.subtitles_rounded : Icons.subtitles_off_outlined, + ), + ); + } + + static MediaStreamsModel fromMediaStreamsList( + dto.MediaSourceInfo? mediaSource, List streams, Ref ref) { + return MediaStreamsModel( + defaultAudioStreamIndex: mediaSource?.defaultAudioStreamIndex, + defaultSubStreamIndex: mediaSource?.defaultSubtitleStreamIndex, + videoStreams: streams + .where((element) => element.type == dto.MediaStreamType.video) + .map( + (e) => VideoStreamModel.fromMediaStream(e), + ) + .sortByExternal(), + audioStreams: streams + .where((element) => element.type == dto.MediaStreamType.audio) + .map( + (e) => AudioStreamModel.fromMediaStream(e), + ) + .sortByExternal(), + subStreams: streams + .where((element) => element.type == dto.MediaStreamType.subtitle) + .map( + (sub) => SubStreamModel.fromMediaStream(sub, ref), + ) + .sortByExternal(), + ); + } + + MediaStreamsModel copyWith({ + int? defaultAudioStreamIndex, + int? defaultSubStreamIndex, + List? videoStreams, + List? audioStreams, + List? subStreams, + }) { + return MediaStreamsModel( + defaultAudioStreamIndex: defaultAudioStreamIndex ?? this.defaultAudioStreamIndex, + defaultSubStreamIndex: defaultSubStreamIndex ?? this.defaultSubStreamIndex, + videoStreams: videoStreams ?? this.videoStreams, + audioStreams: audioStreams ?? this.audioStreams, + subStreams: subStreams ?? this.subStreams, + ); + } + + @override + String toString() { + return 'MediaStreamsModel(defaultAudioStreamIndex: $defaultAudioStreamIndex, defaultSubStreamIndex: $defaultSubStreamIndex, videoStreams: $videoStreams, audioStreams: $audioStreams, subStreams: $subStreams)'; + } +} + +class StreamModel { + final String name; + final String codec; + final bool isDefault; + final bool isExternal; + final int index; + StreamModel({ + required this.name, + required this.codec, + required this.isDefault, + required this.isExternal, + required this.index, + }); +} + +class VideoStreamModel extends StreamModel { + final int width; + final int height; + final double frameRate; + final String? videoDoViTitle; + final VideoRangeType? videoRangeType; + VideoStreamModel({ + required super.name, + required super.codec, + required super.isDefault, + required super.isExternal, + required super.index, + required this.videoDoViTitle, + required this.videoRangeType, + required this.width, + required this.height, + required this.frameRate, + }); + + factory VideoStreamModel.fromMediaStream(dto.MediaStream stream) { + return VideoStreamModel( + name: stream.title ?? "", + isDefault: stream.isDefault ?? false, + codec: stream.codec ?? "", + videoDoViTitle: stream.videoDoViTitle, + videoRangeType: stream.videoRangeType, + width: stream.width ?? 0, + height: stream.height ?? 0, + frameRate: stream.realFrameRate ?? 24, + isExternal: stream.isExternal ?? false, + index: stream.index ?? -1, + ); + } + String get prettyName { + return "${Resolution.fromVideoStream(this)?.value} - ${DisplayProfile.fromVideoStream(this).value} - (${codec.toUpperCase()})"; + } + + @override + String toString() { + return 'VideoStreamModel(width: $width, height: $height, frameRate: $frameRate, videoDoViTitle: $videoDoViTitle, videoRangeType: $videoRangeType)'; + } +} + +//Instead of using sortBy(a.isExternal etc..) this one seems to be more consistent for some reason +extension SortByExternalExtension on Iterable { + List sortByExternal() { + return [...where((element) => !element.isExternal), ...where((element) => element.isExternal)]; + } +} + +class AudioStreamModel extends StreamModel { + final String displayTitle; + final String language; + final String channelLayout; + + AudioStreamModel({ + required this.displayTitle, + required super.name, + required super.codec, + required super.isDefault, + required super.isExternal, + required super.index, + required this.language, + required this.channelLayout, + }); + + factory AudioStreamModel.fromMediaStream(dto.MediaStream stream) { + return AudioStreamModel( + displayTitle: stream.displayTitle ?? "", + name: stream.title ?? "", + isDefault: stream.isDefault ?? false, + codec: stream.codec ?? "", + language: stream.language ?? "Unknown", + channelLayout: stream.channelLayout ?? "", + isExternal: stream.isExternal ?? false, + index: stream.index ?? -1, + ); + } + + String get title => + [name, language, codec, channelLayout].whereNotNull().where((element) => element.isNotEmpty).join(' - '); + + AudioStreamModel.no({ + super.name = 'Off', + this.displayTitle = 'Off', + this.language = '', + super.codec = '', + this.channelLayout = '', + super.isDefault = false, + super.isExternal = false, + super.index = -1, + }); +} + +class SubStreamModel extends StreamModel { + String id; + String title; + String displayTitle; + String language; + String? url; + bool supportsExternalStream; + SubStreamModel({ + required super.name, + required this.id, + required this.title, + required this.displayTitle, + required this.language, + this.url, + required super.codec, + required super.isDefault, + required super.isExternal, + required super.index, + this.supportsExternalStream = false, + }); + + SubStreamModel.no({ + super.name = 'Off', + this.id = 'Off', + this.title = 'Off', + this.displayTitle = 'Off', + this.language = '', + this.url = '', + super.codec = '', + super.isDefault = false, + super.isExternal = false, + super.index = -1, + this.supportsExternalStream = false, + }); + + factory SubStreamModel.fromMediaStream(dto.MediaStream stream, Ref ref) { + return SubStreamModel( + name: stream.title ?? "", + title: stream.title ?? "", + displayTitle: stream.displayTitle ?? "", + language: stream.language ?? "Unknown", + isDefault: stream.isDefault ?? false, + codec: stream.codec ?? "", + id: stream.hashCode.toString(), + supportsExternalStream: stream.supportsExternalStream ?? false, + url: stream.deliveryUrl != null + ? "${ref.read(userProvider)?.server ?? ""}${stream.deliveryUrl}}".replaceAll(".vtt", ".srt") + : null, + isExternal: stream.isExternal ?? false, + index: stream.index ?? -1, + ); + } + + SubStreamModel copyWith({ + String? name, + String? id, + String? title, + String? displayTitle, + String? language, + ValueGetter? url, + String? codec, + bool? isDefault, + bool? isExternal, + int? index, + bool? supportsExternalStream, + }) { + return SubStreamModel( + name: name ?? this.name, + id: id ?? this.id, + title: title ?? this.title, + displayTitle: displayTitle ?? this.displayTitle, + language: language ?? this.language, + url: url != null ? url() : this.url, + supportsExternalStream: supportsExternalStream ?? this.supportsExternalStream, + codec: codec ?? this.codec, + isDefault: isDefault ?? this.isDefault, + isExternal: isExternal ?? this.isExternal, + index: index ?? this.index, + ); + } + + Map toMap() { + return { + 'name': name, + 'id': id, + 'title': title, + 'displayTitle': displayTitle, + 'language': language, + 'url': url, + 'supportsExternalStream': supportsExternalStream, + 'codec': codec, + 'isExternal': isExternal, + 'isDefault': isDefault, + 'index': index, + }; + } + + factory SubStreamModel.fromMap(Map map) { + return SubStreamModel( + name: map['name'] ?? '', + id: map['id'] ?? '', + title: map['title'] ?? '', + displayTitle: map['displayTitle'] ?? '', + language: map['language'] ?? '', + url: map['url'], + supportsExternalStream: map['supportsExternalStream'] ?? false, + codec: map['codec'] ?? '', + isDefault: map['isDefault'] ?? false, + isExternal: map['isExternal'] ?? false, + index: map['index'] ?? -1, + ); + } + + String toJson() => json.encode(toMap()); + + factory SubStreamModel.fromJson(String source) => SubStreamModel.fromMap(json.decode(source)); + + @override + String toString() { + return 'SubFile(title: $title, displayTitle: $displayTitle, language: $language, url: $url, isExternal: $isExternal)'; + } +} diff --git a/lib/models/items/movie_model.dart b/lib/models/items/movie_model.dart new file mode 100644 index 0000000..84125fb --- /dev/null +++ b/lib/models/items/movie_model.dart @@ -0,0 +1,107 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first + +import 'package:fladder/util/humanize_duration.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart' as dto; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/chapters_model.dart'; +import 'package:fladder/models/items/images_models.dart'; +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/models/items/item_stream_model.dart'; +import 'package:fladder/models/items/media_streams_model.dart'; +import 'package:fladder/models/items/overview_model.dart'; +import 'package:fladder/screens/details_screens/movie_detail_screen.dart'; + +import 'package:dart_mappable/dart_mappable.dart'; + +part 'movie_model.mapper.dart'; + +@MappableClass() +class MovieModel extends ItemStreamModel with MovieModelMappable { + final String originalTitle; + final String? path; + final DateTime premiereDate; + final String sortName; + final String status; + final List related; + final List chapters; + const MovieModel({ + required this.originalTitle, + this.path, + this.chapters = const [], + required this.premiereDate, + required this.sortName, + required this.status, + this.related = const [], + required super.name, + required super.id, + required super.overview, + required super.parentId, + required super.playlistId, + required super.images, + required super.childCount, + required super.primaryRatio, + required super.userData, + required super.parentImages, + required super.mediaStreams, + required super.canDownload, + required super.canDelete, + super.jellyType, + }); + @override + String? detailedName(BuildContext context) => "$name${overview.yearAired != null ? " (${overview.yearAired})" : ""}"; + + @override + Widget get detailScreenWidget => MovieDetailScreen(item: this); + + @override + ItemBaseModel get parentBaseModel => this; + + @override + String? get subText => overview.yearAired?.toString() ?? overview.runTime.humanize; + + @override + bool get playAble => true; + + @override + bool get identifiable => true; + + @override + String? label(BuildContext context) => + overview.yearAired == null ? overview.runTime.humanize : "$name (${overview.yearAired})"; + + @override + ImageData? get bannerImage => images?.backDrop?.firstOrNull ?? images?.primary ?? getPosters?.primary; + + @override + MediaStreamsModel? get streamModel => mediaStreams; + + @override + bool get syncAble => true; + + factory MovieModel.fromBaseDto(dto.BaseItemDto item, Ref ref) { + return MovieModel( + name: item.name ?? "", + id: item.id ?? "", + childCount: item.childCount, + overview: OverviewModel.fromBaseItemDto(item, ref), + userData: UserData.fromDto(item.userData), + parentId: item.parentId, + playlistId: item.playlistItemId, + sortName: item.sortName ?? "", + status: item.status ?? "", + originalTitle: item.originalTitle ?? "", + images: ImagesData.fromBaseItem(item, ref), + primaryRatio: item.primaryImageAspectRatio, + chapters: Chapter.chaptersFromInfo(item.id ?? "", item.chapters ?? [], ref), + premiereDate: item.premiereDate ?? DateTime.now(), + parentImages: ImagesData.fromBaseItemParent(item, ref), + canDelete: item.canDelete, + canDownload: item.canDownload, + mediaStreams: + MediaStreamsModel.fromMediaStreamsList(item.mediaSources?.firstOrNull, item.mediaStreams ?? [], ref), + ); + } +} diff --git a/lib/models/items/movie_model.mapper.dart b/lib/models/items/movie_model.mapper.dart new file mode 100644 index 0000000..56b8f4c --- /dev/null +++ b/lib/models/items/movie_model.mapper.dart @@ -0,0 +1,318 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member +// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter + +part of 'movie_model.dart'; + +class MovieModelMapper extends SubClassMapperBase { + MovieModelMapper._(); + + static MovieModelMapper? _instance; + static MovieModelMapper ensureInitialized() { + if (_instance == null) { + MapperContainer.globals.use(_instance = MovieModelMapper._()); + ItemStreamModelMapper.ensureInitialized().addSubMapper(_instance!); + ItemBaseModelMapper.ensureInitialized(); + OverviewModelMapper.ensureInitialized(); + UserDataMapper.ensureInitialized(); + } + return _instance!; + } + + @override + final String id = 'MovieModel'; + + static String _$originalTitle(MovieModel v) => v.originalTitle; + static const Field _f$originalTitle = + Field('originalTitle', _$originalTitle); + static String? _$path(MovieModel v) => v.path; + static const Field _f$path = + Field('path', _$path, opt: true); + static List _$chapters(MovieModel v) => v.chapters; + static const Field> _f$chapters = + Field('chapters', _$chapters, opt: true, def: const []); + static DateTime _$premiereDate(MovieModel v) => v.premiereDate; + static const Field _f$premiereDate = + Field('premiereDate', _$premiereDate); + static String _$sortName(MovieModel v) => v.sortName; + static const Field _f$sortName = + Field('sortName', _$sortName); + static String _$status(MovieModel v) => v.status; + static const Field _f$status = Field('status', _$status); + static List _$related(MovieModel v) => v.related; + static const Field> _f$related = + Field('related', _$related, opt: true, def: const []); + static String _$name(MovieModel v) => v.name; + static const Field _f$name = Field('name', _$name); + static String _$id(MovieModel v) => v.id; + static const Field _f$id = Field('id', _$id); + static OverviewModel _$overview(MovieModel v) => v.overview; + static const Field _f$overview = + Field('overview', _$overview); + static String? _$parentId(MovieModel v) => v.parentId; + static const Field _f$parentId = + Field('parentId', _$parentId); + static String? _$playlistId(MovieModel v) => v.playlistId; + static const Field _f$playlistId = + Field('playlistId', _$playlistId); + static ImagesData? _$images(MovieModel v) => v.images; + static const Field _f$images = + Field('images', _$images); + static int? _$childCount(MovieModel v) => v.childCount; + static const Field _f$childCount = + Field('childCount', _$childCount); + static double? _$primaryRatio(MovieModel v) => v.primaryRatio; + static const Field _f$primaryRatio = + Field('primaryRatio', _$primaryRatio); + static UserData _$userData(MovieModel v) => v.userData; + static const Field _f$userData = + Field('userData', _$userData); + static ImagesData? _$parentImages(MovieModel v) => v.parentImages; + static const Field _f$parentImages = + Field('parentImages', _$parentImages); + static MediaStreamsModel _$mediaStreams(MovieModel v) => v.mediaStreams; + static const Field _f$mediaStreams = + Field('mediaStreams', _$mediaStreams); + static bool? _$canDownload(MovieModel v) => v.canDownload; + static const Field _f$canDownload = + Field('canDownload', _$canDownload); + static bool? _$canDelete(MovieModel v) => v.canDelete; + static const Field _f$canDelete = + Field('canDelete', _$canDelete); + static dto.BaseItemKind? _$jellyType(MovieModel v) => v.jellyType; + static const Field _f$jellyType = + Field('jellyType', _$jellyType, opt: true); + + @override + final MappableFields fields = const { + #originalTitle: _f$originalTitle, + #path: _f$path, + #chapters: _f$chapters, + #premiereDate: _f$premiereDate, + #sortName: _f$sortName, + #status: _f$status, + #related: _f$related, + #name: _f$name, + #id: _f$id, + #overview: _f$overview, + #parentId: _f$parentId, + #playlistId: _f$playlistId, + #images: _f$images, + #childCount: _f$childCount, + #primaryRatio: _f$primaryRatio, + #userData: _f$userData, + #parentImages: _f$parentImages, + #mediaStreams: _f$mediaStreams, + #canDownload: _f$canDownload, + #canDelete: _f$canDelete, + #jellyType: _f$jellyType, + }; + @override + final bool ignoreNull = true; + + @override + final String discriminatorKey = 'type'; + @override + final dynamic discriminatorValue = 'MovieModel'; + @override + late final ClassMapperBase superMapper = + ItemStreamModelMapper.ensureInitialized(); + + static MovieModel _instantiate(DecodingData data) { + return MovieModel( + originalTitle: data.dec(_f$originalTitle), + path: data.dec(_f$path), + chapters: data.dec(_f$chapters), + premiereDate: data.dec(_f$premiereDate), + sortName: data.dec(_f$sortName), + status: data.dec(_f$status), + related: data.dec(_f$related), + name: data.dec(_f$name), + id: data.dec(_f$id), + overview: data.dec(_f$overview), + parentId: data.dec(_f$parentId), + playlistId: data.dec(_f$playlistId), + images: data.dec(_f$images), + childCount: data.dec(_f$childCount), + primaryRatio: data.dec(_f$primaryRatio), + userData: data.dec(_f$userData), + parentImages: data.dec(_f$parentImages), + mediaStreams: data.dec(_f$mediaStreams), + canDownload: data.dec(_f$canDownload), + canDelete: data.dec(_f$canDelete), + jellyType: data.dec(_f$jellyType)); + } + + @override + final Function instantiate = _instantiate; + + static MovieModel fromMap(Map map) { + return ensureInitialized().decodeMap(map); + } + + static MovieModel fromJson(String json) { + return ensureInitialized().decodeJson(json); + } +} + +mixin MovieModelMappable { + String toJson() { + return MovieModelMapper.ensureInitialized() + .encodeJson(this as MovieModel); + } + + Map toMap() { + return MovieModelMapper.ensureInitialized() + .encodeMap(this as MovieModel); + } + + MovieModelCopyWith get copyWith => + _MovieModelCopyWithImpl(this as MovieModel, $identity, $identity); + @override + String toString() { + return MovieModelMapper.ensureInitialized() + .stringifyValue(this as MovieModel); + } +} + +extension MovieModelValueCopy<$R, $Out> + on ObjectCopyWith<$R, MovieModel, $Out> { + MovieModelCopyWith<$R, MovieModel, $Out> get $asMovieModel => + $base.as((v, t, t2) => _MovieModelCopyWithImpl(v, t, t2)); +} + +abstract class MovieModelCopyWith<$R, $In extends MovieModel, $Out> + implements ItemStreamModelCopyWith<$R, $In, $Out> { + ListCopyWith<$R, Chapter, ObjectCopyWith<$R, Chapter, Chapter>> get chapters; + ListCopyWith<$R, ItemBaseModel, + ItemBaseModelCopyWith<$R, ItemBaseModel, ItemBaseModel>> get related; + @override + OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview; + @override + UserDataCopyWith<$R, UserData, UserData> get userData; + @override + $R call( + {String? originalTitle, + String? path, + List? chapters, + DateTime? premiereDate, + String? sortName, + String? status, + List? related, + String? name, + String? id, + OverviewModel? overview, + String? parentId, + String? playlistId, + ImagesData? images, + int? childCount, + double? primaryRatio, + UserData? userData, + ImagesData? parentImages, + MediaStreamsModel? mediaStreams, + bool? canDownload, + bool? canDelete, + dto.BaseItemKind? jellyType}); + MovieModelCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t); +} + +class _MovieModelCopyWithImpl<$R, $Out> + extends ClassCopyWithBase<$R, MovieModel, $Out> + implements MovieModelCopyWith<$R, MovieModel, $Out> { + _MovieModelCopyWithImpl(super.value, super.then, super.then2); + + @override + late final ClassMapperBase $mapper = + MovieModelMapper.ensureInitialized(); + @override + ListCopyWith<$R, Chapter, ObjectCopyWith<$R, Chapter, Chapter>> + get chapters => ListCopyWith($value.chapters, + (v, t) => ObjectCopyWith(v, $identity, t), (v) => call(chapters: v)); + @override + ListCopyWith<$R, ItemBaseModel, + ItemBaseModelCopyWith<$R, ItemBaseModel, ItemBaseModel>> + get related => ListCopyWith($value.related, + (v, t) => v.copyWith.$chain(t), (v) => call(related: v)); + @override + OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview => + $value.overview.copyWith.$chain((v) => call(overview: v)); + @override + UserDataCopyWith<$R, UserData, UserData> get userData => + $value.userData.copyWith.$chain((v) => call(userData: v)); + @override + $R call( + {String? originalTitle, + Object? path = $none, + List? chapters, + DateTime? premiereDate, + String? sortName, + String? status, + List? related, + String? name, + String? id, + OverviewModel? overview, + Object? parentId = $none, + Object? playlistId = $none, + Object? images = $none, + Object? childCount = $none, + Object? primaryRatio = $none, + UserData? userData, + Object? parentImages = $none, + MediaStreamsModel? mediaStreams, + Object? canDownload = $none, + Object? canDelete = $none, + Object? jellyType = $none}) => + $apply(FieldCopyWithData({ + if (originalTitle != null) #originalTitle: originalTitle, + if (path != $none) #path: path, + if (chapters != null) #chapters: chapters, + if (premiereDate != null) #premiereDate: premiereDate, + if (sortName != null) #sortName: sortName, + if (status != null) #status: status, + if (related != null) #related: related, + if (name != null) #name: name, + if (id != null) #id: id, + if (overview != null) #overview: overview, + if (parentId != $none) #parentId: parentId, + if (playlistId != $none) #playlistId: playlistId, + if (images != $none) #images: images, + if (childCount != $none) #childCount: childCount, + if (primaryRatio != $none) #primaryRatio: primaryRatio, + if (userData != null) #userData: userData, + if (parentImages != $none) #parentImages: parentImages, + if (mediaStreams != null) #mediaStreams: mediaStreams, + if (canDownload != $none) #canDownload: canDownload, + if (canDelete != $none) #canDelete: canDelete, + if (jellyType != $none) #jellyType: jellyType + })); + @override + MovieModel $make(CopyWithData data) => MovieModel( + originalTitle: data.get(#originalTitle, or: $value.originalTitle), + path: data.get(#path, or: $value.path), + chapters: data.get(#chapters, or: $value.chapters), + premiereDate: data.get(#premiereDate, or: $value.premiereDate), + sortName: data.get(#sortName, or: $value.sortName), + status: data.get(#status, or: $value.status), + related: data.get(#related, or: $value.related), + name: data.get(#name, or: $value.name), + id: data.get(#id, or: $value.id), + overview: data.get(#overview, or: $value.overview), + parentId: data.get(#parentId, or: $value.parentId), + playlistId: data.get(#playlistId, or: $value.playlistId), + images: data.get(#images, or: $value.images), + childCount: data.get(#childCount, or: $value.childCount), + primaryRatio: data.get(#primaryRatio, or: $value.primaryRatio), + userData: data.get(#userData, or: $value.userData), + parentImages: data.get(#parentImages, or: $value.parentImages), + mediaStreams: data.get(#mediaStreams, or: $value.mediaStreams), + canDownload: data.get(#canDownload, or: $value.canDownload), + canDelete: data.get(#canDelete, or: $value.canDelete), + jellyType: data.get(#jellyType, or: $value.jellyType)); + + @override + MovieModelCopyWith<$R2, MovieModel, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t) => + _MovieModelCopyWithImpl($value, $cast, t); +} diff --git a/lib/models/items/overview_model.dart b/lib/models/items/overview_model.dart new file mode 100644 index 0000000..6747026 --- /dev/null +++ b/lib/models/items/overview_model.dart @@ -0,0 +1,82 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/items/chapters_model.dart'; +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/models/items/trick_play_model.dart'; +import 'package:fladder/util/duration_extensions.dart'; + +import 'package:dart_mappable/dart_mappable.dart'; + +part 'overview_model.mapper.dart'; + +@MappableClass() +class OverviewModel with OverviewModelMappable { + final Duration? runTime; + final String summary; + final int? yearAired; + final DateTime? dateAdded; + final String? parentalRating; + final int? productionYear; + final double? criticRating; + final double? communityRating; + final Map? trickPlayInfo; + final List? chapters; + final List? externalUrls; + final List studios; + final List genres; + final List genreItems; + final List tags; + final List people; + const OverviewModel({ + this.runTime, + this.summary = "", + this.yearAired, + this.dateAdded, + this.parentalRating, + this.productionYear, + this.criticRating, + this.communityRating, + this.trickPlayInfo, + this.chapters, + this.externalUrls, + this.studios = const [], + this.genres = const [], + this.genreItems = const [], + this.tags = const [], + this.people = const [], + }); + + List get directors { + return people.where((element) => element.type == PersonKind.director).toList(); + } + + List get writers { + return people.where((element) => element.type == PersonKind.writer).toList(); + } + + factory OverviewModel.fromBaseItemDto(BaseItemDto item, Ref ref) { + final trickPlayItem = item.trickplay; + return OverviewModel( + runTime: item.runTimeDuration, + yearAired: item.productionYear, + parentalRating: item.officialRating, + summary: item.overview ?? "", + genres: item.genres ?? [], + criticRating: item.criticRating, + communityRating: item.communityRating, + tags: item.tags ?? [], + dateAdded: item.dateCreated, + trickPlayInfo: + trickPlayItem != null && trickPlayItem.isNotEmpty ? TrickPlayModel.toTrickPlayMap(trickPlayItem) : null, + chapters: item.id != null ? Chapter.chaptersFromInfo(item.id ?? "", item.chapters ?? [], ref) : null, + studios: item.studios?.map((e) => Studio(id: e.id ?? "", name: e.name ?? "")).toList() ?? [], + genreItems: item.genreItems?.map((e) => GenreItems(id: e.id ?? "", name: e.name ?? "")).toList() ?? [], + externalUrls: ExternalUrls.fromDto(item.externalUrls ?? []), + people: Person.peopleFromDto(item.people ?? [], ref), + ); + } + + factory OverviewModel.fromMap(Map map) => OverviewModelMapper.fromMap(map); + factory OverviewModel.fromJson(String json) => OverviewModelMapper.fromJson(json); +} diff --git a/lib/models/items/overview_model.mapper.dart b/lib/models/items/overview_model.mapper.dart new file mode 100644 index 0000000..9afaf5b --- /dev/null +++ b/lib/models/items/overview_model.mapper.dart @@ -0,0 +1,302 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member +// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter + +part of 'overview_model.dart'; + +class OverviewModelMapper extends ClassMapperBase { + OverviewModelMapper._(); + + static OverviewModelMapper? _instance; + static OverviewModelMapper ensureInitialized() { + if (_instance == null) { + MapperContainer.globals.use(_instance = OverviewModelMapper._()); + } + return _instance!; + } + + @override + final String id = 'OverviewModel'; + + static Duration? _$runTime(OverviewModel v) => v.runTime; + static const Field _f$runTime = + Field('runTime', _$runTime, opt: true); + static String _$summary(OverviewModel v) => v.summary; + static const Field _f$summary = + Field('summary', _$summary, opt: true, def: ""); + static int? _$yearAired(OverviewModel v) => v.yearAired; + static const Field _f$yearAired = + Field('yearAired', _$yearAired, opt: true); + static DateTime? _$dateAdded(OverviewModel v) => v.dateAdded; + static const Field _f$dateAdded = + Field('dateAdded', _$dateAdded, opt: true); + static String? _$parentalRating(OverviewModel v) => v.parentalRating; + static const Field _f$parentalRating = + Field('parentalRating', _$parentalRating, opt: true); + static int? _$productionYear(OverviewModel v) => v.productionYear; + static const Field _f$productionYear = + Field('productionYear', _$productionYear, opt: true); + static double? _$criticRating(OverviewModel v) => v.criticRating; + static const Field _f$criticRating = + Field('criticRating', _$criticRating, opt: true); + static double? _$communityRating(OverviewModel v) => v.communityRating; + static const Field _f$communityRating = + Field('communityRating', _$communityRating, opt: true); + static Map? _$trickPlayInfo(OverviewModel v) => + v.trickPlayInfo; + static const Field> + _f$trickPlayInfo = Field('trickPlayInfo', _$trickPlayInfo, opt: true); + static List? _$chapters(OverviewModel v) => v.chapters; + static const Field> _f$chapters = + Field('chapters', _$chapters, opt: true); + static List? _$externalUrls(OverviewModel v) => v.externalUrls; + static const Field> _f$externalUrls = + Field('externalUrls', _$externalUrls, opt: true); + static List _$studios(OverviewModel v) => v.studios; + static const Field> _f$studios = + Field('studios', _$studios, opt: true, def: const []); + static List _$genres(OverviewModel v) => v.genres; + static const Field> _f$genres = + Field('genres', _$genres, opt: true, def: const []); + static List _$genreItems(OverviewModel v) => v.genreItems; + static const Field> _f$genreItems = + Field('genreItems', _$genreItems, opt: true, def: const []); + static List _$tags(OverviewModel v) => v.tags; + static const Field> _f$tags = + Field('tags', _$tags, opt: true, def: const []); + static List _$people(OverviewModel v) => v.people; + static const Field> _f$people = + Field('people', _$people, opt: true, def: const []); + + @override + final MappableFields fields = const { + #runTime: _f$runTime, + #summary: _f$summary, + #yearAired: _f$yearAired, + #dateAdded: _f$dateAdded, + #parentalRating: _f$parentalRating, + #productionYear: _f$productionYear, + #criticRating: _f$criticRating, + #communityRating: _f$communityRating, + #trickPlayInfo: _f$trickPlayInfo, + #chapters: _f$chapters, + #externalUrls: _f$externalUrls, + #studios: _f$studios, + #genres: _f$genres, + #genreItems: _f$genreItems, + #tags: _f$tags, + #people: _f$people, + }; + @override + final bool ignoreNull = true; + + static OverviewModel _instantiate(DecodingData data) { + return OverviewModel( + runTime: data.dec(_f$runTime), + summary: data.dec(_f$summary), + yearAired: data.dec(_f$yearAired), + dateAdded: data.dec(_f$dateAdded), + parentalRating: data.dec(_f$parentalRating), + productionYear: data.dec(_f$productionYear), + criticRating: data.dec(_f$criticRating), + communityRating: data.dec(_f$communityRating), + trickPlayInfo: data.dec(_f$trickPlayInfo), + chapters: data.dec(_f$chapters), + externalUrls: data.dec(_f$externalUrls), + studios: data.dec(_f$studios), + genres: data.dec(_f$genres), + genreItems: data.dec(_f$genreItems), + tags: data.dec(_f$tags), + people: data.dec(_f$people)); + } + + @override + final Function instantiate = _instantiate; + + static OverviewModel fromMap(Map map) { + return ensureInitialized().decodeMap(map); + } + + static OverviewModel fromJson(String json) { + return ensureInitialized().decodeJson(json); + } +} + +mixin OverviewModelMappable { + String toJson() { + return OverviewModelMapper.ensureInitialized() + .encodeJson(this as OverviewModel); + } + + Map toMap() { + return OverviewModelMapper.ensureInitialized() + .encodeMap(this as OverviewModel); + } + + OverviewModelCopyWith + get copyWith => _OverviewModelCopyWithImpl( + this as OverviewModel, $identity, $identity); + @override + String toString() { + return OverviewModelMapper.ensureInitialized() + .stringifyValue(this as OverviewModel); + } +} + +extension OverviewModelValueCopy<$R, $Out> + on ObjectCopyWith<$R, OverviewModel, $Out> { + OverviewModelCopyWith<$R, OverviewModel, $Out> get $asOverviewModel => + $base.as((v, t, t2) => _OverviewModelCopyWithImpl(v, t, t2)); +} + +abstract class OverviewModelCopyWith<$R, $In extends OverviewModel, $Out> + implements ClassCopyWith<$R, $In, $Out> { + MapCopyWith<$R, String, TrickPlayModel, + ObjectCopyWith<$R, TrickPlayModel, TrickPlayModel>>? get trickPlayInfo; + ListCopyWith<$R, Chapter, ObjectCopyWith<$R, Chapter, Chapter>>? get chapters; + ListCopyWith<$R, ExternalUrls, + ObjectCopyWith<$R, ExternalUrls, ExternalUrls>>? get externalUrls; + ListCopyWith<$R, Studio, ObjectCopyWith<$R, Studio, Studio>> get studios; + ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>> get genres; + ListCopyWith<$R, GenreItems, ObjectCopyWith<$R, GenreItems, GenreItems>> + get genreItems; + ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>> get tags; + ListCopyWith<$R, Person, ObjectCopyWith<$R, Person, Person>> get people; + $R call( + {Duration? runTime, + String? summary, + int? yearAired, + DateTime? dateAdded, + String? parentalRating, + int? productionYear, + double? criticRating, + double? communityRating, + Map? trickPlayInfo, + List? chapters, + List? externalUrls, + List? studios, + List? genres, + List? genreItems, + List? tags, + List? people}); + OverviewModelCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t); +} + +class _OverviewModelCopyWithImpl<$R, $Out> + extends ClassCopyWithBase<$R, OverviewModel, $Out> + implements OverviewModelCopyWith<$R, OverviewModel, $Out> { + _OverviewModelCopyWithImpl(super.value, super.then, super.then2); + + @override + late final ClassMapperBase $mapper = + OverviewModelMapper.ensureInitialized(); + @override + MapCopyWith<$R, String, TrickPlayModel, + ObjectCopyWith<$R, TrickPlayModel, TrickPlayModel>>? + get trickPlayInfo => $value.trickPlayInfo != null + ? MapCopyWith( + $value.trickPlayInfo!, + (v, t) => ObjectCopyWith(v, $identity, t), + (v) => call(trickPlayInfo: v)) + : null; + @override + ListCopyWith<$R, Chapter, ObjectCopyWith<$R, Chapter, Chapter>>? + get chapters => $value.chapters != null + ? ListCopyWith( + $value.chapters!, + (v, t) => ObjectCopyWith(v, $identity, t), + (v) => call(chapters: v)) + : null; + @override + ListCopyWith<$R, ExternalUrls, + ObjectCopyWith<$R, ExternalUrls, ExternalUrls>>? + get externalUrls => $value.externalUrls != null + ? ListCopyWith( + $value.externalUrls!, + (v, t) => ObjectCopyWith(v, $identity, t), + (v) => call(externalUrls: v)) + : null; + @override + ListCopyWith<$R, Studio, ObjectCopyWith<$R, Studio, Studio>> get studios => + ListCopyWith($value.studios, (v, t) => ObjectCopyWith(v, $identity, t), + (v) => call(studios: v)); + @override + ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>> get genres => + ListCopyWith($value.genres, (v, t) => ObjectCopyWith(v, $identity, t), + (v) => call(genres: v)); + @override + ListCopyWith<$R, GenreItems, ObjectCopyWith<$R, GenreItems, GenreItems>> + get genreItems => ListCopyWith( + $value.genreItems, + (v, t) => ObjectCopyWith(v, $identity, t), + (v) => call(genreItems: v)); + @override + ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>> get tags => + ListCopyWith($value.tags, (v, t) => ObjectCopyWith(v, $identity, t), + (v) => call(tags: v)); + @override + ListCopyWith<$R, Person, ObjectCopyWith<$R, Person, Person>> get people => + ListCopyWith($value.people, (v, t) => ObjectCopyWith(v, $identity, t), + (v) => call(people: v)); + @override + $R call( + {Object? runTime = $none, + String? summary, + Object? yearAired = $none, + Object? dateAdded = $none, + Object? parentalRating = $none, + Object? productionYear = $none, + Object? criticRating = $none, + Object? communityRating = $none, + Object? trickPlayInfo = $none, + Object? chapters = $none, + Object? externalUrls = $none, + List? studios, + List? genres, + List? genreItems, + List? tags, + List? people}) => + $apply(FieldCopyWithData({ + if (runTime != $none) #runTime: runTime, + if (summary != null) #summary: summary, + if (yearAired != $none) #yearAired: yearAired, + if (dateAdded != $none) #dateAdded: dateAdded, + if (parentalRating != $none) #parentalRating: parentalRating, + if (productionYear != $none) #productionYear: productionYear, + if (criticRating != $none) #criticRating: criticRating, + if (communityRating != $none) #communityRating: communityRating, + if (trickPlayInfo != $none) #trickPlayInfo: trickPlayInfo, + if (chapters != $none) #chapters: chapters, + if (externalUrls != $none) #externalUrls: externalUrls, + if (studios != null) #studios: studios, + if (genres != null) #genres: genres, + if (genreItems != null) #genreItems: genreItems, + if (tags != null) #tags: tags, + if (people != null) #people: people + })); + @override + OverviewModel $make(CopyWithData data) => OverviewModel( + runTime: data.get(#runTime, or: $value.runTime), + summary: data.get(#summary, or: $value.summary), + yearAired: data.get(#yearAired, or: $value.yearAired), + dateAdded: data.get(#dateAdded, or: $value.dateAdded), + parentalRating: data.get(#parentalRating, or: $value.parentalRating), + productionYear: data.get(#productionYear, or: $value.productionYear), + criticRating: data.get(#criticRating, or: $value.criticRating), + communityRating: data.get(#communityRating, or: $value.communityRating), + trickPlayInfo: data.get(#trickPlayInfo, or: $value.trickPlayInfo), + chapters: data.get(#chapters, or: $value.chapters), + externalUrls: data.get(#externalUrls, or: $value.externalUrls), + studios: data.get(#studios, or: $value.studios), + genres: data.get(#genres, or: $value.genres), + genreItems: data.get(#genreItems, or: $value.genreItems), + tags: data.get(#tags, or: $value.tags), + people: data.get(#people, or: $value.people)); + + @override + OverviewModelCopyWith<$R2, OverviewModel, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t) => + _OverviewModelCopyWithImpl($value, $cast, t); +} diff --git a/lib/models/items/person_model.dart b/lib/models/items/person_model.dart new file mode 100644 index 0000000..ebbaf2a --- /dev/null +++ b/lib/models/items/person_model.dart @@ -0,0 +1,68 @@ +import 'package:fladder/models/items/images_models.dart'; +import 'package:fladder/models/items/overview_model.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/models/items/movie_model.dart'; +import 'package:fladder/models/items/series_model.dart'; + +import 'package:dart_mappable/dart_mappable.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +part 'person_model.mapper.dart'; + +@MappableClass() +class PersonModel extends ItemBaseModel with PersonModelMappable { + final DateTime? dateOfBirth; + final List birthPlace; + final List movies; + final List series; + const PersonModel({ + this.dateOfBirth, + required this.birthPlace, + required this.movies, + required this.series, + required super.name, + required super.id, + required super.overview, + required super.parentId, + required super.playlistId, + required super.images, + required super.childCount, + required super.primaryRatio, + required super.userData, + super.canDownload, + super.canDelete, + super.jellyType, + }); + + static PersonModel fromBaseDto(BaseItemDto item, Ref ref) { + return PersonModel( + name: item.name ?? "", + id: item.id ?? "", + childCount: item.childCount, + overview: OverviewModel.fromBaseItemDto(item, ref), + userData: UserData.fromDto(item.userData), + parentId: item.parentId, + playlistId: item.playlistItemId, + images: ImagesData.fromBaseItem(item, ref, getOriginalSize: true), + primaryRatio: item.primaryImageAspectRatio, + dateOfBirth: item.premiereDate, + birthPlace: item.productionLocations ?? [], + movies: [], + series: [], + ); + } + + int? get age { + if (dateOfBirth == null) return null; + final today = DateTime.now(); + final months = today.month - dateOfBirth!.month; + if (months < 0) { + return (dateOfBirth!.year - (DateTime.now().year - 1)).abs(); + } else { + return (dateOfBirth!.year - DateTime.now().year).abs(); + } + } +} diff --git a/lib/models/items/person_model.mapper.dart b/lib/models/items/person_model.mapper.dart new file mode 100644 index 0000000..2577548 --- /dev/null +++ b/lib/models/items/person_model.mapper.dart @@ -0,0 +1,281 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member +// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter + +part of 'person_model.dart'; + +class PersonModelMapper extends SubClassMapperBase { + PersonModelMapper._(); + + static PersonModelMapper? _instance; + static PersonModelMapper ensureInitialized() { + if (_instance == null) { + MapperContainer.globals.use(_instance = PersonModelMapper._()); + ItemBaseModelMapper.ensureInitialized().addSubMapper(_instance!); + MovieModelMapper.ensureInitialized(); + SeriesModelMapper.ensureInitialized(); + OverviewModelMapper.ensureInitialized(); + UserDataMapper.ensureInitialized(); + } + return _instance!; + } + + @override + final String id = 'PersonModel'; + + static DateTime? _$dateOfBirth(PersonModel v) => v.dateOfBirth; + static const Field _f$dateOfBirth = + Field('dateOfBirth', _$dateOfBirth, opt: true); + static List _$birthPlace(PersonModel v) => v.birthPlace; + static const Field> _f$birthPlace = + Field('birthPlace', _$birthPlace); + static List _$movies(PersonModel v) => v.movies; + static const Field> _f$movies = + Field('movies', _$movies); + static List _$series(PersonModel v) => v.series; + static const Field> _f$series = + Field('series', _$series); + static String _$name(PersonModel v) => v.name; + static const Field _f$name = Field('name', _$name); + static String _$id(PersonModel v) => v.id; + static const Field _f$id = Field('id', _$id); + static OverviewModel _$overview(PersonModel v) => v.overview; + static const Field _f$overview = + Field('overview', _$overview); + static String? _$parentId(PersonModel v) => v.parentId; + static const Field _f$parentId = + Field('parentId', _$parentId); + static String? _$playlistId(PersonModel v) => v.playlistId; + static const Field _f$playlistId = + Field('playlistId', _$playlistId); + static ImagesData? _$images(PersonModel v) => v.images; + static const Field _f$images = + Field('images', _$images); + static int? _$childCount(PersonModel v) => v.childCount; + static const Field _f$childCount = + Field('childCount', _$childCount); + static double? _$primaryRatio(PersonModel v) => v.primaryRatio; + static const Field _f$primaryRatio = + Field('primaryRatio', _$primaryRatio); + static UserData _$userData(PersonModel v) => v.userData; + static const Field _f$userData = + Field('userData', _$userData); + static bool? _$canDownload(PersonModel v) => v.canDownload; + static const Field _f$canDownload = + Field('canDownload', _$canDownload, opt: true); + static bool? _$canDelete(PersonModel v) => v.canDelete; + static const Field _f$canDelete = + Field('canDelete', _$canDelete, opt: true); + static BaseItemKind? _$jellyType(PersonModel v) => v.jellyType; + static const Field _f$jellyType = + Field('jellyType', _$jellyType, opt: true); + + @override + final MappableFields fields = const { + #dateOfBirth: _f$dateOfBirth, + #birthPlace: _f$birthPlace, + #movies: _f$movies, + #series: _f$series, + #name: _f$name, + #id: _f$id, + #overview: _f$overview, + #parentId: _f$parentId, + #playlistId: _f$playlistId, + #images: _f$images, + #childCount: _f$childCount, + #primaryRatio: _f$primaryRatio, + #userData: _f$userData, + #canDownload: _f$canDownload, + #canDelete: _f$canDelete, + #jellyType: _f$jellyType, + }; + @override + final bool ignoreNull = true; + + @override + final String discriminatorKey = 'type'; + @override + final dynamic discriminatorValue = 'PersonModel'; + @override + late final ClassMapperBase superMapper = + ItemBaseModelMapper.ensureInitialized(); + + static PersonModel _instantiate(DecodingData data) { + return PersonModel( + dateOfBirth: data.dec(_f$dateOfBirth), + birthPlace: data.dec(_f$birthPlace), + movies: data.dec(_f$movies), + series: data.dec(_f$series), + name: data.dec(_f$name), + id: data.dec(_f$id), + overview: data.dec(_f$overview), + parentId: data.dec(_f$parentId), + playlistId: data.dec(_f$playlistId), + images: data.dec(_f$images), + childCount: data.dec(_f$childCount), + primaryRatio: data.dec(_f$primaryRatio), + userData: data.dec(_f$userData), + canDownload: data.dec(_f$canDownload), + canDelete: data.dec(_f$canDelete), + jellyType: data.dec(_f$jellyType)); + } + + @override + final Function instantiate = _instantiate; + + static PersonModel fromMap(Map map) { + return ensureInitialized().decodeMap(map); + } + + static PersonModel fromJson(String json) { + return ensureInitialized().decodeJson(json); + } +} + +mixin PersonModelMappable { + String toJson() { + return PersonModelMapper.ensureInitialized() + .encodeJson(this as PersonModel); + } + + Map toMap() { + return PersonModelMapper.ensureInitialized() + .encodeMap(this as PersonModel); + } + + PersonModelCopyWith get copyWith => + _PersonModelCopyWithImpl(this as PersonModel, $identity, $identity); + @override + String toString() { + return PersonModelMapper.ensureInitialized() + .stringifyValue(this as PersonModel); + } +} + +extension PersonModelValueCopy<$R, $Out> + on ObjectCopyWith<$R, PersonModel, $Out> { + PersonModelCopyWith<$R, PersonModel, $Out> get $asPersonModel => + $base.as((v, t, t2) => _PersonModelCopyWithImpl(v, t, t2)); +} + +abstract class PersonModelCopyWith<$R, $In extends PersonModel, $Out> + implements ItemBaseModelCopyWith<$R, $In, $Out> { + ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>> get birthPlace; + ListCopyWith<$R, MovieModel, MovieModelCopyWith<$R, MovieModel, MovieModel>> + get movies; + ListCopyWith<$R, SeriesModel, + SeriesModelCopyWith<$R, SeriesModel, SeriesModel>> get series; + @override + OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview; + @override + UserDataCopyWith<$R, UserData, UserData> get userData; + @override + $R call( + {DateTime? dateOfBirth, + List? birthPlace, + List? movies, + List? series, + String? name, + String? id, + OverviewModel? overview, + String? parentId, + String? playlistId, + ImagesData? images, + int? childCount, + double? primaryRatio, + UserData? userData, + bool? canDownload, + bool? canDelete, + BaseItemKind? jellyType}); + PersonModelCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t); +} + +class _PersonModelCopyWithImpl<$R, $Out> + extends ClassCopyWithBase<$R, PersonModel, $Out> + implements PersonModelCopyWith<$R, PersonModel, $Out> { + _PersonModelCopyWithImpl(super.value, super.then, super.then2); + + @override + late final ClassMapperBase $mapper = + PersonModelMapper.ensureInitialized(); + @override + ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>> get birthPlace => + ListCopyWith($value.birthPlace, (v, t) => ObjectCopyWith(v, $identity, t), + (v) => call(birthPlace: v)); + @override + ListCopyWith<$R, MovieModel, MovieModelCopyWith<$R, MovieModel, MovieModel>> + get movies => ListCopyWith($value.movies, (v, t) => v.copyWith.$chain(t), + (v) => call(movies: v)); + @override + ListCopyWith<$R, SeriesModel, + SeriesModelCopyWith<$R, SeriesModel, SeriesModel>> + get series => ListCopyWith($value.series, (v, t) => v.copyWith.$chain(t), + (v) => call(series: v)); + @override + OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview => + $value.overview.copyWith.$chain((v) => call(overview: v)); + @override + UserDataCopyWith<$R, UserData, UserData> get userData => + $value.userData.copyWith.$chain((v) => call(userData: v)); + @override + $R call( + {Object? dateOfBirth = $none, + List? birthPlace, + List? movies, + List? series, + String? name, + String? id, + OverviewModel? overview, + Object? parentId = $none, + Object? playlistId = $none, + Object? images = $none, + Object? childCount = $none, + Object? primaryRatio = $none, + UserData? userData, + Object? canDownload = $none, + Object? canDelete = $none, + Object? jellyType = $none}) => + $apply(FieldCopyWithData({ + if (dateOfBirth != $none) #dateOfBirth: dateOfBirth, + if (birthPlace != null) #birthPlace: birthPlace, + if (movies != null) #movies: movies, + if (series != null) #series: series, + if (name != null) #name: name, + if (id != null) #id: id, + if (overview != null) #overview: overview, + if (parentId != $none) #parentId: parentId, + if (playlistId != $none) #playlistId: playlistId, + if (images != $none) #images: images, + if (childCount != $none) #childCount: childCount, + if (primaryRatio != $none) #primaryRatio: primaryRatio, + if (userData != null) #userData: userData, + if (canDownload != $none) #canDownload: canDownload, + if (canDelete != $none) #canDelete: canDelete, + if (jellyType != $none) #jellyType: jellyType + })); + @override + PersonModel $make(CopyWithData data) => PersonModel( + dateOfBirth: data.get(#dateOfBirth, or: $value.dateOfBirth), + birthPlace: data.get(#birthPlace, or: $value.birthPlace), + movies: data.get(#movies, or: $value.movies), + series: data.get(#series, or: $value.series), + name: data.get(#name, or: $value.name), + id: data.get(#id, or: $value.id), + overview: data.get(#overview, or: $value.overview), + parentId: data.get(#parentId, or: $value.parentId), + playlistId: data.get(#playlistId, or: $value.playlistId), + images: data.get(#images, or: $value.images), + childCount: data.get(#childCount, or: $value.childCount), + primaryRatio: data.get(#primaryRatio, or: $value.primaryRatio), + userData: data.get(#userData, or: $value.userData), + canDownload: data.get(#canDownload, or: $value.canDownload), + canDelete: data.get(#canDelete, or: $value.canDelete), + jellyType: data.get(#jellyType, or: $value.jellyType)); + + @override + PersonModelCopyWith<$R2, PersonModel, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t) => + _PersonModelCopyWithImpl($value, $cast, t); +} diff --git a/lib/models/items/photos_model.dart b/lib/models/items/photos_model.dart new file mode 100644 index 0000000..d8b637b --- /dev/null +++ b/lib/models/items/photos_model.dart @@ -0,0 +1,154 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart' as dto; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/images_models.dart'; +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/models/items/overview_model.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/screens/shared/fladder_snackbar.dart'; +import 'package:fladder/util/refresh_state.dart'; + +import 'package:dart_mappable/dart_mappable.dart'; + +part 'photos_model.mapper.dart'; + +@MappableClass() +class PhotoAlbumModel extends ItemBaseModel with PhotoAlbumModelMappable { + final List photos; + + const PhotoAlbumModel({ + required this.photos, + required super.name, + required super.id, + required super.overview, + required super.parentId, + required super.playlistId, + required super.images, + required super.childCount, + required super.primaryRatio, + required super.userData, + super.canDelete, + super.canDownload, + super.jellyType, + }); + @override + bool get unWatched => userData.unPlayedItemCount != 0; + + @override + bool get playAble => true; + + @override + ItemBaseModel get parentBaseModel => copyWith(id: parentId); + + factory PhotoAlbumModel.fromBaseDto(dto.BaseItemDto item, Ref ref) { + return PhotoAlbumModel( + name: item.name ?? "", + id: item.id ?? "", + childCount: item.childCount, + overview: OverviewModel.fromBaseItemDto(item, ref), + userData: UserData.fromDto(item.userData), + parentId: item.parentId, + playlistId: item.playlistItemId, + images: ImagesData.fromBaseItem(item, ref), + primaryRatio: item.primaryImageAspectRatio, + canDelete: item.canDelete, + canDownload: item.canDownload, + photos: [], + ); + } +} + +@MappableClass() +class PhotoModel extends ItemBaseModel with PhotoModelMappable { + final String? albumId; + final DateTime? dateTaken; + final ImagesData? thumbnail; + final FladderItemType internalType; + + const PhotoModel({ + required this.albumId, + required this.dateTaken, + required this.thumbnail, + required this.internalType, + required super.name, + required super.id, + required super.overview, + required super.parentId, + required super.playlistId, + required super.images, + required super.childCount, + required super.primaryRatio, + required super.userData, + required super.canDownload, + required super.canDelete, + super.jellyType, + }); + + @override + PhotoAlbumModel get parentBaseModel => PhotoAlbumModel( + photos: [], + name: "", + id: parentId ?? "", + overview: overview, + parentId: parentId, + playlistId: playlistId, + images: images, + childCount: childCount, + primaryRatio: primaryRatio, + userData: userData, + ); + + @override + ImagesData? get getPosters => thumbnail; + + @override + bool get galleryItem => switch (internalType) { + FladderItemType.photo => albumId?.isNotEmpty == true, + FladderItemType.video => parentId?.isNotEmpty == true, + _ => false, + }; + + @override + bool get unWatched => false; + + factory PhotoModel.fromBaseDto(dto.BaseItemDto item, Ref ref) { + return PhotoModel( + name: item.name ?? "", + id: item.id ?? "", + childCount: item.childCount, + overview: OverviewModel.fromBaseItemDto(item, ref), + userData: UserData.fromDto(item.userData), + parentId: item.parentId, + playlistId: item.playlistItemId, + primaryRatio: double.tryParse(item.aspectRatio ?? "") ?? item.primaryImageAspectRatio ?? 1.0, + dateTaken: item.dateCreated, + albumId: item.albumId, + thumbnail: ImagesData.fromBaseItem(item, ref), + images: ImagesData.fromBaseItem(item, ref, getOriginalSize: true), + canDelete: item.canDelete, + canDownload: item.canDownload, + internalType: switch (item.type) { + BaseItemKind.video => FladderItemType.video, + _ => FladderItemType.photo, + }, + ); + } + + String downloadPath(WidgetRef ref) { + return "${ref.read(userProvider)?.server}/Items/$id/Download?api_key=${ref.read(userProvider)?.credentials.token}"; + } + + Future navigateToAlbum(BuildContext context) async { + if ((albumId ?? parentId) == null) { + fladderSnackbar(context, title: context.localized.notPartOfAlbum); + return; + } + await parentBaseModel.navigateTo(context); + if (context.mounted) context.refreshData(); + } +} diff --git a/lib/models/items/photos_model.mapper.dart b/lib/models/items/photos_model.mapper.dart new file mode 100644 index 0000000..b19c827 --- /dev/null +++ b/lib/models/items/photos_model.mapper.dart @@ -0,0 +1,498 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member +// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter + +part of 'photos_model.dart'; + +class PhotoAlbumModelMapper extends SubClassMapperBase { + PhotoAlbumModelMapper._(); + + static PhotoAlbumModelMapper? _instance; + static PhotoAlbumModelMapper ensureInitialized() { + if (_instance == null) { + MapperContainer.globals.use(_instance = PhotoAlbumModelMapper._()); + ItemBaseModelMapper.ensureInitialized().addSubMapper(_instance!); + ItemBaseModelMapper.ensureInitialized(); + OverviewModelMapper.ensureInitialized(); + UserDataMapper.ensureInitialized(); + } + return _instance!; + } + + @override + final String id = 'PhotoAlbumModel'; + + static List _$photos(PhotoAlbumModel v) => v.photos; + static const Field> _f$photos = + Field('photos', _$photos); + static String _$name(PhotoAlbumModel v) => v.name; + static const Field _f$name = Field('name', _$name); + static String _$id(PhotoAlbumModel v) => v.id; + static const Field _f$id = Field('id', _$id); + static OverviewModel _$overview(PhotoAlbumModel v) => v.overview; + static const Field _f$overview = + Field('overview', _$overview); + static String? _$parentId(PhotoAlbumModel v) => v.parentId; + static const Field _f$parentId = + Field('parentId', _$parentId); + static String? _$playlistId(PhotoAlbumModel v) => v.playlistId; + static const Field _f$playlistId = + Field('playlistId', _$playlistId); + static ImagesData? _$images(PhotoAlbumModel v) => v.images; + static const Field _f$images = + Field('images', _$images); + static int? _$childCount(PhotoAlbumModel v) => v.childCount; + static const Field _f$childCount = + Field('childCount', _$childCount); + static double? _$primaryRatio(PhotoAlbumModel v) => v.primaryRatio; + static const Field _f$primaryRatio = + Field('primaryRatio', _$primaryRatio); + static UserData _$userData(PhotoAlbumModel v) => v.userData; + static const Field _f$userData = + Field('userData', _$userData); + static bool? _$canDelete(PhotoAlbumModel v) => v.canDelete; + static const Field _f$canDelete = + Field('canDelete', _$canDelete, opt: true); + static bool? _$canDownload(PhotoAlbumModel v) => v.canDownload; + static const Field _f$canDownload = + Field('canDownload', _$canDownload, opt: true); + static dto.BaseItemKind? _$jellyType(PhotoAlbumModel v) => v.jellyType; + static const Field _f$jellyType = + Field('jellyType', _$jellyType, opt: true); + + @override + final MappableFields fields = const { + #photos: _f$photos, + #name: _f$name, + #id: _f$id, + #overview: _f$overview, + #parentId: _f$parentId, + #playlistId: _f$playlistId, + #images: _f$images, + #childCount: _f$childCount, + #primaryRatio: _f$primaryRatio, + #userData: _f$userData, + #canDelete: _f$canDelete, + #canDownload: _f$canDownload, + #jellyType: _f$jellyType, + }; + @override + final bool ignoreNull = true; + + @override + final String discriminatorKey = 'type'; + @override + final dynamic discriminatorValue = 'PhotoAlbumModel'; + @override + late final ClassMapperBase superMapper = + ItemBaseModelMapper.ensureInitialized(); + + static PhotoAlbumModel _instantiate(DecodingData data) { + return PhotoAlbumModel( + photos: data.dec(_f$photos), + name: data.dec(_f$name), + id: data.dec(_f$id), + overview: data.dec(_f$overview), + parentId: data.dec(_f$parentId), + playlistId: data.dec(_f$playlistId), + images: data.dec(_f$images), + childCount: data.dec(_f$childCount), + primaryRatio: data.dec(_f$primaryRatio), + userData: data.dec(_f$userData), + canDelete: data.dec(_f$canDelete), + canDownload: data.dec(_f$canDownload), + jellyType: data.dec(_f$jellyType)); + } + + @override + final Function instantiate = _instantiate; + + static PhotoAlbumModel fromMap(Map map) { + return ensureInitialized().decodeMap(map); + } + + static PhotoAlbumModel fromJson(String json) { + return ensureInitialized().decodeJson(json); + } +} + +mixin PhotoAlbumModelMappable { + String toJson() { + return PhotoAlbumModelMapper.ensureInitialized() + .encodeJson(this as PhotoAlbumModel); + } + + Map toMap() { + return PhotoAlbumModelMapper.ensureInitialized() + .encodeMap(this as PhotoAlbumModel); + } + + PhotoAlbumModelCopyWith + get copyWith => _PhotoAlbumModelCopyWithImpl( + this as PhotoAlbumModel, $identity, $identity); + @override + String toString() { + return PhotoAlbumModelMapper.ensureInitialized() + .stringifyValue(this as PhotoAlbumModel); + } +} + +extension PhotoAlbumModelValueCopy<$R, $Out> + on ObjectCopyWith<$R, PhotoAlbumModel, $Out> { + PhotoAlbumModelCopyWith<$R, PhotoAlbumModel, $Out> get $asPhotoAlbumModel => + $base.as((v, t, t2) => _PhotoAlbumModelCopyWithImpl(v, t, t2)); +} + +abstract class PhotoAlbumModelCopyWith<$R, $In extends PhotoAlbumModel, $Out> + implements ItemBaseModelCopyWith<$R, $In, $Out> { + ListCopyWith<$R, ItemBaseModel, + ItemBaseModelCopyWith<$R, ItemBaseModel, ItemBaseModel>> get photos; + @override + OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview; + @override + UserDataCopyWith<$R, UserData, UserData> get userData; + @override + $R call( + {List? photos, + String? name, + String? id, + OverviewModel? overview, + String? parentId, + String? playlistId, + ImagesData? images, + int? childCount, + double? primaryRatio, + UserData? userData, + bool? canDelete, + bool? canDownload, + dto.BaseItemKind? jellyType}); + PhotoAlbumModelCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t); +} + +class _PhotoAlbumModelCopyWithImpl<$R, $Out> + extends ClassCopyWithBase<$R, PhotoAlbumModel, $Out> + implements PhotoAlbumModelCopyWith<$R, PhotoAlbumModel, $Out> { + _PhotoAlbumModelCopyWithImpl(super.value, super.then, super.then2); + + @override + late final ClassMapperBase $mapper = + PhotoAlbumModelMapper.ensureInitialized(); + @override + ListCopyWith<$R, ItemBaseModel, + ItemBaseModelCopyWith<$R, ItemBaseModel, ItemBaseModel>> + get photos => ListCopyWith($value.photos, (v, t) => v.copyWith.$chain(t), + (v) => call(photos: v)); + @override + OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview => + $value.overview.copyWith.$chain((v) => call(overview: v)); + @override + UserDataCopyWith<$R, UserData, UserData> get userData => + $value.userData.copyWith.$chain((v) => call(userData: v)); + @override + $R call( + {List? photos, + String? name, + String? id, + OverviewModel? overview, + Object? parentId = $none, + Object? playlistId = $none, + Object? images = $none, + Object? childCount = $none, + Object? primaryRatio = $none, + UserData? userData, + Object? canDelete = $none, + Object? canDownload = $none, + Object? jellyType = $none}) => + $apply(FieldCopyWithData({ + if (photos != null) #photos: photos, + if (name != null) #name: name, + if (id != null) #id: id, + if (overview != null) #overview: overview, + if (parentId != $none) #parentId: parentId, + if (playlistId != $none) #playlistId: playlistId, + if (images != $none) #images: images, + if (childCount != $none) #childCount: childCount, + if (primaryRatio != $none) #primaryRatio: primaryRatio, + if (userData != null) #userData: userData, + if (canDelete != $none) #canDelete: canDelete, + if (canDownload != $none) #canDownload: canDownload, + if (jellyType != $none) #jellyType: jellyType + })); + @override + PhotoAlbumModel $make(CopyWithData data) => PhotoAlbumModel( + photos: data.get(#photos, or: $value.photos), + name: data.get(#name, or: $value.name), + id: data.get(#id, or: $value.id), + overview: data.get(#overview, or: $value.overview), + parentId: data.get(#parentId, or: $value.parentId), + playlistId: data.get(#playlistId, or: $value.playlistId), + images: data.get(#images, or: $value.images), + childCount: data.get(#childCount, or: $value.childCount), + primaryRatio: data.get(#primaryRatio, or: $value.primaryRatio), + userData: data.get(#userData, or: $value.userData), + canDelete: data.get(#canDelete, or: $value.canDelete), + canDownload: data.get(#canDownload, or: $value.canDownload), + jellyType: data.get(#jellyType, or: $value.jellyType)); + + @override + PhotoAlbumModelCopyWith<$R2, PhotoAlbumModel, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t) => + _PhotoAlbumModelCopyWithImpl($value, $cast, t); +} + +class PhotoModelMapper extends SubClassMapperBase { + PhotoModelMapper._(); + + static PhotoModelMapper? _instance; + static PhotoModelMapper ensureInitialized() { + if (_instance == null) { + MapperContainer.globals.use(_instance = PhotoModelMapper._()); + ItemBaseModelMapper.ensureInitialized().addSubMapper(_instance!); + OverviewModelMapper.ensureInitialized(); + UserDataMapper.ensureInitialized(); + } + return _instance!; + } + + @override + final String id = 'PhotoModel'; + + static String? _$albumId(PhotoModel v) => v.albumId; + static const Field _f$albumId = + Field('albumId', _$albumId); + static DateTime? _$dateTaken(PhotoModel v) => v.dateTaken; + static const Field _f$dateTaken = + Field('dateTaken', _$dateTaken); + static ImagesData? _$thumbnail(PhotoModel v) => v.thumbnail; + static const Field _f$thumbnail = + Field('thumbnail', _$thumbnail); + static FladderItemType _$internalType(PhotoModel v) => v.internalType; + static const Field _f$internalType = + Field('internalType', _$internalType); + static String _$name(PhotoModel v) => v.name; + static const Field _f$name = Field('name', _$name); + static String _$id(PhotoModel v) => v.id; + static const Field _f$id = Field('id', _$id); + static OverviewModel _$overview(PhotoModel v) => v.overview; + static const Field _f$overview = + Field('overview', _$overview); + static String? _$parentId(PhotoModel v) => v.parentId; + static const Field _f$parentId = + Field('parentId', _$parentId); + static String? _$playlistId(PhotoModel v) => v.playlistId; + static const Field _f$playlistId = + Field('playlistId', _$playlistId); + static ImagesData? _$images(PhotoModel v) => v.images; + static const Field _f$images = + Field('images', _$images); + static int? _$childCount(PhotoModel v) => v.childCount; + static const Field _f$childCount = + Field('childCount', _$childCount); + static double? _$primaryRatio(PhotoModel v) => v.primaryRatio; + static const Field _f$primaryRatio = + Field('primaryRatio', _$primaryRatio); + static UserData _$userData(PhotoModel v) => v.userData; + static const Field _f$userData = + Field('userData', _$userData); + static bool? _$canDownload(PhotoModel v) => v.canDownload; + static const Field _f$canDownload = + Field('canDownload', _$canDownload); + static bool? _$canDelete(PhotoModel v) => v.canDelete; + static const Field _f$canDelete = + Field('canDelete', _$canDelete); + static dto.BaseItemKind? _$jellyType(PhotoModel v) => v.jellyType; + static const Field _f$jellyType = + Field('jellyType', _$jellyType, opt: true); + + @override + final MappableFields fields = const { + #albumId: _f$albumId, + #dateTaken: _f$dateTaken, + #thumbnail: _f$thumbnail, + #internalType: _f$internalType, + #name: _f$name, + #id: _f$id, + #overview: _f$overview, + #parentId: _f$parentId, + #playlistId: _f$playlistId, + #images: _f$images, + #childCount: _f$childCount, + #primaryRatio: _f$primaryRatio, + #userData: _f$userData, + #canDownload: _f$canDownload, + #canDelete: _f$canDelete, + #jellyType: _f$jellyType, + }; + @override + final bool ignoreNull = true; + + @override + final String discriminatorKey = 'type'; + @override + final dynamic discriminatorValue = 'PhotoModel'; + @override + late final ClassMapperBase superMapper = + ItemBaseModelMapper.ensureInitialized(); + + static PhotoModel _instantiate(DecodingData data) { + return PhotoModel( + albumId: data.dec(_f$albumId), + dateTaken: data.dec(_f$dateTaken), + thumbnail: data.dec(_f$thumbnail), + internalType: data.dec(_f$internalType), + name: data.dec(_f$name), + id: data.dec(_f$id), + overview: data.dec(_f$overview), + parentId: data.dec(_f$parentId), + playlistId: data.dec(_f$playlistId), + images: data.dec(_f$images), + childCount: data.dec(_f$childCount), + primaryRatio: data.dec(_f$primaryRatio), + userData: data.dec(_f$userData), + canDownload: data.dec(_f$canDownload), + canDelete: data.dec(_f$canDelete), + jellyType: data.dec(_f$jellyType)); + } + + @override + final Function instantiate = _instantiate; + + static PhotoModel fromMap(Map map) { + return ensureInitialized().decodeMap(map); + } + + static PhotoModel fromJson(String json) { + return ensureInitialized().decodeJson(json); + } +} + +mixin PhotoModelMappable { + String toJson() { + return PhotoModelMapper.ensureInitialized() + .encodeJson(this as PhotoModel); + } + + Map toMap() { + return PhotoModelMapper.ensureInitialized() + .encodeMap(this as PhotoModel); + } + + PhotoModelCopyWith get copyWith => + _PhotoModelCopyWithImpl(this as PhotoModel, $identity, $identity); + @override + String toString() { + return PhotoModelMapper.ensureInitialized() + .stringifyValue(this as PhotoModel); + } +} + +extension PhotoModelValueCopy<$R, $Out> + on ObjectCopyWith<$R, PhotoModel, $Out> { + PhotoModelCopyWith<$R, PhotoModel, $Out> get $asPhotoModel => + $base.as((v, t, t2) => _PhotoModelCopyWithImpl(v, t, t2)); +} + +abstract class PhotoModelCopyWith<$R, $In extends PhotoModel, $Out> + implements ItemBaseModelCopyWith<$R, $In, $Out> { + @override + OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview; + @override + UserDataCopyWith<$R, UserData, UserData> get userData; + @override + $R call( + {String? albumId, + DateTime? dateTaken, + ImagesData? thumbnail, + FladderItemType? internalType, + String? name, + String? id, + OverviewModel? overview, + String? parentId, + String? playlistId, + ImagesData? images, + int? childCount, + double? primaryRatio, + UserData? userData, + bool? canDownload, + bool? canDelete, + dto.BaseItemKind? jellyType}); + PhotoModelCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t); +} + +class _PhotoModelCopyWithImpl<$R, $Out> + extends ClassCopyWithBase<$R, PhotoModel, $Out> + implements PhotoModelCopyWith<$R, PhotoModel, $Out> { + _PhotoModelCopyWithImpl(super.value, super.then, super.then2); + + @override + late final ClassMapperBase $mapper = + PhotoModelMapper.ensureInitialized(); + @override + OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview => + $value.overview.copyWith.$chain((v) => call(overview: v)); + @override + UserDataCopyWith<$R, UserData, UserData> get userData => + $value.userData.copyWith.$chain((v) => call(userData: v)); + @override + $R call( + {Object? albumId = $none, + Object? dateTaken = $none, + Object? thumbnail = $none, + FladderItemType? internalType, + String? name, + String? id, + OverviewModel? overview, + Object? parentId = $none, + Object? playlistId = $none, + Object? images = $none, + Object? childCount = $none, + Object? primaryRatio = $none, + UserData? userData, + Object? canDownload = $none, + Object? canDelete = $none, + Object? jellyType = $none}) => + $apply(FieldCopyWithData({ + if (albumId != $none) #albumId: albumId, + if (dateTaken != $none) #dateTaken: dateTaken, + if (thumbnail != $none) #thumbnail: thumbnail, + if (internalType != null) #internalType: internalType, + if (name != null) #name: name, + if (id != null) #id: id, + if (overview != null) #overview: overview, + if (parentId != $none) #parentId: parentId, + if (playlistId != $none) #playlistId: playlistId, + if (images != $none) #images: images, + if (childCount != $none) #childCount: childCount, + if (primaryRatio != $none) #primaryRatio: primaryRatio, + if (userData != null) #userData: userData, + if (canDownload != $none) #canDownload: canDownload, + if (canDelete != $none) #canDelete: canDelete, + if (jellyType != $none) #jellyType: jellyType + })); + @override + PhotoModel $make(CopyWithData data) => PhotoModel( + albumId: data.get(#albumId, or: $value.albumId), + dateTaken: data.get(#dateTaken, or: $value.dateTaken), + thumbnail: data.get(#thumbnail, or: $value.thumbnail), + internalType: data.get(#internalType, or: $value.internalType), + name: data.get(#name, or: $value.name), + id: data.get(#id, or: $value.id), + overview: data.get(#overview, or: $value.overview), + parentId: data.get(#parentId, or: $value.parentId), + playlistId: data.get(#playlistId, or: $value.playlistId), + images: data.get(#images, or: $value.images), + childCount: data.get(#childCount, or: $value.childCount), + primaryRatio: data.get(#primaryRatio, or: $value.primaryRatio), + userData: data.get(#userData, or: $value.userData), + canDownload: data.get(#canDownload, or: $value.canDownload), + canDelete: data.get(#canDelete, or: $value.canDelete), + jellyType: data.get(#jellyType, or: $value.jellyType)); + + @override + PhotoModelCopyWith<$R2, PhotoModel, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t) => + _PhotoModelCopyWithImpl($value, $cast, t); +} diff --git a/lib/models/items/season_model.dart b/lib/models/items/season_model.dart new file mode 100644 index 0000000..41b03bd --- /dev/null +++ b/lib/models/items/season_model.dart @@ -0,0 +1,98 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first + +import 'package:collection/collection.dart'; +import 'package:fladder/models/items/overview_model.dart'; +import 'package:fladder/models/items/series_model.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart' as dto; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/episode_model.dart'; +import 'package:fladder/models/items/images_models.dart'; +import 'package:fladder/models/items/item_shared_models.dart'; + +import 'package:dart_mappable/dart_mappable.dart'; + +part 'season_model.mapper.dart'; + +@MappableClass() +class SeasonModel extends ItemBaseModel with SeasonModelMappable { + final ImagesData? parentImages; + final String seasonName; + final List episodes; + final int episodeCount; + final String seriesId; + final String seriesName; + const SeasonModel({ + required this.parentImages, + required this.seasonName, + this.episodes = const [], + required this.episodeCount, + required this.seriesId, + required this.seriesName, + required super.name, + required super.id, + required super.overview, + required super.parentId, + required super.playlistId, + required super.images, + required super.childCount, + required super.primaryRatio, + required super.userData, + required super.canDelete, + required super.canDownload, + super.jellyType, + }); + factory SeasonModel.fromBaseDto(dto.BaseItemDto item, Ref ref) { + return SeasonModel( + name: item.name ?? "", + id: item.id ?? "", + childCount: item.childCount, + overview: OverviewModel.fromBaseItemDto(item, ref), + userData: UserData.fromDto(item.userData), + parentId: item.seasonId ?? item.parentId, + playlistId: item.playlistItemId, + images: ImagesData.fromBaseItem(item, ref), + primaryRatio: item.primaryImageAspectRatio, + seasonName: item.seasonName ?? "", + episodeCount: item.episodeCount ?? 0, + parentImages: ImagesData.fromBaseItemParent(item, ref, primary: const Size(2000, 2000)), + seriesId: item.seriesId ?? item.parentId ?? item.id ?? "", + canDelete: item.canDelete, + canDownload: item.canDownload, + seriesName: item.seriesName ?? "", + ); + } + + EpisodeModel? get nextUp { + return episodes.lastWhereOrNull((element) => element.userData.progress > 0) ?? + episodes.firstWhereOrNull((element) => element.userData.played == false); + } + + @override + ImagesData? get getPosters => images ?? parentImages; + + String localizedName(BuildContext context) => name.replaceFirst("Season", context.localized.season(1)); + + @override + SeriesModel get parentBaseModel => SeriesModel( + originalTitle: '', + sortName: '', + status: "", + name: seriesName, + id: parentId ?? "", + playlistId: playlistId, + overview: overview, + parentId: parentId, + images: images, + childCount: childCount, + primaryRatio: primaryRatio, + userData: UserData(), + ); + + static List seasonsFromDto(List? dto, Ref ref) { + return dto?.map((e) => SeasonModel.fromBaseDto(e, ref)).toList() ?? []; + } +} diff --git a/lib/models/items/season_model.mapper.dart b/lib/models/items/season_model.mapper.dart new file mode 100644 index 0000000..fa1ef89 --- /dev/null +++ b/lib/models/items/season_model.mapper.dart @@ -0,0 +1,287 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member +// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter + +part of 'season_model.dart'; + +class SeasonModelMapper extends SubClassMapperBase { + SeasonModelMapper._(); + + static SeasonModelMapper? _instance; + static SeasonModelMapper ensureInitialized() { + if (_instance == null) { + MapperContainer.globals.use(_instance = SeasonModelMapper._()); + ItemBaseModelMapper.ensureInitialized().addSubMapper(_instance!); + EpisodeModelMapper.ensureInitialized(); + OverviewModelMapper.ensureInitialized(); + UserDataMapper.ensureInitialized(); + } + return _instance!; + } + + @override + final String id = 'SeasonModel'; + + static ImagesData? _$parentImages(SeasonModel v) => v.parentImages; + static const Field _f$parentImages = + Field('parentImages', _$parentImages); + static String _$seasonName(SeasonModel v) => v.seasonName; + static const Field _f$seasonName = + Field('seasonName', _$seasonName); + static List _$episodes(SeasonModel v) => v.episodes; + static const Field> _f$episodes = + Field('episodes', _$episodes, opt: true, def: const []); + static int _$episodeCount(SeasonModel v) => v.episodeCount; + static const Field _f$episodeCount = + Field('episodeCount', _$episodeCount); + static String _$seriesId(SeasonModel v) => v.seriesId; + static const Field _f$seriesId = + Field('seriesId', _$seriesId); + static String _$seriesName(SeasonModel v) => v.seriesName; + static const Field _f$seriesName = + Field('seriesName', _$seriesName); + static String _$name(SeasonModel v) => v.name; + static const Field _f$name = Field('name', _$name); + static String _$id(SeasonModel v) => v.id; + static const Field _f$id = Field('id', _$id); + static OverviewModel _$overview(SeasonModel v) => v.overview; + static const Field _f$overview = + Field('overview', _$overview); + static String? _$parentId(SeasonModel v) => v.parentId; + static const Field _f$parentId = + Field('parentId', _$parentId); + static String? _$playlistId(SeasonModel v) => v.playlistId; + static const Field _f$playlistId = + Field('playlistId', _$playlistId); + static ImagesData? _$images(SeasonModel v) => v.images; + static const Field _f$images = + Field('images', _$images); + static int? _$childCount(SeasonModel v) => v.childCount; + static const Field _f$childCount = + Field('childCount', _$childCount); + static double? _$primaryRatio(SeasonModel v) => v.primaryRatio; + static const Field _f$primaryRatio = + Field('primaryRatio', _$primaryRatio); + static UserData _$userData(SeasonModel v) => v.userData; + static const Field _f$userData = + Field('userData', _$userData); + static bool? _$canDelete(SeasonModel v) => v.canDelete; + static const Field _f$canDelete = + Field('canDelete', _$canDelete); + static bool? _$canDownload(SeasonModel v) => v.canDownload; + static const Field _f$canDownload = + Field('canDownload', _$canDownload); + static dto.BaseItemKind? _$jellyType(SeasonModel v) => v.jellyType; + static const Field _f$jellyType = + Field('jellyType', _$jellyType, opt: true); + + @override + final MappableFields fields = const { + #parentImages: _f$parentImages, + #seasonName: _f$seasonName, + #episodes: _f$episodes, + #episodeCount: _f$episodeCount, + #seriesId: _f$seriesId, + #seriesName: _f$seriesName, + #name: _f$name, + #id: _f$id, + #overview: _f$overview, + #parentId: _f$parentId, + #playlistId: _f$playlistId, + #images: _f$images, + #childCount: _f$childCount, + #primaryRatio: _f$primaryRatio, + #userData: _f$userData, + #canDelete: _f$canDelete, + #canDownload: _f$canDownload, + #jellyType: _f$jellyType, + }; + @override + final bool ignoreNull = true; + + @override + final String discriminatorKey = 'type'; + @override + final dynamic discriminatorValue = 'SeasonModel'; + @override + late final ClassMapperBase superMapper = + ItemBaseModelMapper.ensureInitialized(); + + static SeasonModel _instantiate(DecodingData data) { + return SeasonModel( + parentImages: data.dec(_f$parentImages), + seasonName: data.dec(_f$seasonName), + episodes: data.dec(_f$episodes), + episodeCount: data.dec(_f$episodeCount), + seriesId: data.dec(_f$seriesId), + seriesName: data.dec(_f$seriesName), + name: data.dec(_f$name), + id: data.dec(_f$id), + overview: data.dec(_f$overview), + parentId: data.dec(_f$parentId), + playlistId: data.dec(_f$playlistId), + images: data.dec(_f$images), + childCount: data.dec(_f$childCount), + primaryRatio: data.dec(_f$primaryRatio), + userData: data.dec(_f$userData), + canDelete: data.dec(_f$canDelete), + canDownload: data.dec(_f$canDownload), + jellyType: data.dec(_f$jellyType)); + } + + @override + final Function instantiate = _instantiate; + + static SeasonModel fromMap(Map map) { + return ensureInitialized().decodeMap(map); + } + + static SeasonModel fromJson(String json) { + return ensureInitialized().decodeJson(json); + } +} + +mixin SeasonModelMappable { + String toJson() { + return SeasonModelMapper.ensureInitialized() + .encodeJson(this as SeasonModel); + } + + Map toMap() { + return SeasonModelMapper.ensureInitialized() + .encodeMap(this as SeasonModel); + } + + SeasonModelCopyWith get copyWith => + _SeasonModelCopyWithImpl(this as SeasonModel, $identity, $identity); + @override + String toString() { + return SeasonModelMapper.ensureInitialized() + .stringifyValue(this as SeasonModel); + } +} + +extension SeasonModelValueCopy<$R, $Out> + on ObjectCopyWith<$R, SeasonModel, $Out> { + SeasonModelCopyWith<$R, SeasonModel, $Out> get $asSeasonModel => + $base.as((v, t, t2) => _SeasonModelCopyWithImpl(v, t, t2)); +} + +abstract class SeasonModelCopyWith<$R, $In extends SeasonModel, $Out> + implements ItemBaseModelCopyWith<$R, $In, $Out> { + ListCopyWith<$R, EpisodeModel, + EpisodeModelCopyWith<$R, EpisodeModel, EpisodeModel>> get episodes; + @override + OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview; + @override + UserDataCopyWith<$R, UserData, UserData> get userData; + @override + $R call( + {ImagesData? parentImages, + String? seasonName, + List? episodes, + int? episodeCount, + String? seriesId, + String? seriesName, + String? name, + String? id, + OverviewModel? overview, + String? parentId, + String? playlistId, + ImagesData? images, + int? childCount, + double? primaryRatio, + UserData? userData, + bool? canDelete, + bool? canDownload, + dto.BaseItemKind? jellyType}); + SeasonModelCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t); +} + +class _SeasonModelCopyWithImpl<$R, $Out> + extends ClassCopyWithBase<$R, SeasonModel, $Out> + implements SeasonModelCopyWith<$R, SeasonModel, $Out> { + _SeasonModelCopyWithImpl(super.value, super.then, super.then2); + + @override + late final ClassMapperBase $mapper = + SeasonModelMapper.ensureInitialized(); + @override + ListCopyWith<$R, EpisodeModel, + EpisodeModelCopyWith<$R, EpisodeModel, EpisodeModel>> + get episodes => ListCopyWith($value.episodes, + (v, t) => v.copyWith.$chain(t), (v) => call(episodes: v)); + @override + OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview => + $value.overview.copyWith.$chain((v) => call(overview: v)); + @override + UserDataCopyWith<$R, UserData, UserData> get userData => + $value.userData.copyWith.$chain((v) => call(userData: v)); + @override + $R call( + {Object? parentImages = $none, + String? seasonName, + List? episodes, + int? episodeCount, + String? seriesId, + String? seriesName, + String? name, + String? id, + OverviewModel? overview, + Object? parentId = $none, + Object? playlistId = $none, + Object? images = $none, + Object? childCount = $none, + Object? primaryRatio = $none, + UserData? userData, + Object? canDelete = $none, + Object? canDownload = $none, + Object? jellyType = $none}) => + $apply(FieldCopyWithData({ + if (parentImages != $none) #parentImages: parentImages, + if (seasonName != null) #seasonName: seasonName, + if (episodes != null) #episodes: episodes, + if (episodeCount != null) #episodeCount: episodeCount, + if (seriesId != null) #seriesId: seriesId, + if (seriesName != null) #seriesName: seriesName, + if (name != null) #name: name, + if (id != null) #id: id, + if (overview != null) #overview: overview, + if (parentId != $none) #parentId: parentId, + if (playlistId != $none) #playlistId: playlistId, + if (images != $none) #images: images, + if (childCount != $none) #childCount: childCount, + if (primaryRatio != $none) #primaryRatio: primaryRatio, + if (userData != null) #userData: userData, + if (canDelete != $none) #canDelete: canDelete, + if (canDownload != $none) #canDownload: canDownload, + if (jellyType != $none) #jellyType: jellyType + })); + @override + SeasonModel $make(CopyWithData data) => SeasonModel( + parentImages: data.get(#parentImages, or: $value.parentImages), + seasonName: data.get(#seasonName, or: $value.seasonName), + episodes: data.get(#episodes, or: $value.episodes), + episodeCount: data.get(#episodeCount, or: $value.episodeCount), + seriesId: data.get(#seriesId, or: $value.seriesId), + seriesName: data.get(#seriesName, or: $value.seriesName), + name: data.get(#name, or: $value.name), + id: data.get(#id, or: $value.id), + overview: data.get(#overview, or: $value.overview), + parentId: data.get(#parentId, or: $value.parentId), + playlistId: data.get(#playlistId, or: $value.playlistId), + images: data.get(#images, or: $value.images), + childCount: data.get(#childCount, or: $value.childCount), + primaryRatio: data.get(#primaryRatio, or: $value.primaryRatio), + userData: data.get(#userData, or: $value.userData), + canDelete: data.get(#canDelete, or: $value.canDelete), + canDownload: data.get(#canDownload, or: $value.canDownload), + jellyType: data.get(#jellyType, or: $value.jellyType)); + + @override + SeasonModelCopyWith<$R2, SeasonModel, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t) => + _SeasonModelCopyWithImpl($value, $cast, t); +} diff --git a/lib/models/items/series_model.dart b/lib/models/items/series_model.dart new file mode 100644 index 0000000..c1f16f7 --- /dev/null +++ b/lib/models/items/series_model.dart @@ -0,0 +1,96 @@ +import 'package:fladder/screens/details_screens/series_detail_screen.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart' as dto; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/episode_model.dart'; +import 'package:fladder/models/items/images_models.dart'; +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/models/items/overview_model.dart'; +import 'package:fladder/models/items/season_model.dart'; + +import 'package:dart_mappable/dart_mappable.dart'; + +part 'series_model.mapper.dart'; + +@MappableClass() +class SeriesModel extends ItemBaseModel with SeriesModelMappable { + final List? availableEpisodes; + final List? seasons; + final String originalTitle; + final String sortName; + final String status; + final List related; + const SeriesModel({ + this.availableEpisodes, + this.seasons, + required this.originalTitle, + required this.sortName, + required this.status, + this.related = const [], + required super.name, + required super.id, + required super.overview, + required super.parentId, + required super.playlistId, + required super.images, + required super.childCount, + required super.primaryRatio, + required super.userData, + super.canDownload, + super.canDelete, + super.jellyType, + }); + + EpisodeModel? get nextUp => availableEpisodes?.nextUp ?? availableEpisodes?.firstOrNull; + + @override + String detailedName(BuildContext context) => name; + + @override + ItemBaseModel get parentBaseModel => this; + + @override + Widget get detailScreenWidget => SeriesDetailScreen(item: this); + + @override + bool get emptyShow => childCount == 0; + + @override + bool get playAble => userData.unPlayedItemCount != 0; + + @override + bool get identifiable => true; + + @override + bool get unWatched => + !userData.played && userData.progress <= 0 && userData.unPlayedItemCount == 0 && childCount != 0; + + @override + String get subText => overview.yearAired?.toString() ?? ""; + + List fetchAllShows() { + return availableEpisodes?.map((e) => e).toList() ?? []; + } + + @override + bool get syncAble => true; + + factory SeriesModel.fromBaseDto(dto.BaseItemDto item, Ref ref) => SeriesModel( + name: item.name ?? "", + id: item.id ?? "", + childCount: item.childCount, + overview: OverviewModel.fromBaseItemDto(item, ref), + userData: UserData.fromDto(item.userData), + parentId: item.parentId, + playlistId: item.playlistItemId, + images: ImagesData.fromBaseItem(item, ref, getOriginalSize: true), + primaryRatio: item.primaryImageAspectRatio, + originalTitle: item.originalTitle ?? "", + sortName: item.sortName ?? "", + canDelete: item.canDelete, + canDownload: item.canDownload, + status: item.status ?? "Continuing", + ); +} diff --git a/lib/models/items/series_model.mapper.dart b/lib/models/items/series_model.mapper.dart new file mode 100644 index 0000000..7f9b7cf --- /dev/null +++ b/lib/models/items/series_model.mapper.dart @@ -0,0 +1,309 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member +// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter + +part of 'series_model.dart'; + +class SeriesModelMapper extends SubClassMapperBase { + SeriesModelMapper._(); + + static SeriesModelMapper? _instance; + static SeriesModelMapper ensureInitialized() { + if (_instance == null) { + MapperContainer.globals.use(_instance = SeriesModelMapper._()); + ItemBaseModelMapper.ensureInitialized().addSubMapper(_instance!); + EpisodeModelMapper.ensureInitialized(); + SeasonModelMapper.ensureInitialized(); + ItemBaseModelMapper.ensureInitialized(); + OverviewModelMapper.ensureInitialized(); + UserDataMapper.ensureInitialized(); + } + return _instance!; + } + + @override + final String id = 'SeriesModel'; + + static List? _$availableEpisodes(SeriesModel v) => + v.availableEpisodes; + static const Field> _f$availableEpisodes = + Field('availableEpisodes', _$availableEpisodes, opt: true); + static List? _$seasons(SeriesModel v) => v.seasons; + static const Field> _f$seasons = + Field('seasons', _$seasons, opt: true); + static String _$originalTitle(SeriesModel v) => v.originalTitle; + static const Field _f$originalTitle = + Field('originalTitle', _$originalTitle); + static String _$sortName(SeriesModel v) => v.sortName; + static const Field _f$sortName = + Field('sortName', _$sortName); + static String _$status(SeriesModel v) => v.status; + static const Field _f$status = Field('status', _$status); + static List _$related(SeriesModel v) => v.related; + static const Field> _f$related = + Field('related', _$related, opt: true, def: const []); + static String _$name(SeriesModel v) => v.name; + static const Field _f$name = Field('name', _$name); + static String _$id(SeriesModel v) => v.id; + static const Field _f$id = Field('id', _$id); + static OverviewModel _$overview(SeriesModel v) => v.overview; + static const Field _f$overview = + Field('overview', _$overview); + static String? _$parentId(SeriesModel v) => v.parentId; + static const Field _f$parentId = + Field('parentId', _$parentId); + static String? _$playlistId(SeriesModel v) => v.playlistId; + static const Field _f$playlistId = + Field('playlistId', _$playlistId); + static ImagesData? _$images(SeriesModel v) => v.images; + static const Field _f$images = + Field('images', _$images); + static int? _$childCount(SeriesModel v) => v.childCount; + static const Field _f$childCount = + Field('childCount', _$childCount); + static double? _$primaryRatio(SeriesModel v) => v.primaryRatio; + static const Field _f$primaryRatio = + Field('primaryRatio', _$primaryRatio); + static UserData _$userData(SeriesModel v) => v.userData; + static const Field _f$userData = + Field('userData', _$userData); + static bool? _$canDownload(SeriesModel v) => v.canDownload; + static const Field _f$canDownload = + Field('canDownload', _$canDownload, opt: true); + static bool? _$canDelete(SeriesModel v) => v.canDelete; + static const Field _f$canDelete = + Field('canDelete', _$canDelete, opt: true); + static dto.BaseItemKind? _$jellyType(SeriesModel v) => v.jellyType; + static const Field _f$jellyType = + Field('jellyType', _$jellyType, opt: true); + + @override + final MappableFields fields = const { + #availableEpisodes: _f$availableEpisodes, + #seasons: _f$seasons, + #originalTitle: _f$originalTitle, + #sortName: _f$sortName, + #status: _f$status, + #related: _f$related, + #name: _f$name, + #id: _f$id, + #overview: _f$overview, + #parentId: _f$parentId, + #playlistId: _f$playlistId, + #images: _f$images, + #childCount: _f$childCount, + #primaryRatio: _f$primaryRatio, + #userData: _f$userData, + #canDownload: _f$canDownload, + #canDelete: _f$canDelete, + #jellyType: _f$jellyType, + }; + @override + final bool ignoreNull = true; + + @override + final String discriminatorKey = 'type'; + @override + final dynamic discriminatorValue = 'SeriesModel'; + @override + late final ClassMapperBase superMapper = + ItemBaseModelMapper.ensureInitialized(); + + static SeriesModel _instantiate(DecodingData data) { + return SeriesModel( + availableEpisodes: data.dec(_f$availableEpisodes), + seasons: data.dec(_f$seasons), + originalTitle: data.dec(_f$originalTitle), + sortName: data.dec(_f$sortName), + status: data.dec(_f$status), + related: data.dec(_f$related), + name: data.dec(_f$name), + id: data.dec(_f$id), + overview: data.dec(_f$overview), + parentId: data.dec(_f$parentId), + playlistId: data.dec(_f$playlistId), + images: data.dec(_f$images), + childCount: data.dec(_f$childCount), + primaryRatio: data.dec(_f$primaryRatio), + userData: data.dec(_f$userData), + canDownload: data.dec(_f$canDownload), + canDelete: data.dec(_f$canDelete), + jellyType: data.dec(_f$jellyType)); + } + + @override + final Function instantiate = _instantiate; + + static SeriesModel fromMap(Map map) { + return ensureInitialized().decodeMap(map); + } + + static SeriesModel fromJson(String json) { + return ensureInitialized().decodeJson(json); + } +} + +mixin SeriesModelMappable { + String toJson() { + return SeriesModelMapper.ensureInitialized() + .encodeJson(this as SeriesModel); + } + + Map toMap() { + return SeriesModelMapper.ensureInitialized() + .encodeMap(this as SeriesModel); + } + + SeriesModelCopyWith get copyWith => + _SeriesModelCopyWithImpl(this as SeriesModel, $identity, $identity); + @override + String toString() { + return SeriesModelMapper.ensureInitialized() + .stringifyValue(this as SeriesModel); + } +} + +extension SeriesModelValueCopy<$R, $Out> + on ObjectCopyWith<$R, SeriesModel, $Out> { + SeriesModelCopyWith<$R, SeriesModel, $Out> get $asSeriesModel => + $base.as((v, t, t2) => _SeriesModelCopyWithImpl(v, t, t2)); +} + +abstract class SeriesModelCopyWith<$R, $In extends SeriesModel, $Out> + implements ItemBaseModelCopyWith<$R, $In, $Out> { + ListCopyWith<$R, EpisodeModel, + EpisodeModelCopyWith<$R, EpisodeModel, EpisodeModel>>? + get availableEpisodes; + ListCopyWith<$R, SeasonModel, + SeasonModelCopyWith<$R, SeasonModel, SeasonModel>>? get seasons; + ListCopyWith<$R, ItemBaseModel, + ItemBaseModelCopyWith<$R, ItemBaseModel, ItemBaseModel>> get related; + @override + OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview; + @override + UserDataCopyWith<$R, UserData, UserData> get userData; + @override + $R call( + {List? availableEpisodes, + List? seasons, + String? originalTitle, + String? sortName, + String? status, + List? related, + String? name, + String? id, + OverviewModel? overview, + String? parentId, + String? playlistId, + ImagesData? images, + int? childCount, + double? primaryRatio, + UserData? userData, + bool? canDownload, + bool? canDelete, + dto.BaseItemKind? jellyType}); + SeriesModelCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t); +} + +class _SeriesModelCopyWithImpl<$R, $Out> + extends ClassCopyWithBase<$R, SeriesModel, $Out> + implements SeriesModelCopyWith<$R, SeriesModel, $Out> { + _SeriesModelCopyWithImpl(super.value, super.then, super.then2); + + @override + late final ClassMapperBase $mapper = + SeriesModelMapper.ensureInitialized(); + @override + ListCopyWith<$R, EpisodeModel, + EpisodeModelCopyWith<$R, EpisodeModel, EpisodeModel>>? + get availableEpisodes => $value.availableEpisodes != null + ? ListCopyWith($value.availableEpisodes!, + (v, t) => v.copyWith.$chain(t), (v) => call(availableEpisodes: v)) + : null; + @override + ListCopyWith<$R, SeasonModel, + SeasonModelCopyWith<$R, SeasonModel, SeasonModel>>? + get seasons => $value.seasons != null + ? ListCopyWith($value.seasons!, (v, t) => v.copyWith.$chain(t), + (v) => call(seasons: v)) + : null; + @override + ListCopyWith<$R, ItemBaseModel, + ItemBaseModelCopyWith<$R, ItemBaseModel, ItemBaseModel>> + get related => ListCopyWith($value.related, + (v, t) => v.copyWith.$chain(t), (v) => call(related: v)); + @override + OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview => + $value.overview.copyWith.$chain((v) => call(overview: v)); + @override + UserDataCopyWith<$R, UserData, UserData> get userData => + $value.userData.copyWith.$chain((v) => call(userData: v)); + @override + $R call( + {Object? availableEpisodes = $none, + Object? seasons = $none, + String? originalTitle, + String? sortName, + String? status, + List? related, + String? name, + String? id, + OverviewModel? overview, + Object? parentId = $none, + Object? playlistId = $none, + Object? images = $none, + Object? childCount = $none, + Object? primaryRatio = $none, + UserData? userData, + Object? canDownload = $none, + Object? canDelete = $none, + Object? jellyType = $none}) => + $apply(FieldCopyWithData({ + if (availableEpisodes != $none) #availableEpisodes: availableEpisodes, + if (seasons != $none) #seasons: seasons, + if (originalTitle != null) #originalTitle: originalTitle, + if (sortName != null) #sortName: sortName, + if (status != null) #status: status, + if (related != null) #related: related, + if (name != null) #name: name, + if (id != null) #id: id, + if (overview != null) #overview: overview, + if (parentId != $none) #parentId: parentId, + if (playlistId != $none) #playlistId: playlistId, + if (images != $none) #images: images, + if (childCount != $none) #childCount: childCount, + if (primaryRatio != $none) #primaryRatio: primaryRatio, + if (userData != null) #userData: userData, + if (canDownload != $none) #canDownload: canDownload, + if (canDelete != $none) #canDelete: canDelete, + if (jellyType != $none) #jellyType: jellyType + })); + @override + SeriesModel $make(CopyWithData data) => SeriesModel( + availableEpisodes: + data.get(#availableEpisodes, or: $value.availableEpisodes), + seasons: data.get(#seasons, or: $value.seasons), + originalTitle: data.get(#originalTitle, or: $value.originalTitle), + sortName: data.get(#sortName, or: $value.sortName), + status: data.get(#status, or: $value.status), + related: data.get(#related, or: $value.related), + name: data.get(#name, or: $value.name), + id: data.get(#id, or: $value.id), + overview: data.get(#overview, or: $value.overview), + parentId: data.get(#parentId, or: $value.parentId), + playlistId: data.get(#playlistId, or: $value.playlistId), + images: data.get(#images, or: $value.images), + childCount: data.get(#childCount, or: $value.childCount), + primaryRatio: data.get(#primaryRatio, or: $value.primaryRatio), + userData: data.get(#userData, or: $value.userData), + canDownload: data.get(#canDownload, or: $value.canDownload), + canDelete: data.get(#canDelete, or: $value.canDelete), + jellyType: data.get(#jellyType, or: $value.jellyType)); + + @override + SeriesModelCopyWith<$R2, SeriesModel, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t) => + _SeriesModelCopyWithImpl($value, $cast, t); +} diff --git a/lib/models/items/trick_play_model.dart b/lib/models/items/trick_play_model.dart new file mode 100644 index 0000000..1f0b03d --- /dev/null +++ b/lib/models/items/trick_play_model.dart @@ -0,0 +1,61 @@ +import 'dart:ui'; + +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'trick_play_model.freezed.dart'; +part 'trick_play_model.g.dart'; + +@freezed +class TrickPlayModel with _$TrickPlayModel { + factory TrickPlayModel({ + required int width, + required int height, + required int tileWidth, + required int tileHeight, + required int thumbnailCount, + required Duration interval, + @Default([]) List images, + }) = _TrickPlayModel; + + const TrickPlayModel._(); + + int get imagesPerTile => tileWidth * tileHeight; + + String? getTile(Duration position) { + final int currentIndex = (position.inMilliseconds ~/ interval.inMilliseconds).clamp(0, thumbnailCount); + final int indexOfTile = (currentIndex ~/ imagesPerTile).clamp(0, images.length); + return images.elementAtOrNull(indexOfTile); + } + + Offset offset(Duration position) { + final int currentIndex = (position.inMilliseconds ~/ interval.inMilliseconds).clamp(0, thumbnailCount - 1); + final int tileIndex = currentIndex % imagesPerTile; + final int column = tileIndex % tileWidth; + final int row = tileIndex ~/ tileWidth; + return Offset((width * column).toDouble(), (height * row).toDouble()); + } + + static Map toTrickPlayMap(Map map) { + Map newMap = {}; + final firstMap = (((map.entries.first as MapEntry).value as Map)); + newMap.addEntries(firstMap.entries.map( + (e) { + final map = e.value as Map; + return MapEntry( + e.key, + TrickPlayModel( + width: map['Width'] as int? ?? 0, + height: map['Height'] as int? ?? 0, + tileWidth: map['TileWidth'] as int? ?? 0, + tileHeight: map['TileHeight'] as int? ?? 0, + thumbnailCount: map['ThumbnailCount'] as int? ?? 0, + interval: Duration(milliseconds: map['Interval'] as int? ?? 0), + ), + ); + }, + )); + return newMap; + } + + factory TrickPlayModel.fromJson(Map json) => _$TrickPlayModelFromJson(json); +} diff --git a/lib/models/items/trick_play_model.freezed.dart b/lib/models/items/trick_play_model.freezed.dart new file mode 100644 index 0000000..b376eef --- /dev/null +++ b/lib/models/items/trick_play_model.freezed.dart @@ -0,0 +1,297 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'trick_play_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +TrickPlayModel _$TrickPlayModelFromJson(Map json) { + return _TrickPlayModel.fromJson(json); +} + +/// @nodoc +mixin _$TrickPlayModel { + int get width => throw _privateConstructorUsedError; + int get height => throw _privateConstructorUsedError; + int get tileWidth => throw _privateConstructorUsedError; + int get tileHeight => throw _privateConstructorUsedError; + int get thumbnailCount => throw _privateConstructorUsedError; + Duration get interval => throw _privateConstructorUsedError; + List get images => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $TrickPlayModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $TrickPlayModelCopyWith<$Res> { + factory $TrickPlayModelCopyWith( + TrickPlayModel value, $Res Function(TrickPlayModel) then) = + _$TrickPlayModelCopyWithImpl<$Res, TrickPlayModel>; + @useResult + $Res call( + {int width, + int height, + int tileWidth, + int tileHeight, + int thumbnailCount, + Duration interval, + List images}); +} + +/// @nodoc +class _$TrickPlayModelCopyWithImpl<$Res, $Val extends TrickPlayModel> + implements $TrickPlayModelCopyWith<$Res> { + _$TrickPlayModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? width = null, + Object? height = null, + Object? tileWidth = null, + Object? tileHeight = null, + Object? thumbnailCount = null, + Object? interval = null, + Object? images = null, + }) { + return _then(_value.copyWith( + width: null == width + ? _value.width + : width // ignore: cast_nullable_to_non_nullable + as int, + height: null == height + ? _value.height + : height // ignore: cast_nullable_to_non_nullable + as int, + tileWidth: null == tileWidth + ? _value.tileWidth + : tileWidth // ignore: cast_nullable_to_non_nullable + as int, + tileHeight: null == tileHeight + ? _value.tileHeight + : tileHeight // ignore: cast_nullable_to_non_nullable + as int, + thumbnailCount: null == thumbnailCount + ? _value.thumbnailCount + : thumbnailCount // ignore: cast_nullable_to_non_nullable + as int, + interval: null == interval + ? _value.interval + : interval // ignore: cast_nullable_to_non_nullable + as Duration, + images: null == images + ? _value.images + : images // ignore: cast_nullable_to_non_nullable + as List, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$TrickPlayModelImplCopyWith<$Res> + implements $TrickPlayModelCopyWith<$Res> { + factory _$$TrickPlayModelImplCopyWith(_$TrickPlayModelImpl value, + $Res Function(_$TrickPlayModelImpl) then) = + __$$TrickPlayModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {int width, + int height, + int tileWidth, + int tileHeight, + int thumbnailCount, + Duration interval, + List images}); +} + +/// @nodoc +class __$$TrickPlayModelImplCopyWithImpl<$Res> + extends _$TrickPlayModelCopyWithImpl<$Res, _$TrickPlayModelImpl> + implements _$$TrickPlayModelImplCopyWith<$Res> { + __$$TrickPlayModelImplCopyWithImpl( + _$TrickPlayModelImpl _value, $Res Function(_$TrickPlayModelImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? width = null, + Object? height = null, + Object? tileWidth = null, + Object? tileHeight = null, + Object? thumbnailCount = null, + Object? interval = null, + Object? images = null, + }) { + return _then(_$TrickPlayModelImpl( + width: null == width + ? _value.width + : width // ignore: cast_nullable_to_non_nullable + as int, + height: null == height + ? _value.height + : height // ignore: cast_nullable_to_non_nullable + as int, + tileWidth: null == tileWidth + ? _value.tileWidth + : tileWidth // ignore: cast_nullable_to_non_nullable + as int, + tileHeight: null == tileHeight + ? _value.tileHeight + : tileHeight // ignore: cast_nullable_to_non_nullable + as int, + thumbnailCount: null == thumbnailCount + ? _value.thumbnailCount + : thumbnailCount // ignore: cast_nullable_to_non_nullable + as int, + interval: null == interval + ? _value.interval + : interval // ignore: cast_nullable_to_non_nullable + as Duration, + images: null == images + ? _value._images + : images // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$TrickPlayModelImpl extends _TrickPlayModel { + _$TrickPlayModelImpl( + {required this.width, + required this.height, + required this.tileWidth, + required this.tileHeight, + required this.thumbnailCount, + required this.interval, + final List images = const []}) + : _images = images, + super._(); + + factory _$TrickPlayModelImpl.fromJson(Map json) => + _$$TrickPlayModelImplFromJson(json); + + @override + final int width; + @override + final int height; + @override + final int tileWidth; + @override + final int tileHeight; + @override + final int thumbnailCount; + @override + final Duration interval; + final List _images; + @override + @JsonKey() + List get images { + if (_images is EqualUnmodifiableListView) return _images; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_images); + } + + @override + String toString() { + return 'TrickPlayModel(width: $width, height: $height, tileWidth: $tileWidth, tileHeight: $tileHeight, thumbnailCount: $thumbnailCount, interval: $interval, images: $images)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$TrickPlayModelImpl && + (identical(other.width, width) || other.width == width) && + (identical(other.height, height) || other.height == height) && + (identical(other.tileWidth, tileWidth) || + other.tileWidth == tileWidth) && + (identical(other.tileHeight, tileHeight) || + other.tileHeight == tileHeight) && + (identical(other.thumbnailCount, thumbnailCount) || + other.thumbnailCount == thumbnailCount) && + (identical(other.interval, interval) || + other.interval == interval) && + const DeepCollectionEquality().equals(other._images, _images)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, + width, + height, + tileWidth, + tileHeight, + thumbnailCount, + interval, + const DeepCollectionEquality().hash(_images)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$TrickPlayModelImplCopyWith<_$TrickPlayModelImpl> get copyWith => + __$$TrickPlayModelImplCopyWithImpl<_$TrickPlayModelImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$TrickPlayModelImplToJson( + this, + ); + } +} + +abstract class _TrickPlayModel extends TrickPlayModel { + factory _TrickPlayModel( + {required final int width, + required final int height, + required final int tileWidth, + required final int tileHeight, + required final int thumbnailCount, + required final Duration interval, + final List images}) = _$TrickPlayModelImpl; + _TrickPlayModel._() : super._(); + + factory _TrickPlayModel.fromJson(Map json) = + _$TrickPlayModelImpl.fromJson; + + @override + int get width; + @override + int get height; + @override + int get tileWidth; + @override + int get tileHeight; + @override + int get thumbnailCount; + @override + Duration get interval; + @override + List get images; + @override + @JsonKey(ignore: true) + _$$TrickPlayModelImplCopyWith<_$TrickPlayModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/items/trick_play_model.g.dart b/lib/models/items/trick_play_model.g.dart new file mode 100644 index 0000000..fb17ee6 --- /dev/null +++ b/lib/models/items/trick_play_model.g.dart @@ -0,0 +1,33 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'trick_play_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$TrickPlayModelImpl _$$TrickPlayModelImplFromJson(Map json) => + _$TrickPlayModelImpl( + width: (json['width'] as num).toInt(), + height: (json['height'] as num).toInt(), + tileWidth: (json['tileWidth'] as num).toInt(), + tileHeight: (json['tileHeight'] as num).toInt(), + thumbnailCount: (json['thumbnailCount'] as num).toInt(), + interval: Duration(microseconds: (json['interval'] as num).toInt()), + images: (json['images'] as List?) + ?.map((e) => e as String) + .toList() ?? + const [], + ); + +Map _$$TrickPlayModelImplToJson( + _$TrickPlayModelImpl instance) => + { + 'width': instance.width, + 'height': instance.height, + 'tileWidth': instance.tileWidth, + 'tileHeight': instance.tileHeight, + 'thumbnailCount': instance.thumbnailCount, + 'interval': instance.interval.inMicroseconds, + 'images': instance.images, + }; diff --git a/lib/models/library_model.dart b/lib/models/library_model.dart new file mode 100644 index 0000000..1a0dd90 --- /dev/null +++ b/lib/models/library_model.dart @@ -0,0 +1,61 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.dart' as enums; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/photos_model.dart'; +import 'package:fladder/models/recommended_model.dart'; + +class LibraryModel { + final bool loading; + final String id; + final String name; + final List timelinePhotos; + final List posters; + final List recommendations; + final List genres; + final List latest; + final List nextUp; + final List favourites; + final enums.BaseItemKind type; + + LibraryModel({ + this.loading = false, + required this.id, + required this.name, + this.timelinePhotos = const [], + this.posters = const [], + this.recommendations = const [], + this.genres = const [], + this.latest = const [], + this.nextUp = const [], + this.favourites = const [], + required this.type, + }); + + LibraryModel copyWith({ + bool? loading, + String? id, + String? name, + List? timelinePhotos, + List? posters, + List? recommendations, + List? genres, + List? latest, + List? nextUp, + List? favourites, + enums.BaseItemKind? type, + }) { + return LibraryModel( + loading: loading ?? this.loading, + id: id ?? this.id, + name: name ?? this.name, + timelinePhotos: timelinePhotos ?? this.timelinePhotos, + posters: posters ?? this.posters, + recommendations: recommendations ?? this.recommendations, + genres: genres ?? this.genres, + latest: latest ?? this.latest, + nextUp: nextUp ?? this.nextUp, + favourites: favourites ?? this.favourites, + type: type ?? this.type, + ); + } +} diff --git a/lib/models/library_search/library_search_model.dart b/lib/models/library_search/library_search_model.dart new file mode 100644 index 0000000..e1bcc73 --- /dev/null +++ b/lib/models/library_search/library_search_model.dart @@ -0,0 +1,223 @@ +import 'package:collection/collection.dart'; +import 'package:dart_mappable/dart_mappable.dart'; +import 'package:fladder/util/list_extensions.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/models/library_search/library_search_options.dart'; +import 'package:fladder/models/view_model.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/map_bool_helper.dart'; + +part 'library_search_model.mapper.dart'; + +@MappableClass() +class LibrarySearchModel with LibrarySearchModelMappable { + final bool loading; + final bool selecteMode; + final String searchQuery; + final List folderOverwrite; + final Map views; + final List posters; + final List selectedPosters; + final Map filters; + final Map genres; + final Map studios; + final Map tags; + final Map years; + final Map officialRatings; + final Map types; + final SortingOptions sortingOption; + final SortingOrder sortOrder; + final bool favourites; + final bool hideEmtpyShows; + final bool recursive; + final GroupBy groupBy; + final Map lastIndices; + final Map libraryItemCounts; + final bool fetchingItems; + + const LibrarySearchModel({ + this.loading = false, + this.selecteMode = false, + this.folderOverwrite = const [], + this.searchQuery = "", + this.views = const {}, + this.posters = const [], + this.selectedPosters = const [], + this.filters = const { + ItemFilter.isplayed: false, + ItemFilter.isunplayed: false, + ItemFilter.isresumable: false, + }, + this.genres = const {}, + this.studios = const {}, + this.tags = const {}, + this.years = const {}, + this.officialRatings = const {}, + this.types = const { + FladderItemType.audio: false, + FladderItemType.boxset: false, + FladderItemType.book: false, + FladderItemType.collectionFolder: false, + FladderItemType.episode: false, + FladderItemType.folder: false, + FladderItemType.movie: true, + FladderItemType.musicAlbum: false, + FladderItemType.musicVideo: false, + FladderItemType.photo: false, + FladderItemType.person: false, + FladderItemType.photoalbum: false, + FladderItemType.series: true, + FladderItemType.video: true, + }, + this.favourites = false, + this.sortingOption = SortingOptions.name, + this.sortOrder = SortingOrder.ascending, + this.hideEmtpyShows = true, + this.recursive = false, + this.groupBy = GroupBy.none, + this.lastIndices = const {}, + this.libraryItemCounts = const {}, + this.fetchingItems = false, + }); + + bool get hasActiveFilters { + return genres.hasEnabled || + studios.hasEnabled || + tags.hasEnabled || + years.hasEnabled || + officialRatings.hasEnabled || + hideEmtpyShows || + filters.hasEnabled || + favourites || + searchQuery.isNotEmpty; + } + + int get totalItemCount { + if (libraryItemCounts.isEmpty) return posters.length; + int totalCount = 0; + for (var item in libraryItemCounts.values) { + totalCount += item; + } + return totalCount; + } + + bool get allDoneFetching { + if (libraryItemCounts.isEmpty) return false; + if (libraryItemCounts.length != lastIndices.length) { + return false; + } else { + for (var item in libraryItemCounts.entries) { + if (lastIndices[item.key] != item.value) { + return false; + } + } + } + return true; + } + + String searchBarTitle(BuildContext context) { + if (folderOverwrite.isNotEmpty) { + return "${context.localized.search} ${folderOverwrite.last.name}..."; + } + return views.included.length == 1 + ? "${context.localized.search} ${views.included.first.name}..." + : "${context.localized.search} ${context.localized.library(2)}..."; + } + + ItemBaseModel? get nestedCurrentItem => folderOverwrite.lastOrNull; + + List get activePosters => selectedPosters.isNotEmpty ? selectedPosters : posters; + + bool get showPlayButtons { + if (totalItemCount == 0) return false; + return types.included.isEmpty || + types.included.containsAny( + {...FladderItemType.playable, FladderItemType.folder}, + ); + } + + bool get showGalleryButtons { + if (totalItemCount == 0) return false; + return types.included.isEmpty || + types.included.containsAny( + {...FladderItemType.galleryItem, FladderItemType.photoalbum, FladderItemType.folder}, + ); + } + + LibrarySearchModel resetLazyLoad() { + return copyWith( + selectedPosters: [], + lastIndices: const {}, + libraryItemCounts: const {}, + ); + } + + LibrarySearchModel fullReset() { + return copyWith( + posters: [], + selectedPosters: [], + lastIndices: const {}, + libraryItemCounts: const {}, + ); + } + + LibrarySearchModel setFiltersToDefault() { + return copyWith( + genres: const {}, + tags: const {}, + officialRatings: const {}, + years: const {}, + searchQuery: '', + favourites: false, + recursive: false, + studios: const {}, + hideEmtpyShows: true, + ); + } + + @override + bool operator ==(covariant LibrarySearchModel other) { + if (identical(this, other)) return true; + + return other.searchQuery == searchQuery && + listEquals(other.folderOverwrite, folderOverwrite) && + mapEquals(other.views, views) && + mapEquals(other.filters, filters) && + mapEquals(other.genres, genres) && + mapEquals(other.studios, studios) && + mapEquals(other.tags, tags) && + mapEquals(other.years, years) && + mapEquals(other.officialRatings, officialRatings) && + mapEquals(other.types, types) && + other.sortingOption == sortingOption && + other.sortOrder == sortOrder && + other.favourites == favourites && + other.recursive == recursive; + } + + @override + int get hashCode { + return searchQuery.hashCode ^ + folderOverwrite.hashCode ^ + views.hashCode ^ + posters.hashCode ^ + selectedPosters.hashCode ^ + filters.hashCode ^ + genres.hashCode ^ + studios.hashCode ^ + tags.hashCode ^ + years.hashCode ^ + officialRatings.hashCode ^ + types.hashCode ^ + sortingOption.hashCode ^ + sortOrder.hashCode ^ + favourites.hashCode ^ + recursive.hashCode; + } +} diff --git a/lib/models/library_search/library_search_model.mapper.dart b/lib/models/library_search/library_search_model.mapper.dart new file mode 100644 index 0000000..2ffe0c8 --- /dev/null +++ b/lib/models/library_search/library_search_model.mapper.dart @@ -0,0 +1,418 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member +// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter + +part of 'library_search_model.dart'; + +class LibrarySearchModelMapper extends ClassMapperBase { + LibrarySearchModelMapper._(); + + static LibrarySearchModelMapper? _instance; + static LibrarySearchModelMapper ensureInitialized() { + if (_instance == null) { + MapperContainer.globals.use(_instance = LibrarySearchModelMapper._()); + ItemBaseModelMapper.ensureInitialized(); + } + return _instance!; + } + + @override + final String id = 'LibrarySearchModel'; + + static bool _$loading(LibrarySearchModel v) => v.loading; + static const Field _f$loading = + Field('loading', _$loading, opt: true, def: false); + static bool _$selecteMode(LibrarySearchModel v) => v.selecteMode; + static const Field _f$selecteMode = + Field('selecteMode', _$selecteMode, opt: true, def: false); + static List _$folderOverwrite(LibrarySearchModel v) => + v.folderOverwrite; + static const Field> + _f$folderOverwrite = + Field('folderOverwrite', _$folderOverwrite, opt: true, def: const []); + static String _$searchQuery(LibrarySearchModel v) => v.searchQuery; + static const Field _f$searchQuery = + Field('searchQuery', _$searchQuery, opt: true, def: ""); + static Map _$views(LibrarySearchModel v) => v.views; + static const Field> _f$views = + Field('views', _$views, opt: true, def: const {}); + static List _$posters(LibrarySearchModel v) => v.posters; + static const Field> _f$posters = + Field('posters', _$posters, opt: true, def: const []); + static List _$selectedPosters(LibrarySearchModel v) => + v.selectedPosters; + static const Field> + _f$selectedPosters = + Field('selectedPosters', _$selectedPosters, opt: true, def: const []); + static Map _$filters(LibrarySearchModel v) => v.filters; + static const Field> _f$filters = + Field('filters', _$filters, opt: true, def: const { + ItemFilter.isplayed: false, + ItemFilter.isunplayed: false, + ItemFilter.isresumable: false + }); + static Map _$genres(LibrarySearchModel v) => v.genres; + static const Field> _f$genres = + Field('genres', _$genres, opt: true, def: const {}); + static Map _$studios(LibrarySearchModel v) => v.studios; + static const Field> _f$studios = + Field('studios', _$studios, opt: true, def: const {}); + static Map _$tags(LibrarySearchModel v) => v.tags; + static const Field> _f$tags = + Field('tags', _$tags, opt: true, def: const {}); + static Map _$years(LibrarySearchModel v) => v.years; + static const Field> _f$years = + Field('years', _$years, opt: true, def: const {}); + static Map _$officialRatings(LibrarySearchModel v) => + v.officialRatings; + static const Field> _f$officialRatings = + Field('officialRatings', _$officialRatings, opt: true, def: const {}); + static Map _$types(LibrarySearchModel v) => v.types; + static const Field> _f$types = + Field('types', _$types, opt: true, def: const { + FladderItemType.audio: false, + FladderItemType.boxset: false, + FladderItemType.book: false, + FladderItemType.collectionFolder: false, + FladderItemType.episode: false, + FladderItemType.folder: false, + FladderItemType.movie: true, + FladderItemType.musicAlbum: false, + FladderItemType.musicVideo: false, + FladderItemType.photo: false, + FladderItemType.person: false, + FladderItemType.photoalbum: false, + FladderItemType.series: true, + FladderItemType.video: true + }); + static bool _$favourites(LibrarySearchModel v) => v.favourites; + static const Field _f$favourites = + Field('favourites', _$favourites, opt: true, def: false); + static SortingOptions _$sortingOption(LibrarySearchModel v) => + v.sortingOption; + static const Field _f$sortingOption = + Field('sortingOption', _$sortingOption, + opt: true, def: SortingOptions.name); + static SortingOrder _$sortOrder(LibrarySearchModel v) => v.sortOrder; + static const Field _f$sortOrder = + Field('sortOrder', _$sortOrder, opt: true, def: SortingOrder.ascending); + static bool _$hideEmtpyShows(LibrarySearchModel v) => v.hideEmtpyShows; + static const Field _f$hideEmtpyShows = + Field('hideEmtpyShows', _$hideEmtpyShows, opt: true, def: true); + static bool _$recursive(LibrarySearchModel v) => v.recursive; + static const Field _f$recursive = + Field('recursive', _$recursive, opt: true, def: false); + static GroupBy _$groupBy(LibrarySearchModel v) => v.groupBy; + static const Field _f$groupBy = + Field('groupBy', _$groupBy, opt: true, def: GroupBy.none); + static Map _$lastIndices(LibrarySearchModel v) => v.lastIndices; + static const Field> _f$lastIndices = + Field('lastIndices', _$lastIndices, opt: true, def: const {}); + static Map _$libraryItemCounts(LibrarySearchModel v) => + v.libraryItemCounts; + static const Field> + _f$libraryItemCounts = + Field('libraryItemCounts', _$libraryItemCounts, opt: true, def: const {}); + static bool _$fetchingItems(LibrarySearchModel v) => v.fetchingItems; + static const Field _f$fetchingItems = + Field('fetchingItems', _$fetchingItems, opt: true, def: false); + + @override + final MappableFields fields = const { + #loading: _f$loading, + #selecteMode: _f$selecteMode, + #folderOverwrite: _f$folderOverwrite, + #searchQuery: _f$searchQuery, + #views: _f$views, + #posters: _f$posters, + #selectedPosters: _f$selectedPosters, + #filters: _f$filters, + #genres: _f$genres, + #studios: _f$studios, + #tags: _f$tags, + #years: _f$years, + #officialRatings: _f$officialRatings, + #types: _f$types, + #favourites: _f$favourites, + #sortingOption: _f$sortingOption, + #sortOrder: _f$sortOrder, + #hideEmtpyShows: _f$hideEmtpyShows, + #recursive: _f$recursive, + #groupBy: _f$groupBy, + #lastIndices: _f$lastIndices, + #libraryItemCounts: _f$libraryItemCounts, + #fetchingItems: _f$fetchingItems, + }; + @override + final bool ignoreNull = true; + + static LibrarySearchModel _instantiate(DecodingData data) { + return LibrarySearchModel( + loading: data.dec(_f$loading), + selecteMode: data.dec(_f$selecteMode), + folderOverwrite: data.dec(_f$folderOverwrite), + searchQuery: data.dec(_f$searchQuery), + views: data.dec(_f$views), + posters: data.dec(_f$posters), + selectedPosters: data.dec(_f$selectedPosters), + filters: data.dec(_f$filters), + genres: data.dec(_f$genres), + studios: data.dec(_f$studios), + tags: data.dec(_f$tags), + years: data.dec(_f$years), + officialRatings: data.dec(_f$officialRatings), + types: data.dec(_f$types), + favourites: data.dec(_f$favourites), + sortingOption: data.dec(_f$sortingOption), + sortOrder: data.dec(_f$sortOrder), + hideEmtpyShows: data.dec(_f$hideEmtpyShows), + recursive: data.dec(_f$recursive), + groupBy: data.dec(_f$groupBy), + lastIndices: data.dec(_f$lastIndices), + libraryItemCounts: data.dec(_f$libraryItemCounts), + fetchingItems: data.dec(_f$fetchingItems)); + } + + @override + final Function instantiate = _instantiate; + + static LibrarySearchModel fromMap(Map map) { + return ensureInitialized().decodeMap(map); + } + + static LibrarySearchModel fromJson(String json) { + return ensureInitialized().decodeJson(json); + } +} + +mixin LibrarySearchModelMappable { + String toJson() { + return LibrarySearchModelMapper.ensureInitialized() + .encodeJson(this as LibrarySearchModel); + } + + Map toMap() { + return LibrarySearchModelMapper.ensureInitialized() + .encodeMap(this as LibrarySearchModel); + } + + LibrarySearchModelCopyWith + get copyWith => _LibrarySearchModelCopyWithImpl( + this as LibrarySearchModel, $identity, $identity); + @override + String toString() { + return LibrarySearchModelMapper.ensureInitialized() + .stringifyValue(this as LibrarySearchModel); + } +} + +extension LibrarySearchModelValueCopy<$R, $Out> + on ObjectCopyWith<$R, LibrarySearchModel, $Out> { + LibrarySearchModelCopyWith<$R, LibrarySearchModel, $Out> + get $asLibrarySearchModel => + $base.as((v, t, t2) => _LibrarySearchModelCopyWithImpl(v, t, t2)); +} + +abstract class LibrarySearchModelCopyWith<$R, $In extends LibrarySearchModel, + $Out> implements ClassCopyWith<$R, $In, $Out> { + ListCopyWith<$R, ItemBaseModel, + ItemBaseModelCopyWith<$R, ItemBaseModel, ItemBaseModel>> + get folderOverwrite; + MapCopyWith<$R, ViewModel, bool, ObjectCopyWith<$R, bool, bool>> get views; + ListCopyWith<$R, ItemBaseModel, + ItemBaseModelCopyWith<$R, ItemBaseModel, ItemBaseModel>> get posters; + ListCopyWith<$R, ItemBaseModel, + ItemBaseModelCopyWith<$R, ItemBaseModel, ItemBaseModel>> + get selectedPosters; + MapCopyWith<$R, ItemFilter, bool, ObjectCopyWith<$R, bool, bool>> get filters; + MapCopyWith<$R, String, bool, ObjectCopyWith<$R, bool, bool>> get genres; + MapCopyWith<$R, Studio, bool, ObjectCopyWith<$R, bool, bool>> get studios; + MapCopyWith<$R, String, bool, ObjectCopyWith<$R, bool, bool>> get tags; + MapCopyWith<$R, int, bool, ObjectCopyWith<$R, bool, bool>> get years; + MapCopyWith<$R, String, bool, ObjectCopyWith<$R, bool, bool>> + get officialRatings; + MapCopyWith<$R, FladderItemType, bool, ObjectCopyWith<$R, bool, bool>> + get types; + MapCopyWith<$R, String, int, ObjectCopyWith<$R, int, int>> get lastIndices; + MapCopyWith<$R, String, int, ObjectCopyWith<$R, int, int>> + get libraryItemCounts; + $R call( + {bool? loading, + bool? selecteMode, + List? folderOverwrite, + String? searchQuery, + Map? views, + List? posters, + List? selectedPosters, + Map? filters, + Map? genres, + Map? studios, + Map? tags, + Map? years, + Map? officialRatings, + Map? types, + bool? favourites, + SortingOptions? sortingOption, + SortingOrder? sortOrder, + bool? hideEmtpyShows, + bool? recursive, + GroupBy? groupBy, + Map? lastIndices, + Map? libraryItemCounts, + bool? fetchingItems}); + LibrarySearchModelCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t); +} + +class _LibrarySearchModelCopyWithImpl<$R, $Out> + extends ClassCopyWithBase<$R, LibrarySearchModel, $Out> + implements LibrarySearchModelCopyWith<$R, LibrarySearchModel, $Out> { + _LibrarySearchModelCopyWithImpl(super.value, super.then, super.then2); + + @override + late final ClassMapperBase $mapper = + LibrarySearchModelMapper.ensureInitialized(); + @override + ListCopyWith<$R, ItemBaseModel, + ItemBaseModelCopyWith<$R, ItemBaseModel, ItemBaseModel>> + get folderOverwrite => ListCopyWith($value.folderOverwrite, + (v, t) => v.copyWith.$chain(t), (v) => call(folderOverwrite: v)); + @override + MapCopyWith<$R, ViewModel, bool, ObjectCopyWith<$R, bool, bool>> get views => + MapCopyWith($value.views, (v, t) => ObjectCopyWith(v, $identity, t), + (v) => call(views: v)); + @override + ListCopyWith<$R, ItemBaseModel, + ItemBaseModelCopyWith<$R, ItemBaseModel, ItemBaseModel>> + get posters => ListCopyWith($value.posters, + (v, t) => v.copyWith.$chain(t), (v) => call(posters: v)); + @override + ListCopyWith<$R, ItemBaseModel, + ItemBaseModelCopyWith<$R, ItemBaseModel, ItemBaseModel>> + get selectedPosters => ListCopyWith($value.selectedPosters, + (v, t) => v.copyWith.$chain(t), (v) => call(selectedPosters: v)); + @override + MapCopyWith<$R, ItemFilter, bool, ObjectCopyWith<$R, bool, bool>> + get filters => MapCopyWith($value.filters, + (v, t) => ObjectCopyWith(v, $identity, t), (v) => call(filters: v)); + @override + MapCopyWith<$R, String, bool, ObjectCopyWith<$R, bool, bool>> get genres => + MapCopyWith($value.genres, (v, t) => ObjectCopyWith(v, $identity, t), + (v) => call(genres: v)); + @override + MapCopyWith<$R, Studio, bool, ObjectCopyWith<$R, bool, bool>> get studios => + MapCopyWith($value.studios, (v, t) => ObjectCopyWith(v, $identity, t), + (v) => call(studios: v)); + @override + MapCopyWith<$R, String, bool, ObjectCopyWith<$R, bool, bool>> get tags => + MapCopyWith($value.tags, (v, t) => ObjectCopyWith(v, $identity, t), + (v) => call(tags: v)); + @override + MapCopyWith<$R, int, bool, ObjectCopyWith<$R, bool, bool>> get years => + MapCopyWith($value.years, (v, t) => ObjectCopyWith(v, $identity, t), + (v) => call(years: v)); + @override + MapCopyWith<$R, String, bool, ObjectCopyWith<$R, bool, bool>> + get officialRatings => MapCopyWith( + $value.officialRatings, + (v, t) => ObjectCopyWith(v, $identity, t), + (v) => call(officialRatings: v)); + @override + MapCopyWith<$R, FladderItemType, bool, ObjectCopyWith<$R, bool, bool>> + get types => MapCopyWith($value.types, + (v, t) => ObjectCopyWith(v, $identity, t), (v) => call(types: v)); + @override + MapCopyWith<$R, String, int, ObjectCopyWith<$R, int, int>> get lastIndices => + MapCopyWith($value.lastIndices, (v, t) => ObjectCopyWith(v, $identity, t), + (v) => call(lastIndices: v)); + @override + MapCopyWith<$R, String, int, ObjectCopyWith<$R, int, int>> + get libraryItemCounts => MapCopyWith( + $value.libraryItemCounts, + (v, t) => ObjectCopyWith(v, $identity, t), + (v) => call(libraryItemCounts: v)); + @override + $R call( + {bool? loading, + bool? selecteMode, + List? folderOverwrite, + String? searchQuery, + Map? views, + List? posters, + List? selectedPosters, + Map? filters, + Map? genres, + Map? studios, + Map? tags, + Map? years, + Map? officialRatings, + Map? types, + bool? favourites, + SortingOptions? sortingOption, + SortingOrder? sortOrder, + bool? hideEmtpyShows, + bool? recursive, + GroupBy? groupBy, + Map? lastIndices, + Map? libraryItemCounts, + bool? fetchingItems}) => + $apply(FieldCopyWithData({ + if (loading != null) #loading: loading, + if (selecteMode != null) #selecteMode: selecteMode, + if (folderOverwrite != null) #folderOverwrite: folderOverwrite, + if (searchQuery != null) #searchQuery: searchQuery, + if (views != null) #views: views, + if (posters != null) #posters: posters, + if (selectedPosters != null) #selectedPosters: selectedPosters, + if (filters != null) #filters: filters, + if (genres != null) #genres: genres, + if (studios != null) #studios: studios, + if (tags != null) #tags: tags, + if (years != null) #years: years, + if (officialRatings != null) #officialRatings: officialRatings, + if (types != null) #types: types, + if (favourites != null) #favourites: favourites, + if (sortingOption != null) #sortingOption: sortingOption, + if (sortOrder != null) #sortOrder: sortOrder, + if (hideEmtpyShows != null) #hideEmtpyShows: hideEmtpyShows, + if (recursive != null) #recursive: recursive, + if (groupBy != null) #groupBy: groupBy, + if (lastIndices != null) #lastIndices: lastIndices, + if (libraryItemCounts != null) #libraryItemCounts: libraryItemCounts, + if (fetchingItems != null) #fetchingItems: fetchingItems + })); + @override + LibrarySearchModel $make(CopyWithData data) => LibrarySearchModel( + loading: data.get(#loading, or: $value.loading), + selecteMode: data.get(#selecteMode, or: $value.selecteMode), + folderOverwrite: data.get(#folderOverwrite, or: $value.folderOverwrite), + searchQuery: data.get(#searchQuery, or: $value.searchQuery), + views: data.get(#views, or: $value.views), + posters: data.get(#posters, or: $value.posters), + selectedPosters: data.get(#selectedPosters, or: $value.selectedPosters), + filters: data.get(#filters, or: $value.filters), + genres: data.get(#genres, or: $value.genres), + studios: data.get(#studios, or: $value.studios), + tags: data.get(#tags, or: $value.tags), + years: data.get(#years, or: $value.years), + officialRatings: data.get(#officialRatings, or: $value.officialRatings), + types: data.get(#types, or: $value.types), + favourites: data.get(#favourites, or: $value.favourites), + sortingOption: data.get(#sortingOption, or: $value.sortingOption), + sortOrder: data.get(#sortOrder, or: $value.sortOrder), + hideEmtpyShows: data.get(#hideEmtpyShows, or: $value.hideEmtpyShows), + recursive: data.get(#recursive, or: $value.recursive), + groupBy: data.get(#groupBy, or: $value.groupBy), + lastIndices: data.get(#lastIndices, or: $value.lastIndices), + libraryItemCounts: + data.get(#libraryItemCounts, or: $value.libraryItemCounts), + fetchingItems: data.get(#fetchingItems, or: $value.fetchingItems)); + + @override + LibrarySearchModelCopyWith<$R2, LibrarySearchModel, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t) => + _LibrarySearchModelCopyWithImpl($value, $cast, t); +} diff --git a/lib/models/library_search/library_search_options.dart b/lib/models/library_search/library_search_options.dart new file mode 100644 index 0000000..adcd681 --- /dev/null +++ b/lib/models/library_search/library_search_options.dart @@ -0,0 +1,127 @@ +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/util/localization_helper.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:flutter/material.dart'; + +enum SortingOptions { + name([ItemSortBy.name]), + communityRating([ItemSortBy.communityrating]), + // criticsRating([ItemSortBy.criticrating]), + parentalRating([ItemSortBy.officialrating]), + dateAdded([ItemSortBy.datecreated]), + dateLastContentAdded([ItemSortBy.datelastcontentadded]), + favorite([ItemSortBy.isfavoriteorliked]), + datePlayed([ItemSortBy.dateplayed]), + folders([ItemSortBy.isfolder]), + playCount([ItemSortBy.playcount]), + releaseDate([ItemSortBy.productionyear, ItemSortBy.premieredate]), + runTime([ItemSortBy.runtime]), + random([ItemSortBy.random]); + + const SortingOptions(this.value); + final List value; + + List get toSortBy => [...value, ItemSortBy.name]; + + String label(BuildContext context) => switch (this) { + name => context.localized.name, + communityRating => context.localized.communityRating, + parentalRating => context.localized.parentalRating, + dateAdded => context.localized.dateAdded, + dateLastContentAdded => context.localized.dateLastContentAdded, + favorite => context.localized.favorite, + datePlayed => context.localized.datePlayed, + folders => context.localized.folders, + playCount => context.localized.playCount, + releaseDate => context.localized.releaseDate, + runTime => context.localized.runTime, + random => context.localized.random, + }; +} + +enum GroupBy { + none, + name, + genres, + dateAdded, + tags, + releaseDate, + rating, + type; + + String value(BuildContext context) => switch (this) { + GroupBy.none => context.localized.none, + GroupBy.name => context.localized.name, + GroupBy.genres => context.localized.genre(1), + GroupBy.dateAdded => context.localized.dateAdded, + GroupBy.tags => context.localized.tag(1), + GroupBy.releaseDate => context.localized.releaseDate, + GroupBy.rating => context.localized.rating(1), + GroupBy.type => context.localized.type(1), + }; +} + +enum SortingOrder { + ascending, + descending; + + SortOrder get sortOrder => switch (this) { + ascending => SortOrder.ascending, + descending => SortOrder.descending, + }; + + String label(BuildContext context) => switch (this) { + ascending => context.localized.ascending, + descending => context.localized.descending, + }; +} + +extension ItemFilterExtension on ItemFilter { + String label(BuildContext context) { + return switch (this) { + ItemFilter.isplayed => context.localized.played, + ItemFilter.isunplayed => context.localized.unPlayed, + ItemFilter.isresumable => context.localized.resumable, + _ => "", + }; + } +} + +int sortItems(ItemBaseModel a, ItemBaseModel b, SortingOptions sortingOption, SortingOrder sortingOrder) { + for (var sortBy in sortingOption.toSortBy) { + int comparison = 0; + switch (sortBy) { + case ItemSortBy.communityrating: + comparison = (a.overview.communityRating ?? 0).compareTo(b.overview.communityRating ?? 0); + break; + case ItemSortBy.isfavoriteorliked: + comparison = a.userData.isFavourite == b.userData.isFavourite + ? 0 + : a.userData.isFavourite + ? 1 + : -1; + break; + case ItemSortBy.dateplayed: + comparison = (a.userData.lastPlayed ?? DateTime(0)).compareTo(b.userData.lastPlayed ?? DateTime(0)); + break; + case ItemSortBy.playcount: + comparison = a.userData.playCount.compareTo(b.userData.playCount); + break; + case ItemSortBy.premieredate: + case ItemSortBy.productionyear: + comparison = (a.overview.productionYear ?? 0).compareTo(b.overview.productionYear ?? 0); + break; + case ItemSortBy.runtime: + comparison = (a.overview.runTime ?? Duration.zero).compareTo(b.overview.runTime ?? Duration.zero); + break; + default: + comparison = a.name.compareTo(b.name); + } + if (comparison != 0) { + return sortingOrder == SortingOrder.ascending ? comparison : -comparison; + } + } + return 0; +} diff --git a/lib/models/login_screen_model.dart b/lib/models/login_screen_model.dart new file mode 100644 index 0000000..c607bbc --- /dev/null +++ b/lib/models/login_screen_model.dart @@ -0,0 +1,26 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +import 'package:fladder/models/account_model.dart'; +import 'package:fladder/models/credentials_model.dart'; + +class LoginScreenModel { + final List accounts; + final CredentialsModel tempCredentials; + final bool loading; + LoginScreenModel({ + required this.accounts, + required this.tempCredentials, + required this.loading, + }); + + LoginScreenModel copyWith({ + List? accounts, + CredentialsModel? tempCredentials, + bool? loading, + }) { + return LoginScreenModel( + accounts: accounts ?? this.accounts, + tempCredentials: tempCredentials ?? this.tempCredentials, + loading: loading ?? this.loading, + ); + } +} diff --git a/lib/models/media_playback_model.dart b/lib/models/media_playback_model.dart new file mode 100644 index 0000000..4b38e97 --- /dev/null +++ b/lib/models/media_playback_model.dart @@ -0,0 +1,52 @@ +enum VideoPlayerState { + minimized, + fullScreen, + disposed, +} + +class MediaPlaybackModel { + final VideoPlayerState state; + final bool playing; + final Duration position; + final Duration lastPosition; + final Duration duration; + final Duration buffer; + final bool completed; + final bool errorPlaying; + final bool buffering; + MediaPlaybackModel({ + this.state = VideoPlayerState.disposed, + this.playing = false, + this.position = Duration.zero, + this.lastPosition = Duration.zero, + this.duration = Duration.zero, + this.buffer = Duration.zero, + this.completed = false, + this.errorPlaying = false, + this.buffering = false, + }); + + MediaPlaybackModel copyWith({ + VideoPlayerState? state, + bool? playing, + Duration? position, + Duration? lastPosition, + Duration? duration, + Duration? buffer, + bool? completed, + bool? errorPlaying, + bool? buffering, + }) { + return MediaPlaybackModel( + state: state ?? this.state, + playing: playing ?? this.playing, + position: position ?? this.position, + lastPosition: lastPosition ?? this.lastPosition, + duration: duration ?? this.duration, + buffer: buffer ?? this.buffer, + completed: completed ?? this.completed, + errorPlaying: errorPlaying ?? this.errorPlaying, + buffering: buffering ?? this.buffering, + ); + } +} diff --git a/lib/models/playback/direct_playback_model.dart b/lib/models/playback/direct_playback_model.dart new file mode 100644 index 0000000..818a101 --- /dev/null +++ b/lib/models/playback/direct_playback_model.dart @@ -0,0 +1,209 @@ +import 'package:collection/collection.dart'; +import 'package:fladder/models/items/trick_play_model.dart'; +import 'package:fladder/util/list_extensions.dart'; +import 'package:fladder/wrappers/media_control_wrapper.dart' + if (dart.library.html) 'package:fladder/wrappers/media_control_wrapper_web.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:media_kit/media_kit.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/chapters_model.dart'; +import 'package:fladder/models/items/intro_skip_model.dart'; +import 'package:fladder/models/items/media_streams_model.dart'; +import 'package:fladder/models/playback/playback_model.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:fladder/providers/video_player_provider.dart'; +import 'package:fladder/util/duration_extensions.dart'; + +class DirectPlaybackModel implements PlaybackModel { + DirectPlaybackModel({ + required this.item, + required this.media, + required this.playbackInfo, + this.mediaStreams, + this.introSkipModel, + this.chapters, + this.trickPlay, + this.queue = const [], + }); + + @override + final ItemBaseModel item; + + @override + final Media? media; + + @override + final PlaybackInfoResponse playbackInfo; + + @override + final MediaStreamsModel? mediaStreams; + + @override + final IntroOutSkipModel? introSkipModel; + + @override + final List? chapters; + + @override + final TrickPlayModel? trickPlay; + + @override + ItemBaseModel? get nextVideo => queue.nextOrNull(item); + + @override + ItemBaseModel? get previousVideo => queue.previousOrNull(item); + + @override + Future? startDuration() async => item.userData.playBackPosition; + + @override + List get subStreams => [SubStreamModel.no(), ...mediaStreams?.subStreams ?? []]; + + List get itemsInQueue => + queue.mapIndexed((index, element) => QueueItem(id: element.id, playlistItemId: "playlistItem$index")).toList(); + + @override + Future setSubtitle(SubStreamModel? model, MediaControlsWrapper player) async { + final wantedSubtitle = + model ?? subStreams.firstWhereOrNull((element) => element.index == mediaStreams?.defaultSubStreamIndex); + if (wantedSubtitle == null) return this; + if (wantedSubtitle.index == SubStreamModel.no().index) { + await player.setSubtitleTrack(SubtitleTrack.no()); + } else { + final subTracks = player.subTracks.getRange(2, player.subTracks.length).toList(); + final index = subStreams.sublist(1).indexWhere((element) => element.id == wantedSubtitle.id); + final subTrack = subTracks.elementAtOrNull(index); + if (wantedSubtitle.isExternal && wantedSubtitle.url != null && subTrack == null) { + await player.setSubtitleTrack(SubtitleTrack.uri(wantedSubtitle.url!)); + } else if (subTrack != null) { + await player.setSubtitleTrack(subTrack); + } + } + return copyWith(mediaStreams: () => mediaStreams?.copyWith(defaultSubStreamIndex: wantedSubtitle.index)); + } + + @override + List get audioStreams => [AudioStreamModel.no(), ...mediaStreams?.audioStreams ?? []]; + + @override + Future? setAudio(AudioStreamModel? model, MediaControlsWrapper player) async { + final wantedAudioStream = + model ?? audioStreams.firstWhereOrNull((element) => element.index == mediaStreams?.defaultAudioStreamIndex); + if (wantedAudioStream == null) return this; + if (wantedAudioStream.index == AudioStreamModel.no().index) { + await player.setAudioTrack(AudioTrack.no()); + } else { + final audioTracks = player.audioTracks.getRange(2, player.audioTracks.length).toList(); + final audioTrack = audioTracks.elementAtOrNull(audioStreams.indexOf(wantedAudioStream) - 1); + if (audioTrack != null) { + await player.setAudioTrack(audioTrack); + } + } + return copyWith(mediaStreams: () => mediaStreams?.copyWith(defaultAudioStreamIndex: wantedAudioStream.index)); + } + + @override + Future playbackStarted(Duration position, Ref ref) async { + await ref.read(jellyApiProvider).sessionsPlayingPost( + body: PlaybackStartInfo( + canSeek: true, + itemId: item.id, + mediaSourceId: item.id, + playSessionId: playbackInfo.playSessionId, + subtitleStreamIndex: item.streamModel?.defaultSubStreamIndex, + audioStreamIndex: item.streamModel?.defaultAudioStreamIndex, + volumeLevel: 100, + playbackStartTimeTicks: position.toRuntimeTicks, + playMethod: PlayMethod.directplay, + isMuted: false, + isPaused: false, + repeatMode: RepeatMode.repeatall, + nowPlayingQueue: itemsInQueue, + ), + ); + return null; + } + + @override + Future playbackStopped(Duration position, Duration? totalDuration, Ref ref) async { + ref.read(playBackModel.notifier).update((state) => null); + + await ref.read(jellyApiProvider).sessionsPlayingStoppedPost( + body: PlaybackStopInfo( + itemId: item.id, + mediaSourceId: item.id, + playSessionId: playbackInfo.playSessionId, + positionTicks: position.toRuntimeTicks, + failed: false, + nowPlayingQueue: itemsInQueue, + ), + totalDuration: totalDuration, + ); + + return null; + } + + @override + Future updatePlaybackPosition(Duration position, bool isPlaying, Ref ref) async { + final api = ref.read(jellyApiProvider); + + //Check for newly generated scrubImages + if (trickPlay == null) { + final trickplay = await api.getTrickPlay(item: item, ref: ref); + ref.read(playBackModel.notifier).update((state) => copyWith(trickPlay: () => trickplay?.body)); + } + + await api.sessionsPlayingProgressPost( + body: PlaybackProgressInfo( + canSeek: true, + itemId: item.id, + mediaSourceId: item.id, + playSessionId: playbackInfo.playSessionId, + subtitleStreamIndex: item.streamModel?.defaultSubStreamIndex, + audioStreamIndex: item.streamModel?.defaultAudioStreamIndex, + volumeLevel: 100, + playMethod: PlayMethod.directplay, + isPaused: !isPlaying, + isMuted: false, + positionTicks: position.toRuntimeTicks, + repeatMode: RepeatMode.repeatall, + nowPlayingQueue: itemsInQueue, + ), + ); + + return null; + } + + @override + String toString() => 'DirectPlaybackModel(item: $item, playbackInfo: $playbackInfo)'; + + @override + final List queue; + + @override + DirectPlaybackModel copyWith({ + ItemBaseModel? item, + ValueGetter? media, + ValueGetter? lastPosition, + PlaybackInfoResponse? playbackInfo, + ValueGetter? mediaStreams, + ValueGetter? introSkipModel, + ValueGetter?>? chapters, + ValueGetter? trickPlay, + List? queue, + }) { + return DirectPlaybackModel( + item: item ?? this.item, + media: media != null ? media() : this.media, + playbackInfo: playbackInfo ?? this.playbackInfo, + mediaStreams: mediaStreams != null ? mediaStreams() : this.mediaStreams, + introSkipModel: introSkipModel != null ? introSkipModel() : this.introSkipModel, + chapters: chapters != null ? chapters() : this.chapters, + trickPlay: trickPlay != null ? trickPlay() : this.trickPlay, + queue: queue ?? this.queue, + ); + } +} diff --git a/lib/models/playback/offline_playback_model.dart b/lib/models/playback/offline_playback_model.dart new file mode 100644 index 0000000..60dd1ca --- /dev/null +++ b/lib/models/playback/offline_playback_model.dart @@ -0,0 +1,175 @@ +import 'package:collection/collection.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/items/trick_play_model.dart'; +import 'package:fladder/models/syncing/sync_item.dart'; +import 'package:fladder/util/list_extensions.dart'; +import 'package:fladder/wrappers/media_control_wrapper.dart' + if (dart.library.html) 'package:fladder/wrappers/media_control_wrapper_web.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:media_kit/media_kit.dart'; + +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/chapters_model.dart'; +import 'package:fladder/models/items/intro_skip_model.dart'; +import 'package:fladder/models/items/media_streams_model.dart'; +import 'package:fladder/models/playback/playback_model.dart'; +import 'package:fladder/providers/sync_provider.dart'; +import 'package:fladder/util/duration_extensions.dart'; + +class OfflinePlaybackModel implements PlaybackModel { + OfflinePlaybackModel({ + required this.item, + required this.media, + required this.syncedItem, + this.mediaStreams, + this.playbackInfo, + this.introSkipModel, + this.trickPlay, + this.queue = const [], + this.syncedQueue = const [], + }); + + @override + final ItemBaseModel item; + + @override + final PlaybackInfoResponse? playbackInfo; + + @override + final Media? media; + + final SyncedItem syncedItem; + + @override + final MediaStreamsModel? mediaStreams; + + @override + final IntroOutSkipModel? introSkipModel; + + @override + List? get chapters => syncedItem.chapters; + + @override + final TrickPlayModel? trickPlay; + + @override + Future? startDuration() async => item.userData.playBackPosition; + + @override + ItemBaseModel? get nextVideo => queue.nextOrNull(item); + @override + ItemBaseModel? get previousVideo => queue.previousOrNull(item); + + @override + List get subStreams => [SubStreamModel.no(), ...syncedItem.subtitles]; + + @override + Future setSubtitle(SubStreamModel? model, MediaControlsWrapper player) async { + final wantedSubtitle = + model ?? subStreams.firstWhereOrNull((element) => element.index == mediaStreams?.defaultSubStreamIndex); + if (wantedSubtitle == null) return this; + if (wantedSubtitle.index == SubStreamModel.no().index) { + await player.setSubtitleTrack(SubtitleTrack.no()); + } else { + final subTracks = player.subTracks.getRange(2, player.subTracks.length).toList(); + final index = subStreams.sublist(1).indexWhere((element) => element.id == wantedSubtitle.id); + final subTrack = subTracks.elementAtOrNull(index); + if (wantedSubtitle.isExternal && wantedSubtitle.url != null && subTrack == null) { + await player.setSubtitleTrack(SubtitleTrack.uri(wantedSubtitle.url!)); + } else if (subTrack != null) { + await player.setSubtitleTrack(subTrack); + } + } + return copyWith(mediaStreams: () => mediaStreams?.copyWith(defaultSubStreamIndex: wantedSubtitle.index)); + } + + @override + List get audioStreams => [AudioStreamModel.no(), ...mediaStreams?.audioStreams ?? []]; + + @override + Future? setAudio(AudioStreamModel? model, MediaControlsWrapper player) async { + final wantedAudioStream = + model ?? audioStreams.firstWhereOrNull((element) => element.index == mediaStreams?.defaultAudioStreamIndex); + if (wantedAudioStream == null) return this; + if (wantedAudioStream.index == AudioStreamModel.no().index) { + await player.setAudioTrack(AudioTrack.no()); + } else { + final audioTracks = player.audioTracks.getRange(2, player.audioTracks.length).toList(); + final audioTrack = audioTracks.elementAtOrNull(audioStreams.indexOf(wantedAudioStream) - 1); + if (audioTrack != null) { + await player.setAudioTrack(audioTrack); + } + } + return copyWith(mediaStreams: () => mediaStreams?.copyWith(defaultAudioStreamIndex: wantedAudioStream.index)); + } + + @override + Future playbackStarted(Duration position, Ref ref) async { + return null; + } + + @override + Future playbackStopped(Duration position, Duration? totalDuration, Ref ref) async { + return null; + } + + @override + Future updatePlaybackPosition(Duration position, bool isPlaying, Ref ref) async { + final progress = position.inMilliseconds / (item.overview.runTime?.inMilliseconds ?? 0) * 100; + final newItem = syncedItem.copyWith( + userData: syncedItem.userData?.copyWith( + playbackPositionTicks: position.toRuntimeTicks, + progress: progress, + played: isPlayed(position, item.overview.runTime ?? Duration.zero), + ), + ); + await ref.read(syncProvider.notifier).updateItem(newItem); + return this; + } + + bool isPlayed(Duration position, Duration totalDuration) { + Duration startBuffer = totalDuration * 0.05; + Duration endBuffer = totalDuration * 0.90; + + Duration validStart = startBuffer; + Duration validEnd = endBuffer; + + if (position >= validStart && position <= validEnd) { + return true; + } + + return false; + } + + @override + String toString() => 'OfflinePlaybackModel(item: $item, syncedItem: $syncedItem)'; + + @override + final List queue; + + final List syncedQueue; + + @override + OfflinePlaybackModel copyWith({ + ItemBaseModel? item, + ValueGetter? media, + SyncedItem? syncedItem, + ValueGetter? mediaStreams, + ValueGetter? introSkipModel, + ValueGetter? trickPlay, + List? queue, + List? syncedQueue, + }) { + return OfflinePlaybackModel( + item: item ?? this.item, + media: media != null ? media() : this.media, + syncedItem: syncedItem ?? this.syncedItem, + mediaStreams: mediaStreams != null ? mediaStreams() : this.mediaStreams, + introSkipModel: introSkipModel != null ? introSkipModel() : this.introSkipModel, + trickPlay: trickPlay != null ? trickPlay() : this.trickPlay, + queue: queue ?? this.queue, + syncedQueue: syncedQueue ?? this.syncedQueue, + ); + } +} diff --git a/lib/models/playback/playback_model.dart b/lib/models/playback/playback_model.dart new file mode 100644 index 0000000..637291a --- /dev/null +++ b/lib/models/playback/playback_model.dart @@ -0,0 +1,370 @@ +import 'dart:developer'; + +import 'package:chopper/chopper.dart'; +import 'package:collection/collection.dart'; +import 'package:fladder/models/items/intro_skip_model.dart'; +import 'package:fladder/models/items/season_model.dart'; +import 'package:fladder/models/items/series_model.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:media_kit/media_kit.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/chapters_model.dart'; +import 'package:fladder/models/items/episode_model.dart'; +import 'package:fladder/models/items/media_streams_model.dart'; +import 'package:fladder/models/items/trick_play_model.dart'; +import 'package:fladder/models/playback/direct_playback_model.dart'; +import 'package:fladder/models/playback/offline_playback_model.dart'; +import 'package:fladder/models/playback/transcode_playback_model.dart'; +import 'package:fladder/models/syncing/sync_item.dart'; +import 'package:fladder/models/video_stream_model.dart'; +import 'package:fladder/profiles/default_profile.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:fladder/providers/service_provider.dart'; +import 'package:fladder/providers/sync/sync_provider_helpers.dart'; +import 'package:fladder/providers/sync_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/providers/video_player_provider.dart'; +import 'package:fladder/util/duration_extensions.dart'; +import 'package:fladder/wrappers/media_control_wrapper.dart' + if (dart.library.html) 'package:fladder/wrappers/media_control_wrapper_web.dart'; + +extension PlaybackModelExtension on PlaybackModel? { + String? get label => switch (this) { + DirectPlaybackModel _ => PlaybackType.directStream.name, + TranscodePlaybackModel _ => PlaybackType.transcode.name, + OfflinePlaybackModel _ => PlaybackType.offline.name, + _ => null + }; +} + +abstract class PlaybackModel { + final ItemBaseModel item = throw UnimplementedError(); + final Media? media = throw UnimplementedError(); + final List queue = const []; + final IntroOutSkipModel? introSkipModel = null; + final PlaybackInfoResponse? playbackInfo = throw UnimplementedError(); + + List? get chapters; + TrickPlayModel? get trickPlay; + + Future updatePlaybackPosition(Duration position, bool isPlaying, Ref ref) => + throw UnimplementedError(); + Future playbackStarted(Duration position, Ref ref) => throw UnimplementedError(); + Future playbackStopped(Duration position, Duration? totalDuration, Ref ref) => + throw UnimplementedError(); + + final MediaStreamsModel? mediaStreams = throw UnimplementedError(); + List? get subStreams; + List? get audioStreams; + + Future? startDuration() async => item.userData.playBackPosition; + Future? setSubtitle(SubStreamModel? model, MediaControlsWrapper player) { + return null; + } + + Future? setAudio(AudioStreamModel? model, MediaControlsWrapper player) => null; + + ItemBaseModel? get nextVideo => throw UnimplementedError(); + ItemBaseModel? get previousVideo => throw UnimplementedError(); + + PlaybackModel copyWith(); +} + +final playbackModelHelper = Provider((ref) { + return PlaybackModelHelper(ref: ref); +}); + +class PlaybackModelHelper { + const PlaybackModelHelper({required this.ref}); + + final Ref ref; + + JellyService get api => ref.read(jellyApiProvider); + + Future loadNewVideo(ItemBaseModel newItem) async { + ref.read(videoPlayerProvider).pause(); + ref.read(mediaPlaybackProvider.notifier).update((state) => state.copyWith(buffering: true)); + final currentModel = ref.read(playBackModel); + final newModel = (await createServerPlaybackModel( + newItem, + null, + oldModel: currentModel, + )) ?? + await createOfflinePlaybackModel( + newItem, + ref.read(syncProvider.notifier).getSyncedItem(newItem), + oldModel: currentModel, + ); + if (newModel == null) return null; + ref.read(videoPlayerProvider.notifier).loadPlaybackItem(newModel, startPosition: Duration.zero); + return newModel; + } + + Future createOfflinePlaybackModel( + ItemBaseModel item, + SyncedItem? syncedItem, { + PlaybackModel? oldModel, + }) async { + final ItemBaseModel? syncedItemModel = ref.read(syncProvider.notifier).getItem(syncedItem); + if (syncedItemModel == null || syncedItem == null || !syncedItem.dataFile.existsSync()) return null; + + final children = ref.read(syncChildrenProvider(syncedItem)); + final syncedItems = children.where((element) => element.videoFile.existsSync()).toList(); + final itemQueue = syncedItems.map((e) => e.createItemModel(ref)); + + return OfflinePlaybackModel( + item: syncedItemModel, + syncedItem: syncedItem, + trickPlay: syncedItem.trickPlayModel, + introSkipModel: syncedItem.introOutSkipModel, + media: Media(syncedItem.videoFile.path), + queue: itemQueue.whereNotNull().toList(), + syncedQueue: children, + mediaStreams: item.streamModel ?? syncedItemModel.streamModel, + ); + } + + Future getNextUpEpisode(String itemId) async { + final responnse = await api.showsNextUpGet(parentId: itemId, fields: [ItemFields.overview]); + final episode = responnse.body?.items?.firstOrNull; + if (episode == null) { + return null; + } else { + return EpisodeModel.fromBaseDto(episode, ref); + } + } + + Future createServerPlaybackModel(ItemBaseModel? item, PlaybackType? type, + {PlaybackModel? oldModel, List? libraryQueue, Duration? startPosition}) async { + try { + if (item == null) return null; + final userId = ref.read(userProvider)?.id; + if (userId?.isEmpty == true) return null; + + final queue = oldModel?.queue ?? libraryQueue ?? await collectQueue(item); + + final firstItemToPlay = switch (item) { + SeriesModel _ || SeasonModel _ => (await getNextUpEpisode(item.id) ?? queue.first), + _ => item, + }; + + final fullItem = await api.usersUserIdItemsItemIdGet(itemId: firstItemToPlay.id); + + final streamModel = firstItemToPlay.streamModel; + + Response response = await api.itemsItemIdPlaybackInfoPost( + itemId: firstItemToPlay.id, + enableDirectPlay: type != PlaybackType.transcode, + enableDirectStream: type != PlaybackType.transcode, + enableTranscoding: true, + autoOpenLiveStream: true, + startTimeTicks: startPosition?.toRuntimeTicks, + audioStreamIndex: streamModel?.defaultAudioStreamIndex, + subtitleStreamIndex: streamModel?.defaultSubStreamIndex, + mediaSourceId: firstItemToPlay.id, + body: PlaybackInfoDto( + startTimeTicks: startPosition?.toRuntimeTicks, + audioStreamIndex: streamModel?.defaultAudioStreamIndex, + subtitleStreamIndex: streamModel?.defaultSubStreamIndex, + enableTranscoding: true, + autoOpenLiveStream: true, + deviceProfile: defaultProfile, + userId: userId, + mediaSourceId: firstItemToPlay.id, + ), + ); + + PlaybackInfoResponse? playbackInfo = response.body; + if (playbackInfo == null) return null; + + final mediaSource = playbackInfo.mediaSources?.first; + + final mediaStreamsWithUrls = MediaStreamsModel.fromMediaStreamsList( + playbackInfo.mediaSources?.firstOrNull, playbackInfo.mediaSources?.firstOrNull?.mediaStreams ?? [], ref) + .copyWith( + defaultAudioStreamIndex: streamModel?.defaultAudioStreamIndex, + defaultSubStreamIndex: streamModel?.defaultSubStreamIndex, + ); + + final intro = await api.introSkipGet(id: item.id); + final trickPlay = (await api.getTrickPlay(item: fullItem.body, ref: ref))?.body; + final chapters = fullItem.body?.overview.chapters ?? []; + + if (mediaSource == null) return null; + + if ((mediaSource.supportsDirectStream ?? false) || (mediaSource.supportsDirectPlay ?? false)) { + final Map directOptions = { + 'Static': 'true', + 'mediaSourceId': mediaSource.id, + 'api_key': ref.read(userProvider)?.credentials.token, + }; + + if (mediaSource.eTag != null) { + directOptions['Tag'] = mediaSource.eTag; + } + + if (mediaSource.liveStreamId != null) { + directOptions['LiveStreamId'] = mediaSource.liveStreamId; + } + + final params = Uri(queryParameters: directOptions).query; + + return DirectPlaybackModel( + item: fullItem.body ?? item, + queue: queue, + introSkipModel: intro?.body, + chapters: chapters, + playbackInfo: playbackInfo, + trickPlay: trickPlay, + media: Media('${ref.read(userProvider)?.server ?? ""}/Videos/${mediaSource.id}/stream?$params'), + mediaStreams: mediaStreamsWithUrls, + ); + } else if ((mediaSource.supportsTranscoding ?? false) && mediaSource.transcodingUrl != null) { + return TranscodePlaybackModel( + item: fullItem.body ?? item, + queue: queue, + introSkipModel: intro?.body, + chapters: chapters, + trickPlay: trickPlay, + playbackInfo: playbackInfo, + media: Media("${ref.read(userProvider)?.server ?? ""}${mediaSource.transcodingUrl ?? ""}"), + mediaStreams: mediaStreamsWithUrls, + ); + } + return null; + } catch (e) { + log(e.toString()); + return null; + } + } + + Future> collectQueue(ItemBaseModel model) async { + switch (model) { + case EpisodeModel _: + case SeriesModel _: + case SeasonModel _: + List episodeList = ((await fetchEpisodesFromSeries(model.streamId)).body ?? []) + ..removeWhere((element) => element.status != EpisodeStatus.available); + return episodeList; + default: + return []; + } + } + + Future>> fetchEpisodesFromSeries(String seriesId) async { + final response = await api.showsSeriesIdEpisodesGet( + seriesId: seriesId, + fields: [ + ItemFields.overview, + ItemFields.originaltitle, + ItemFields.mediastreams, + ItemFields.mediasources, + ItemFields.mediasourcecount, + ItemFields.width, + ItemFields.height, + ], + ); + return Response(response.base, (response.body?.items?.map((e) => EpisodeModel.fromBaseDto(e, ref)).toList() ?? [])); + } + + Future shouldReload(PlaybackModel playbackModel) async { + if (playbackModel is OfflinePlaybackModel) { + return; + } + + final item = playbackModel.item; + + final userId = ref.read(userProvider)?.id; + if (userId?.isEmpty == true) return; + + final currentPosition = ref.read(mediaPlaybackProvider.select((value) => value.position)); + + final audioIndex = playbackModel.mediaStreams?.defaultAudioStreamIndex; + final subIndex = playbackModel.mediaStreams?.defaultSubStreamIndex; + + Response response = await api.itemsItemIdPlaybackInfoPost( + itemId: item.id, + enableDirectPlay: true, + enableDirectStream: true, + enableTranscoding: true, + autoOpenLiveStream: true, + startTimeTicks: currentPosition.toRuntimeTicks, + audioStreamIndex: audioIndex, + subtitleStreamIndex: subIndex, + mediaSourceId: item.id, + body: PlaybackInfoDto( + startTimeTicks: currentPosition.toRuntimeTicks, + audioStreamIndex: audioIndex, + subtitleStreamIndex: subIndex, + enableTranscoding: true, + autoOpenLiveStream: true, + deviceProfile: defaultProfile, + userId: userId, + mediaSourceId: item.id, + ), + ); + + PlaybackInfoResponse playbackInfo = response.bodyOrThrow; + + final mediaSource = playbackInfo.mediaSources?.first; + + final mediaStreamsWithUrls = MediaStreamsModel.fromMediaStreamsList( + playbackInfo.mediaSources?.firstOrNull, playbackInfo.mediaSources?.firstOrNull?.mediaStreams ?? [], ref) + .copyWith( + defaultAudioStreamIndex: audioIndex, + defaultSubStreamIndex: subIndex, + ); + + if (mediaSource == null) return; + + PlaybackModel? newModel; + + if ((mediaSource.supportsDirectStream ?? false) || (mediaSource.supportsDirectPlay ?? false)) { + final Map directOptions = { + 'Static': 'true', + 'mediaSourceId': mediaSource.id, + 'api_key': ref.read(userProvider)?.credentials.token, + }; + + if (mediaSource.eTag != null) { + directOptions['Tag'] = mediaSource.eTag; + } + + if (mediaSource.liveStreamId != null) { + directOptions['LiveStreamId'] = mediaSource.liveStreamId; + } + + final params = Uri(queryParameters: directOptions).query; + + final directPlay = '${ref.read(userProvider)?.server ?? ""}/Videos/${mediaSource.id}/stream?$params'; + + newModel = DirectPlaybackModel( + item: playbackModel.item, + queue: playbackModel.queue, + introSkipModel: playbackModel.introSkipModel, + chapters: playbackModel.chapters, + playbackInfo: playbackInfo, + trickPlay: playbackModel.trickPlay, + media: Media(directPlay), + mediaStreams: mediaStreamsWithUrls, + ); + } else if ((mediaSource.supportsTranscoding ?? false) && mediaSource.transcodingUrl != null) { + newModel = TranscodePlaybackModel( + item: playbackModel.item, + queue: playbackModel.queue, + introSkipModel: playbackModel.introSkipModel, + chapters: playbackModel.chapters, + playbackInfo: playbackInfo, + trickPlay: playbackModel.trickPlay, + media: Media("${ref.read(userProvider)?.server ?? ""}${mediaSource.transcodingUrl ?? ""}"), + mediaStreams: mediaStreamsWithUrls, + ); + } + if (newModel == null) return; + if (newModel.runtimeType != playbackModel.runtimeType || newModel is TranscodePlaybackModel) { + ref.read(videoPlayerProvider.notifier).loadPlaybackItem(newModel, startPosition: currentPosition); + } + } +} diff --git a/lib/models/playback/transcode_playback_model.dart b/lib/models/playback/transcode_playback_model.dart new file mode 100644 index 0000000..fb65eeb --- /dev/null +++ b/lib/models/playback/transcode_playback_model.dart @@ -0,0 +1,210 @@ +import 'package:collection/collection.dart'; +import 'package:fladder/models/items/trick_play_model.dart'; +import 'package:fladder/util/list_extensions.dart'; +import 'package:fladder/wrappers/media_control_wrapper.dart' + if (dart.library.html) 'package:fladder/wrappers/media_control_wrapper_web.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:media_kit/media_kit.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/chapters_model.dart'; +import 'package:fladder/models/items/intro_skip_model.dart'; +import 'package:fladder/models/items/media_streams_model.dart'; +import 'package:fladder/models/playback/playback_model.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:fladder/providers/video_player_provider.dart'; +import 'package:fladder/util/duration_extensions.dart'; + +class TranscodePlaybackModel implements PlaybackModel { + TranscodePlaybackModel({ + required this.item, + required this.media, + required this.playbackInfo, + this.mediaStreams, + this.introSkipModel, + this.chapters, + this.trickPlay, + this.queue = const [], + }); + + @override + final ItemBaseModel item; + + @override + final Media? media; + + @override + final PlaybackInfoResponse playbackInfo; + + @override + final MediaStreamsModel? mediaStreams; + + @override + final IntroOutSkipModel? introSkipModel; + + @override + final List? chapters; + + @override + final TrickPlayModel? trickPlay; + + @override + ItemBaseModel? get nextVideo => queue.nextOrNull(item); + + @override + ItemBaseModel? get previousVideo => queue.previousOrNull(item); + + @override + Future? startDuration() async => item.userData.playBackPosition; + + @override + List get subStreams => [SubStreamModel.no(), ...mediaStreams?.subStreams ?? []]; + + List get itemsInQueue => + queue.mapIndexed((index, element) => QueueItem(id: element.id, playlistItemId: "playlistItem$index")).toList(); + + @override + Future setSubtitle(SubStreamModel? model, MediaControlsWrapper player) async { + final wantedSubtitle = + model ?? subStreams.firstWhereOrNull((element) => element.index == mediaStreams?.defaultSubStreamIndex); + if (wantedSubtitle == null) return this; + if (wantedSubtitle.index == SubStreamModel.no().index) { + await player.setSubtitleTrack(SubtitleTrack.no()); + } else { + final subTracks = player.subTracks.getRange(2, player.subTracks.length).toList(); + final index = subStreams.sublist(1).indexWhere((element) => element.id == wantedSubtitle.id); + final subTrack = subTracks.elementAtOrNull(index); + if (wantedSubtitle.isExternal && wantedSubtitle.url != null && subTrack == null) { + await player.setSubtitleTrack(SubtitleTrack.uri(wantedSubtitle.url!)); + } else if (subTrack != null) { + await player.setSubtitleTrack(subTrack); + } + } + return copyWith(mediaStreams: () => mediaStreams?.copyWith(defaultSubStreamIndex: wantedSubtitle.index)); + } + + @override + List get audioStreams => [AudioStreamModel.no(), ...mediaStreams?.audioStreams ?? []]; + + @override + Future? setAudio(AudioStreamModel? model, MediaControlsWrapper player) async { + final wantedAudioStream = + model ?? audioStreams.firstWhereOrNull((element) => element.index == mediaStreams?.defaultAudioStreamIndex); + if (wantedAudioStream == null) return this; + if (wantedAudioStream.index == AudioStreamModel.no().index) { + await player.setAudioTrack(AudioTrack.no()); + } else { + final audioTracks = player.audioTracks.getRange(2, player.audioTracks.length).toList(); + final audioTrack = audioTracks.elementAtOrNull(audioStreams.indexOf(wantedAudioStream) - 1); + if (audioTrack != null) { + await player.setAudioTrack(audioTrack); + } + } + return copyWith(mediaStreams: () => mediaStreams?.copyWith(defaultAudioStreamIndex: wantedAudioStream.index)); + } + + @override + Future playbackStarted(Duration position, Ref ref) async { + await ref.read(jellyApiProvider).sessionsPlayingPost( + body: PlaybackStartInfo( + canSeek: true, + itemId: item.id, + mediaSourceId: item.id, + playSessionId: playbackInfo.playSessionId, + sessionId: playbackInfo.playSessionId, + subtitleStreamIndex: item.streamModel?.defaultSubStreamIndex, + audioStreamIndex: item.streamModel?.defaultAudioStreamIndex, + volumeLevel: 100, + playbackStartTimeTicks: position.toRuntimeTicks, + playMethod: PlayMethod.transcode, + isMuted: false, + isPaused: false, + repeatMode: RepeatMode.repeatall, + nowPlayingQueue: itemsInQueue, + ), + ); + return null; + } + + @override + Future playbackStopped(Duration position, Duration? totalDuration, Ref ref) async { + ref.read(playBackModel.notifier).update((state) => null); + + await ref.read(jellyApiProvider).sessionsPlayingStoppedPost( + body: PlaybackStopInfo( + itemId: item.id, + mediaSourceId: item.id, + playSessionId: playbackInfo.playSessionId, + positionTicks: position.toRuntimeTicks, + failed: false, + nowPlayingQueue: itemsInQueue, + ), + totalDuration: totalDuration, + ); + + return null; + } + + @override + Future updatePlaybackPosition(Duration position, bool isPlaying, Ref ref) async { + final api = ref.read(jellyApiProvider); + + //Check for newly generated scrubImages + if (trickPlay == null) { + final trickplay = await api.getTrickPlay(item: item, ref: ref); + ref.read(playBackModel.notifier).update((state) => copyWith(trickPlay: () => trickplay?.bodyOrThrow)); + } + + await api.sessionsPlayingProgressPost( + body: PlaybackProgressInfo( + canSeek: true, + itemId: item.id, + mediaSourceId: item.id, + playSessionId: playbackInfo.playSessionId, + sessionId: playbackInfo.playSessionId, + subtitleStreamIndex: item.streamModel?.defaultSubStreamIndex, + audioStreamIndex: item.streamModel?.defaultAudioStreamIndex, + volumeLevel: 100, + positionTicks: position.toRuntimeTicks, + playMethod: PlayMethod.transcode, + isPaused: !isPlaying, + isMuted: false, + repeatMode: RepeatMode.repeatall, + nowPlayingQueue: itemsInQueue, + ), + ); + return this; + } + + @override + String toString() => 'TranscodePlaybackModel(item: $item, playbackInfo: $playbackInfo)'; + + @override + final List queue; + + @override + TranscodePlaybackModel copyWith({ + ItemBaseModel? item, + ValueGetter? media, + ValueGetter? lastPosition, + PlaybackInfoResponse? playbackInfo, + ValueGetter? mediaStreams, + ValueGetter? introSkipModel, + ValueGetter?>? chapters, + ValueGetter? trickPlay, + List? queue, + }) { + return TranscodePlaybackModel( + item: item ?? this.item, + media: media != null ? media() : this.media, + playbackInfo: playbackInfo ?? this.playbackInfo, + mediaStreams: mediaStreams != null ? mediaStreams() : this.mediaStreams, + introSkipModel: introSkipModel != null ? introSkipModel() : this.introSkipModel, + chapters: chapters != null ? chapters() : this.chapters, + trickPlay: trickPlay != null ? trickPlay() : this.trickPlay, + queue: queue ?? this.queue, + ); + } +} diff --git a/lib/models/playlist_model.dart b/lib/models/playlist_model.dart new file mode 100644 index 0000000..fcf2b00 --- /dev/null +++ b/lib/models/playlist_model.dart @@ -0,0 +1,40 @@ +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/images_models.dart'; +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/models/items/overview_model.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class PlaylistModel extends ItemBaseModel { + PlaylistModel({ + required super.name, + required super.id, + required super.overview, + required super.parentId, + required super.playlistId, + required super.images, + required super.childCount, + required super.primaryRatio, + required super.userData, + super.canDelete, + super.canDownload, + super.jellyType, + }); + + factory PlaylistModel.fromBaseDto(BaseItemDto item, Ref ref) { + return PlaylistModel( + name: item.name ?? "", + id: item.id ?? "", + childCount: item.childCount, + overview: OverviewModel.fromBaseItemDto(item, ref), + userData: UserData.fromDto(item.userData), + parentId: item.parentId, + playlistId: item.playlistItemId, + images: ImagesData.fromBaseItem(item, ref), + primaryRatio: item.primaryImageAspectRatio, + canDelete: item.canDelete, + canDownload: item.canDownload, + jellyType: item.type, + ); + } +} diff --git a/lib/models/recommended_model.dart b/lib/models/recommended_model.dart new file mode 100644 index 0000000..16f65dd --- /dev/null +++ b/lib/models/recommended_model.dart @@ -0,0 +1,25 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +import 'package:fladder/models/item_base_model.dart'; + +class RecommendedModel { + final String name; + final List posters; + final String type; + RecommendedModel({ + required this.name, + required this.posters, + required this.type, + }); + + RecommendedModel copyWith({ + String? name, + List? posters, + String? type, + }) { + return RecommendedModel( + name: name ?? this.name, + posters: posters ?? this.posters, + type: type ?? this.type, + ); + } +} diff --git a/lib/models/search_model.dart b/lib/models/search_model.dart new file mode 100644 index 0000000..2be2eea --- /dev/null +++ b/lib/models/search_model.dart @@ -0,0 +1,28 @@ +import 'package:fladder/models/item_base_model.dart'; + +class SearchModel { + final bool loading; + final String searchQuery; + final int resultCount; + final Map> results; + SearchModel({ + this.loading = false, + this.searchQuery = "", + this.resultCount = 0, + this.results = const {}, + }); + + SearchModel copyWith({ + bool? loading, + String? searchQuery, + int? resultCount, + Map>? results, + }) { + return SearchModel( + loading: loading ?? this.loading, + searchQuery: searchQuery ?? this.searchQuery, + resultCount: resultCount ?? this.resultCount, + results: results ?? this.results, + ); + } +} diff --git a/lib/models/settings/client_settings_model.dart b/lib/models/settings/client_settings_model.dart new file mode 100644 index 0000000..af2662e --- /dev/null +++ b/lib/models/settings/client_settings_model.dart @@ -0,0 +1,117 @@ +import 'dart:convert'; +import 'dart:developer'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +import 'package:fladder/util/custom_color_themes.dart'; + +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'client_settings_model.freezed.dart'; +part 'client_settings_model.g.dart'; + +@freezed +class ClientSettingsModel with _$ClientSettingsModel { + factory ClientSettingsModel({ + String? syncPath, + @Default(Vector2(x: 0, y: 0)) Vector2 position, + @Default(Vector2(x: 1280, y: 720)) Vector2 size, + @Default(Duration(seconds: 30)) Duration? timeOut, + Duration? nextUpDateCutoff, + @Default(ThemeMode.system) ThemeMode themeMode, + ColorThemes? themeColor, + @Default(false) bool amoledBlack, + @Default(false) bool blurPlaceHolders, + @Default(false) bool blurUpcomingEpisodes, + @LocaleConvert() Locale? selectedLocale, + @Default(true) bool enableMediaKeys, + @Default(1.0) double posterSize, + @Default(false) bool pinchPosterZoom, + @Default(false) bool mouseDragSupport, + int? libraryPageSize, + }) = _ClientSettingsModel; + + factory ClientSettingsModel.fromJson(Map json) => _$ClientSettingsModelFromJson(json); +} + +class LocaleConvert implements JsonConverter { + const LocaleConvert(); + + @override + Locale? fromJson(String? json) { + if (json == null) return null; + final parts = json.split('_'); + if (parts.length == 1) { + return Locale(parts[0]); + } else if (parts.length == 2) { + return Locale(parts[0], parts[1]); + } else { + log("Invalid Locale format"); + return null; + } + } + + @override + String? toJson(Locale? object) { + if (object == null) return null; + if (object.countryCode == null || object.countryCode?.isEmpty == true) { + return object.languageCode; + } + return '${object.languageCode}_${object.countryCode}'; + } +} + +class Vector2 { + final double x; + final double y; + const Vector2({ + required this.x, + required this.y, + }); + + Vector2 copyWith({ + double? x, + double? y, + }) { + return Vector2( + x: x ?? this.x, + y: y ?? this.y, + ); + } + + Map toMap() { + return { + 'x': x, + 'y': y, + }; + } + + factory Vector2.fromMap(Map map) { + return Vector2( + x: map['x'] as double, + y: map['y'] as double, + ); + } + + String toJson() => json.encode(toMap()); + + factory Vector2.fromJson(String source) => Vector2.fromMap(json.decode(source) as Map); + + factory Vector2.fromSize(Size size) => Vector2(x: size.width, y: size.height); + + @override + String toString() => 'Vector2(x: $x, y: $y)'; + + @override + bool operator ==(covariant Vector2 other) { + if (identical(this, other)) return true; + + return other.x == x && other.y == y; + } + + @override + int get hashCode => x.hashCode ^ y.hashCode; + + static fromPosition(Offset windowPosition) => Vector2(x: windowPosition.dx, y: windowPosition.dy); +} diff --git a/lib/models/settings/client_settings_model.freezed.dart b/lib/models/settings/client_settings_model.freezed.dart new file mode 100644 index 0000000..28601be --- /dev/null +++ b/lib/models/settings/client_settings_model.freezed.dart @@ -0,0 +1,526 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'client_settings_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +ClientSettingsModel _$ClientSettingsModelFromJson(Map json) { + return _ClientSettingsModel.fromJson(json); +} + +/// @nodoc +mixin _$ClientSettingsModel { + String? get syncPath => throw _privateConstructorUsedError; + Vector2 get position => throw _privateConstructorUsedError; + Vector2 get size => throw _privateConstructorUsedError; + Duration? get timeOut => throw _privateConstructorUsedError; + Duration? get nextUpDateCutoff => throw _privateConstructorUsedError; + ThemeMode get themeMode => throw _privateConstructorUsedError; + ColorThemes? get themeColor => throw _privateConstructorUsedError; + bool get amoledBlack => throw _privateConstructorUsedError; + bool get blurPlaceHolders => throw _privateConstructorUsedError; + bool get blurUpcomingEpisodes => throw _privateConstructorUsedError; + @LocaleConvert() + Locale? get selectedLocale => throw _privateConstructorUsedError; + bool get enableMediaKeys => throw _privateConstructorUsedError; + double get posterSize => throw _privateConstructorUsedError; + bool get pinchPosterZoom => throw _privateConstructorUsedError; + bool get mouseDragSupport => throw _privateConstructorUsedError; + int? get libraryPageSize => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $ClientSettingsModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ClientSettingsModelCopyWith<$Res> { + factory $ClientSettingsModelCopyWith( + ClientSettingsModel value, $Res Function(ClientSettingsModel) then) = + _$ClientSettingsModelCopyWithImpl<$Res, ClientSettingsModel>; + @useResult + $Res call( + {String? syncPath, + Vector2 position, + Vector2 size, + Duration? timeOut, + Duration? nextUpDateCutoff, + ThemeMode themeMode, + ColorThemes? themeColor, + bool amoledBlack, + bool blurPlaceHolders, + bool blurUpcomingEpisodes, + @LocaleConvert() Locale? selectedLocale, + bool enableMediaKeys, + double posterSize, + bool pinchPosterZoom, + bool mouseDragSupport, + int? libraryPageSize}); +} + +/// @nodoc +class _$ClientSettingsModelCopyWithImpl<$Res, $Val extends ClientSettingsModel> + implements $ClientSettingsModelCopyWith<$Res> { + _$ClientSettingsModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? syncPath = freezed, + Object? position = null, + Object? size = null, + Object? timeOut = freezed, + Object? nextUpDateCutoff = freezed, + Object? themeMode = null, + Object? themeColor = freezed, + Object? amoledBlack = null, + Object? blurPlaceHolders = null, + Object? blurUpcomingEpisodes = null, + Object? selectedLocale = freezed, + Object? enableMediaKeys = null, + Object? posterSize = null, + Object? pinchPosterZoom = null, + Object? mouseDragSupport = null, + Object? libraryPageSize = freezed, + }) { + return _then(_value.copyWith( + syncPath: freezed == syncPath + ? _value.syncPath + : syncPath // ignore: cast_nullable_to_non_nullable + as String?, + position: null == position + ? _value.position + : position // ignore: cast_nullable_to_non_nullable + as Vector2, + size: null == size + ? _value.size + : size // ignore: cast_nullable_to_non_nullable + as Vector2, + timeOut: freezed == timeOut + ? _value.timeOut + : timeOut // ignore: cast_nullable_to_non_nullable + as Duration?, + nextUpDateCutoff: freezed == nextUpDateCutoff + ? _value.nextUpDateCutoff + : nextUpDateCutoff // ignore: cast_nullable_to_non_nullable + as Duration?, + themeMode: null == themeMode + ? _value.themeMode + : themeMode // ignore: cast_nullable_to_non_nullable + as ThemeMode, + themeColor: freezed == themeColor + ? _value.themeColor + : themeColor // ignore: cast_nullable_to_non_nullable + as ColorThemes?, + amoledBlack: null == amoledBlack + ? _value.amoledBlack + : amoledBlack // ignore: cast_nullable_to_non_nullable + as bool, + blurPlaceHolders: null == blurPlaceHolders + ? _value.blurPlaceHolders + : blurPlaceHolders // ignore: cast_nullable_to_non_nullable + as bool, + blurUpcomingEpisodes: null == blurUpcomingEpisodes + ? _value.blurUpcomingEpisodes + : blurUpcomingEpisodes // ignore: cast_nullable_to_non_nullable + as bool, + selectedLocale: freezed == selectedLocale + ? _value.selectedLocale + : selectedLocale // ignore: cast_nullable_to_non_nullable + as Locale?, + enableMediaKeys: null == enableMediaKeys + ? _value.enableMediaKeys + : enableMediaKeys // ignore: cast_nullable_to_non_nullable + as bool, + posterSize: null == posterSize + ? _value.posterSize + : posterSize // ignore: cast_nullable_to_non_nullable + as double, + pinchPosterZoom: null == pinchPosterZoom + ? _value.pinchPosterZoom + : pinchPosterZoom // ignore: cast_nullable_to_non_nullable + as bool, + mouseDragSupport: null == mouseDragSupport + ? _value.mouseDragSupport + : mouseDragSupport // ignore: cast_nullable_to_non_nullable + as bool, + libraryPageSize: freezed == libraryPageSize + ? _value.libraryPageSize + : libraryPageSize // ignore: cast_nullable_to_non_nullable + as int?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$ClientSettingsModelImplCopyWith<$Res> + implements $ClientSettingsModelCopyWith<$Res> { + factory _$$ClientSettingsModelImplCopyWith(_$ClientSettingsModelImpl value, + $Res Function(_$ClientSettingsModelImpl) then) = + __$$ClientSettingsModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String? syncPath, + Vector2 position, + Vector2 size, + Duration? timeOut, + Duration? nextUpDateCutoff, + ThemeMode themeMode, + ColorThemes? themeColor, + bool amoledBlack, + bool blurPlaceHolders, + bool blurUpcomingEpisodes, + @LocaleConvert() Locale? selectedLocale, + bool enableMediaKeys, + double posterSize, + bool pinchPosterZoom, + bool mouseDragSupport, + int? libraryPageSize}); +} + +/// @nodoc +class __$$ClientSettingsModelImplCopyWithImpl<$Res> + extends _$ClientSettingsModelCopyWithImpl<$Res, _$ClientSettingsModelImpl> + implements _$$ClientSettingsModelImplCopyWith<$Res> { + __$$ClientSettingsModelImplCopyWithImpl(_$ClientSettingsModelImpl _value, + $Res Function(_$ClientSettingsModelImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? syncPath = freezed, + Object? position = null, + Object? size = null, + Object? timeOut = freezed, + Object? nextUpDateCutoff = freezed, + Object? themeMode = null, + Object? themeColor = freezed, + Object? amoledBlack = null, + Object? blurPlaceHolders = null, + Object? blurUpcomingEpisodes = null, + Object? selectedLocale = freezed, + Object? enableMediaKeys = null, + Object? posterSize = null, + Object? pinchPosterZoom = null, + Object? mouseDragSupport = null, + Object? libraryPageSize = freezed, + }) { + return _then(_$ClientSettingsModelImpl( + syncPath: freezed == syncPath + ? _value.syncPath + : syncPath // ignore: cast_nullable_to_non_nullable + as String?, + position: null == position + ? _value.position + : position // ignore: cast_nullable_to_non_nullable + as Vector2, + size: null == size + ? _value.size + : size // ignore: cast_nullable_to_non_nullable + as Vector2, + timeOut: freezed == timeOut + ? _value.timeOut + : timeOut // ignore: cast_nullable_to_non_nullable + as Duration?, + nextUpDateCutoff: freezed == nextUpDateCutoff + ? _value.nextUpDateCutoff + : nextUpDateCutoff // ignore: cast_nullable_to_non_nullable + as Duration?, + themeMode: null == themeMode + ? _value.themeMode + : themeMode // ignore: cast_nullable_to_non_nullable + as ThemeMode, + themeColor: freezed == themeColor + ? _value.themeColor + : themeColor // ignore: cast_nullable_to_non_nullable + as ColorThemes?, + amoledBlack: null == amoledBlack + ? _value.amoledBlack + : amoledBlack // ignore: cast_nullable_to_non_nullable + as bool, + blurPlaceHolders: null == blurPlaceHolders + ? _value.blurPlaceHolders + : blurPlaceHolders // ignore: cast_nullable_to_non_nullable + as bool, + blurUpcomingEpisodes: null == blurUpcomingEpisodes + ? _value.blurUpcomingEpisodes + : blurUpcomingEpisodes // ignore: cast_nullable_to_non_nullable + as bool, + selectedLocale: freezed == selectedLocale + ? _value.selectedLocale + : selectedLocale // ignore: cast_nullable_to_non_nullable + as Locale?, + enableMediaKeys: null == enableMediaKeys + ? _value.enableMediaKeys + : enableMediaKeys // ignore: cast_nullable_to_non_nullable + as bool, + posterSize: null == posterSize + ? _value.posterSize + : posterSize // ignore: cast_nullable_to_non_nullable + as double, + pinchPosterZoom: null == pinchPosterZoom + ? _value.pinchPosterZoom + : pinchPosterZoom // ignore: cast_nullable_to_non_nullable + as bool, + mouseDragSupport: null == mouseDragSupport + ? _value.mouseDragSupport + : mouseDragSupport // ignore: cast_nullable_to_non_nullable + as bool, + libraryPageSize: freezed == libraryPageSize + ? _value.libraryPageSize + : libraryPageSize // ignore: cast_nullable_to_non_nullable + as int?, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ClientSettingsModelImpl + with DiagnosticableTreeMixin + implements _ClientSettingsModel { + _$ClientSettingsModelImpl( + {this.syncPath, + this.position = const Vector2(x: 0, y: 0), + this.size = const Vector2(x: 1280, y: 720), + this.timeOut = const Duration(seconds: 30), + this.nextUpDateCutoff, + this.themeMode = ThemeMode.system, + this.themeColor, + this.amoledBlack = false, + this.blurPlaceHolders = false, + this.blurUpcomingEpisodes = false, + @LocaleConvert() this.selectedLocale, + this.enableMediaKeys = true, + this.posterSize = 1.0, + this.pinchPosterZoom = false, + this.mouseDragSupport = false, + this.libraryPageSize}); + + factory _$ClientSettingsModelImpl.fromJson(Map json) => + _$$ClientSettingsModelImplFromJson(json); + + @override + final String? syncPath; + @override + @JsonKey() + final Vector2 position; + @override + @JsonKey() + final Vector2 size; + @override + @JsonKey() + final Duration? timeOut; + @override + final Duration? nextUpDateCutoff; + @override + @JsonKey() + final ThemeMode themeMode; + @override + final ColorThemes? themeColor; + @override + @JsonKey() + final bool amoledBlack; + @override + @JsonKey() + final bool blurPlaceHolders; + @override + @JsonKey() + final bool blurUpcomingEpisodes; + @override + @LocaleConvert() + final Locale? selectedLocale; + @override + @JsonKey() + final bool enableMediaKeys; + @override + @JsonKey() + final double posterSize; + @override + @JsonKey() + final bool pinchPosterZoom; + @override + @JsonKey() + final bool mouseDragSupport; + @override + final int? libraryPageSize; + + @override + String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { + return 'ClientSettingsModel(syncPath: $syncPath, position: $position, size: $size, timeOut: $timeOut, nextUpDateCutoff: $nextUpDateCutoff, themeMode: $themeMode, themeColor: $themeColor, amoledBlack: $amoledBlack, blurPlaceHolders: $blurPlaceHolders, blurUpcomingEpisodes: $blurUpcomingEpisodes, selectedLocale: $selectedLocale, enableMediaKeys: $enableMediaKeys, posterSize: $posterSize, pinchPosterZoom: $pinchPosterZoom, mouseDragSupport: $mouseDragSupport, libraryPageSize: $libraryPageSize)'; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('type', 'ClientSettingsModel')) + ..add(DiagnosticsProperty('syncPath', syncPath)) + ..add(DiagnosticsProperty('position', position)) + ..add(DiagnosticsProperty('size', size)) + ..add(DiagnosticsProperty('timeOut', timeOut)) + ..add(DiagnosticsProperty('nextUpDateCutoff', nextUpDateCutoff)) + ..add(DiagnosticsProperty('themeMode', themeMode)) + ..add(DiagnosticsProperty('themeColor', themeColor)) + ..add(DiagnosticsProperty('amoledBlack', amoledBlack)) + ..add(DiagnosticsProperty('blurPlaceHolders', blurPlaceHolders)) + ..add(DiagnosticsProperty('blurUpcomingEpisodes', blurUpcomingEpisodes)) + ..add(DiagnosticsProperty('selectedLocale', selectedLocale)) + ..add(DiagnosticsProperty('enableMediaKeys', enableMediaKeys)) + ..add(DiagnosticsProperty('posterSize', posterSize)) + ..add(DiagnosticsProperty('pinchPosterZoom', pinchPosterZoom)) + ..add(DiagnosticsProperty('mouseDragSupport', mouseDragSupport)) + ..add(DiagnosticsProperty('libraryPageSize', libraryPageSize)); + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ClientSettingsModelImpl && + (identical(other.syncPath, syncPath) || + other.syncPath == syncPath) && + (identical(other.position, position) || + other.position == position) && + (identical(other.size, size) || other.size == size) && + (identical(other.timeOut, timeOut) || other.timeOut == timeOut) && + (identical(other.nextUpDateCutoff, nextUpDateCutoff) || + other.nextUpDateCutoff == nextUpDateCutoff) && + (identical(other.themeMode, themeMode) || + other.themeMode == themeMode) && + (identical(other.themeColor, themeColor) || + other.themeColor == themeColor) && + (identical(other.amoledBlack, amoledBlack) || + other.amoledBlack == amoledBlack) && + (identical(other.blurPlaceHolders, blurPlaceHolders) || + other.blurPlaceHolders == blurPlaceHolders) && + (identical(other.blurUpcomingEpisodes, blurUpcomingEpisodes) || + other.blurUpcomingEpisodes == blurUpcomingEpisodes) && + (identical(other.selectedLocale, selectedLocale) || + other.selectedLocale == selectedLocale) && + (identical(other.enableMediaKeys, enableMediaKeys) || + other.enableMediaKeys == enableMediaKeys) && + (identical(other.posterSize, posterSize) || + other.posterSize == posterSize) && + (identical(other.pinchPosterZoom, pinchPosterZoom) || + other.pinchPosterZoom == pinchPosterZoom) && + (identical(other.mouseDragSupport, mouseDragSupport) || + other.mouseDragSupport == mouseDragSupport) && + (identical(other.libraryPageSize, libraryPageSize) || + other.libraryPageSize == libraryPageSize)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, + syncPath, + position, + size, + timeOut, + nextUpDateCutoff, + themeMode, + themeColor, + amoledBlack, + blurPlaceHolders, + blurUpcomingEpisodes, + selectedLocale, + enableMediaKeys, + posterSize, + pinchPosterZoom, + mouseDragSupport, + libraryPageSize); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ClientSettingsModelImplCopyWith<_$ClientSettingsModelImpl> get copyWith => + __$$ClientSettingsModelImplCopyWithImpl<_$ClientSettingsModelImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$ClientSettingsModelImplToJson( + this, + ); + } +} + +abstract class _ClientSettingsModel implements ClientSettingsModel { + factory _ClientSettingsModel( + {final String? syncPath, + final Vector2 position, + final Vector2 size, + final Duration? timeOut, + final Duration? nextUpDateCutoff, + final ThemeMode themeMode, + final ColorThemes? themeColor, + final bool amoledBlack, + final bool blurPlaceHolders, + final bool blurUpcomingEpisodes, + @LocaleConvert() final Locale? selectedLocale, + final bool enableMediaKeys, + final double posterSize, + final bool pinchPosterZoom, + final bool mouseDragSupport, + final int? libraryPageSize}) = _$ClientSettingsModelImpl; + + factory _ClientSettingsModel.fromJson(Map json) = + _$ClientSettingsModelImpl.fromJson; + + @override + String? get syncPath; + @override + Vector2 get position; + @override + Vector2 get size; + @override + Duration? get timeOut; + @override + Duration? get nextUpDateCutoff; + @override + ThemeMode get themeMode; + @override + ColorThemes? get themeColor; + @override + bool get amoledBlack; + @override + bool get blurPlaceHolders; + @override + bool get blurUpcomingEpisodes; + @override + @LocaleConvert() + Locale? get selectedLocale; + @override + bool get enableMediaKeys; + @override + double get posterSize; + @override + bool get pinchPosterZoom; + @override + bool get mouseDragSupport; + @override + int? get libraryPageSize; + @override + @JsonKey(ignore: true) + _$$ClientSettingsModelImplCopyWith<_$ClientSettingsModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/settings/client_settings_model.g.dart b/lib/models/settings/client_settings_model.g.dart new file mode 100644 index 0000000..4b71fd5 --- /dev/null +++ b/lib/models/settings/client_settings_model.g.dart @@ -0,0 +1,83 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'client_settings_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$ClientSettingsModelImpl _$$ClientSettingsModelImplFromJson( + Map json) => + _$ClientSettingsModelImpl( + syncPath: json['syncPath'] as String?, + position: json['position'] == null + ? const Vector2(x: 0, y: 0) + : Vector2.fromJson(json['position'] as String), + size: json['size'] == null + ? const Vector2(x: 1280, y: 720) + : Vector2.fromJson(json['size'] as String), + timeOut: json['timeOut'] == null + ? const Duration(seconds: 30) + : Duration(microseconds: (json['timeOut'] as num).toInt()), + nextUpDateCutoff: json['nextUpDateCutoff'] == null + ? null + : Duration(microseconds: (json['nextUpDateCutoff'] as num).toInt()), + themeMode: $enumDecodeNullable(_$ThemeModeEnumMap, json['themeMode']) ?? + ThemeMode.system, + themeColor: $enumDecodeNullable(_$ColorThemesEnumMap, json['themeColor']), + amoledBlack: json['amoledBlack'] as bool? ?? false, + blurPlaceHolders: json['blurPlaceHolders'] as bool? ?? false, + blurUpcomingEpisodes: json['blurUpcomingEpisodes'] as bool? ?? false, + selectedLocale: + const LocaleConvert().fromJson(json['selectedLocale'] as String?), + enableMediaKeys: json['enableMediaKeys'] as bool? ?? true, + posterSize: (json['posterSize'] as num?)?.toDouble() ?? 1.0, + pinchPosterZoom: json['pinchPosterZoom'] as bool? ?? false, + mouseDragSupport: json['mouseDragSupport'] as bool? ?? false, + libraryPageSize: (json['libraryPageSize'] as num?)?.toInt(), + ); + +Map _$$ClientSettingsModelImplToJson( + _$ClientSettingsModelImpl instance) => + { + 'syncPath': instance.syncPath, + 'position': instance.position, + 'size': instance.size, + 'timeOut': instance.timeOut?.inMicroseconds, + 'nextUpDateCutoff': instance.nextUpDateCutoff?.inMicroseconds, + 'themeMode': _$ThemeModeEnumMap[instance.themeMode]!, + 'themeColor': _$ColorThemesEnumMap[instance.themeColor], + 'amoledBlack': instance.amoledBlack, + 'blurPlaceHolders': instance.blurPlaceHolders, + 'blurUpcomingEpisodes': instance.blurUpcomingEpisodes, + 'selectedLocale': const LocaleConvert().toJson(instance.selectedLocale), + 'enableMediaKeys': instance.enableMediaKeys, + 'posterSize': instance.posterSize, + 'pinchPosterZoom': instance.pinchPosterZoom, + 'mouseDragSupport': instance.mouseDragSupport, + 'libraryPageSize': instance.libraryPageSize, + }; + +const _$ThemeModeEnumMap = { + ThemeMode.system: 'system', + ThemeMode.light: 'light', + ThemeMode.dark: 'dark', +}; + +const _$ColorThemesEnumMap = { + ColorThemes.fladder: 'fladder', + ColorThemes.deepOrange: 'deepOrange', + ColorThemes.amber: 'amber', + ColorThemes.green: 'green', + ColorThemes.lightGreen: 'lightGreen', + ColorThemes.lime: 'lime', + ColorThemes.cyan: 'cyan', + ColorThemes.blue: 'blue', + ColorThemes.lightBlue: 'lightBlue', + ColorThemes.indigo: 'indigo', + ColorThemes.deepBlue: 'deepBlue', + ColorThemes.brown: 'brown', + ColorThemes.purple: 'purple', + ColorThemes.deepPurple: 'deepPurple', + ColorThemes.blueGrey: 'blueGrey', +}; diff --git a/lib/models/settings/home_settings_model.dart b/lib/models/settings/home_settings_model.dart new file mode 100644 index 0000000..dd2b8b2 --- /dev/null +++ b/lib/models/settings/home_settings_model.dart @@ -0,0 +1,108 @@ +import 'dart:convert'; + +import 'package:collection/collection.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:flutter/material.dart'; + +enum HomeCarouselSettings { + off, + nextUp, + cont, + combined, + ; + + const HomeCarouselSettings(); + + String label(BuildContext context) => switch (this) { + HomeCarouselSettings.off => context.localized.hide, + HomeCarouselSettings.nextUp => context.localized.nextUp, + HomeCarouselSettings.cont => context.localized.settingsContinue, + HomeCarouselSettings.combined => context.localized.combined, + }; + + String toMap() { + return toString(); + } + + static HomeCarouselSettings fromMap(String value) { + return HomeCarouselSettings.values.firstWhereOrNull((element) => element.name == value) ?? + HomeCarouselSettings.combined; + } +} + +enum HomeNextUp { + off, + nextUp, + cont, + combined, + separate, + ; + + const HomeNextUp(); + + String label(BuildContext context) => switch (this) { + HomeNextUp.off => context.localized.hide, + HomeNextUp.nextUp => context.localized.nextUp, + HomeNextUp.cont => context.localized.settingsContinue, + HomeNextUp.combined => context.localized.combined, + HomeNextUp.separate => context.localized.separate, + }; + + String toMap() { + return toString(); + } + + static HomeNextUp fromMap(String value) { + return HomeNextUp.values.firstWhereOrNull((element) => element.name == value) ?? HomeNextUp.separate; + } +} + +class HomeSettingsModel { + final HomeCarouselSettings carouselSettings; + final HomeNextUp nextUp; + HomeSettingsModel({ + this.carouselSettings = HomeCarouselSettings.combined, + this.nextUp = HomeNextUp.separate, + }); + + HomeSettingsModel copyWith({ + HomeCarouselSettings? carouselSettings, + HomeNextUp? nextUp, + }) { + return HomeSettingsModel( + carouselSettings: carouselSettings ?? this.carouselSettings, + nextUp: nextUp ?? this.nextUp, + ); + } + + Map toMap() { + return { + 'carouselSettings': carouselSettings.toMap(), + 'nextUp': nextUp.toMap(), + }; + } + + factory HomeSettingsModel.fromMap(Map map) { + return HomeSettingsModel( + carouselSettings: HomeCarouselSettings.fromMap(map['carouselSettings']), + nextUp: HomeNextUp.fromMap(map['nextUp']), + ); + } + + String toJson() => json.encode(toMap()); + + factory HomeSettingsModel.fromJson(String source) => HomeSettingsModel.fromMap(json.decode(source)); + + @override + String toString() => 'HomeSettingsModel(carouselSettings: $carouselSettings, nextUp: $nextUp)'; + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + + return other is HomeSettingsModel && other.carouselSettings == carouselSettings && other.nextUp == nextUp; + } + + @override + int get hashCode => carouselSettings.hashCode ^ nextUp.hashCode; +} diff --git a/lib/models/settings/subtitle_settings_model.dart b/lib/models/settings/subtitle_settings_model.dart new file mode 100644 index 0000000..38afce0 --- /dev/null +++ b/lib/models/settings/subtitle_settings_model.dart @@ -0,0 +1,254 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +import 'dart:convert'; +import 'dart:math' as math; + +import 'package:collection/collection.dart'; +import 'package:fladder/providers/settings/subtitle_settings_provider.dart'; +import 'package:fladder/providers/settings/video_player_settings_provider.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:google_fonts/google_fonts.dart'; + +class SubtitleSettingsModel { + final double fontSize; + final FontWeight fontWeight; + final double verticalOffset; + final Color color; + final Color outlineColor; + final double outlineSize; + final Color backGroundColor; + final double shadow; + const SubtitleSettingsModel({ + this.fontSize = 60, + this.fontWeight = FontWeight.normal, + this.verticalOffset = 0.10, + this.color = Colors.white, + this.outlineColor = const Color.fromRGBO(0, 0, 0, 0.85), + this.outlineSize = 4, + this.backGroundColor = const Color.fromARGB(0, 0, 0, 0), + this.shadow = 0.5, + }); + + SubtitleSettingsModel copyWith({ + double? fontSize, + FontWeight? fontWeight, + double? verticalOffset, + Color? color, + Color? outlineColor, + double? outlineSize, + Color? backGroundColor, + double? shadow, + }) { + return SubtitleSettingsModel( + fontSize: fontSize ?? this.fontSize, + fontWeight: fontWeight ?? this.fontWeight, + verticalOffset: verticalOffset ?? this.verticalOffset, + color: color ?? this.color, + outlineColor: outlineColor ?? this.outlineColor, + outlineSize: outlineSize ?? this.outlineSize, + backGroundColor: backGroundColor ?? this.backGroundColor, + shadow: shadow ?? this.shadow, + ); + } + + TextStyle get backGroundStyle { + return style.copyWith( + shadows: (shadow > 0.01) + ? [ + Shadow( + blurRadius: 16, + color: Colors.black.withOpacity(shadow), + ), + Shadow( + blurRadius: 8, + color: Colors.black.withOpacity(shadow), + ), + ] + : null, + foreground: Paint() + ..style = PaintingStyle.stroke + ..strokeWidth = outlineSize * (fontSize / 30) + ..color = outlineColor + ..strokeCap = StrokeCap.round + ..strokeJoin = StrokeJoin.round, + ); + } + + TextStyle get style { + return TextStyle( + height: 1.4, + fontSize: fontSize, + fontWeight: fontWeight, + fontFamily: GoogleFonts.openSans().fontFamily, + letterSpacing: 0.0, + wordSpacing: 0.0, + color: color, + ); + } + + Map toMap() { + return { + 'fontSize': fontSize, + 'fontWeight': fontWeight.value, + 'verticalOffset': verticalOffset, + 'color': color.value, + 'outlineColor': outlineColor.value, + 'outlineSize': outlineSize, + 'backGroundColor': backGroundColor.value, + 'shadow': shadow, + }; + } + + String toJson() => json.encode(toMap()); + + factory SubtitleSettingsModel.fromJson(String source) => SubtitleSettingsModel.fromMap(json.decode(source)); + + factory SubtitleSettingsModel.fromMap(Map map) { + return const SubtitleSettingsModel().copyWith( + fontSize: map['fontSize'] as double?, + fontWeight: FontWeight.values.firstWhereOrNull((element) => element.index == map['fontWeight'] as int?), + verticalOffset: map['verticalOffset'] as double?, + color: map['color'] != null ? Color(map['color'] as int) : null, + outlineColor: map['outlineColor'] != null ? Color(map['outlineColor'] as int) : null, + outlineSize: map['outlineSize'] as double?, + backGroundColor: map['backGroundColor'] != null ? Color(map['backGroundColor'] as int) : null, + shadow: map['shadow'] as double?, + ); + } + + @override + String toString() { + return 'SubtitleSettingsModel(fontSize: $fontSize, fontWeight: $fontWeight, verticalOffset: $verticalOffset, color: $color, outlineColor: $outlineColor, outlineSize: $outlineSize, backGroundColor: $backGroundColor, shadow: $shadow)'; + } + + @override + bool operator ==(covariant SubtitleSettingsModel other) { + if (identical(this, other)) return true; + + return other.fontSize == fontSize && + other.fontWeight == fontWeight && + other.verticalOffset == verticalOffset && + other.color == color && + other.outlineColor == outlineColor && + other.outlineSize == outlineSize && + other.backGroundColor == backGroundColor && + other.shadow == shadow; + } + + @override + int get hashCode { + return fontSize.hashCode ^ + fontWeight.hashCode ^ + verticalOffset.hashCode ^ + color.hashCode ^ + outlineColor.hashCode ^ + outlineSize.hashCode ^ + backGroundColor.hashCode ^ + shadow.hashCode; + } +} + +class SubtitleText extends ConsumerWidget { + final SubtitleSettingsModel subModel; + final EdgeInsets padding; + final String text; + final double offset; + const SubtitleText({ + required this.subModel, + required this.padding, + required this.offset, + required this.text, + super.key, + }); + + // The reference width for calculating the visible text scale factor. + static const kTextScaleFactorReferenceWidth = 1920.0; + // The reference height for calculating the visible text scale factor. + static const kTextScaleFactorReferenceHeight = 1080.0; + + @override + Widget build(BuildContext context, WidgetRef ref) { + final fillScreen = ref.watch(videoPlayerSettingsProvider.select((value) => value.fillScreen)); + return Padding( + padding: (fillScreen ? EdgeInsets.zero : EdgeInsets.only(left: padding.left, right: padding.right)) + .add(const EdgeInsets.all(16)), + child: LayoutBuilder( + builder: (context, constraints) { + final textScale = MediaQuery.textScalerOf(context) + .scale((ref.read(subtitleSettingsProvider.select((value) => value.fontSize)) * + math.sqrt( + ((constraints.maxWidth * constraints.maxHeight) / + (kTextScaleFactorReferenceWidth * kTextScaleFactorReferenceHeight)) + .clamp(0.0, 1.0), + ))); + + // Function to calculate the height of the text + double getTextHeight(BuildContext context, String text, TextStyle style) { + final TextPainter textPainter = TextPainter( + text: TextSpan(text: text, style: style), + textDirection: TextDirection.ltr, + textScaler: MediaQuery.textScalerOf(context), + )..layout(minWidth: 0, maxWidth: double.infinity); + + return textPainter.height; + } + + // Calculate the available height for the text alignment + double availableHeight = constraints.maxHeight; + + // Calculate the desired position based on the percentage + double desiredPosition = availableHeight * offset; + + // Get the height of the Text widget with the current font style + double textHeight = getTextHeight(context, text, subModel.style); + + // Calculate the position to keep the text within visible bounds + double position = desiredPosition - textHeight / 2; + + // Ensure the text doesn't go off-screen + position = position.clamp(0, availableHeight - textHeight); + + return IgnorePointer( + child: Stack( + alignment: Alignment.bottomCenter, + children: [ + Positioned( + bottom: position, + child: Container( + constraints: BoxConstraints(maxWidth: constraints.maxWidth, maxHeight: constraints.maxHeight), + decoration: BoxDecoration( + color: subModel.backGroundColor, + borderRadius: BorderRadius.circular(16), + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Text( + text, + style: subModel.backGroundStyle.copyWith(fontSize: textScale), + textAlign: TextAlign.center, + ), + ), + ), + ), + Positioned( + bottom: position, + child: Container( + constraints: BoxConstraints(maxWidth: constraints.maxWidth, maxHeight: constraints.maxHeight), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Text( + text, + style: subModel.style.copyWith(fontSize: textScale), + textAlign: TextAlign.center, + ), + ), + ), + ) + ], + ), + ); + }, + ), + ); + } +} diff --git a/lib/models/settings/video_player_settings.dart b/lib/models/settings/video_player_settings.dart new file mode 100644 index 0000000..e03cc6c --- /dev/null +++ b/lib/models/settings/video_player_settings.dart @@ -0,0 +1,113 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +import 'dart:convert'; + +import 'package:collection/collection.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +class VideoPlayerSettingsModel { + final double? screenBrightness; + final BoxFit videoFit; + final bool fillScreen; + final bool hardwareAccel; + final bool useLibass; + final double internalVolume; + final String? audioDevice; + const VideoPlayerSettingsModel({ + this.screenBrightness, + this.videoFit = BoxFit.contain, + this.fillScreen = false, + this.hardwareAccel = true, + this.useLibass = false, + this.internalVolume = 100, + this.audioDevice, + }); + + double get volume => switch (defaultTargetPlatform) { + TargetPlatform.android || TargetPlatform.iOS => 100, + _ => internalVolume, + }; + + VideoPlayerSettingsModel copyWith({ + ValueGetter? screenBrightness, + BoxFit? videoFit, + bool? fillScreen, + bool? hardwareAccel, + bool? useLibass, + double? internalVolume, + ValueGetter? audioDevice, + }) { + return VideoPlayerSettingsModel( + screenBrightness: screenBrightness != null ? screenBrightness() : this.screenBrightness, + videoFit: videoFit ?? this.videoFit, + fillScreen: fillScreen ?? this.fillScreen, + hardwareAccel: hardwareAccel ?? this.hardwareAccel, + useLibass: useLibass ?? this.useLibass, + internalVolume: internalVolume ?? this.internalVolume, + audioDevice: audioDevice != null ? audioDevice() : this.audioDevice, + ); + } + + Map toMap() { + return { + 'screenBrightness': screenBrightness, + 'videoFit': videoFit.name, + 'fillScreen': fillScreen, + 'hardwareAccel': hardwareAccel, + 'useLibass': useLibass, + 'internalVolume': internalVolume, + 'audioDevice': audioDevice, + }; + } + + factory VideoPlayerSettingsModel.fromMap(Map map) { + return VideoPlayerSettingsModel( + screenBrightness: map['screenBrightness']?.toDouble(), + videoFit: BoxFit.values.firstWhereOrNull((element) => element.name == map['videoFit']) ?? BoxFit.contain, + fillScreen: map['fillScreen'] ?? false, + hardwareAccel: map['hardwareAccel'] ?? false, + useLibass: map['useLibass'] ?? false, + internalVolume: map['internalVolume']?.toDouble() ?? 0.0, + audioDevice: map['audioDevice'], + ); + } + + String toJson() => json.encode(toMap()); + + factory VideoPlayerSettingsModel.fromJson(String source) => VideoPlayerSettingsModel.fromMap(json.decode(source)); + + @override + String toString() { + return 'VideoPlayerSettingsModel(screenBrightness: $screenBrightness, videoFit: $videoFit, fillScreen: $fillScreen, hardwareAccel: $hardwareAccel, useLibass: $useLibass, internalVolume: $internalVolume, audioDevice: $audioDevice)'; + } + + bool playerSame(VideoPlayerSettingsModel other) { + return other.hardwareAccel == hardwareAccel && other.useLibass == useLibass; + } + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + + return other is VideoPlayerSettingsModel && + other.screenBrightness == screenBrightness && + other.videoFit == videoFit && + other.fillScreen == fillScreen && + other.hardwareAccel == hardwareAccel && + other.useLibass == useLibass && + other.internalVolume == internalVolume && + other.audioDevice == audioDevice; + } + + @override + int get hashCode { + return screenBrightness.hashCode ^ + videoFit.hashCode ^ + fillScreen.hashCode ^ + hardwareAccel.hashCode ^ + useLibass.hashCode ^ + internalVolume.hashCode ^ + audioDevice.hashCode; + } +} diff --git a/lib/models/syncing/download_stream.dart b/lib/models/syncing/download_stream.dart new file mode 100644 index 0000000..44af29c --- /dev/null +++ b/lib/models/syncing/download_stream.dart @@ -0,0 +1,41 @@ +import 'package:background_downloader/background_downloader.dart' as dl; + +class DownloadStream { + final String id; + final dl.DownloadTask? task; + final double progress; + final dl.TaskStatus status; + DownloadStream({ + required this.id, + this.task, + required this.progress, + required this.status, + }); + + DownloadStream.empty() + : id = '', + task = null, + progress = -1, + status = dl.TaskStatus.notFound; + + bool get hasDownload => progress != -1.0 && status != dl.TaskStatus.notFound && status != dl.TaskStatus.complete; + + DownloadStream copyWith({ + String? id, + dl.DownloadTask? task, + double? progress, + dl.TaskStatus? status, + }) { + return DownloadStream( + id: id ?? this.id, + task: task ?? this.task, + progress: progress ?? this.progress, + status: status ?? this.status, + ); + } + + @override + String toString() { + return 'DownloadStream(id: $id, task: $task, progress: $progress, status: $status)'; + } +} diff --git a/lib/models/syncing/i_synced_item.dart b/lib/models/syncing/i_synced_item.dart new file mode 100644 index 0000000..6a83c99 --- /dev/null +++ b/lib/models/syncing/i_synced_item.dart @@ -0,0 +1,75 @@ +import 'dart:convert'; + +import 'package:fladder/models/syncing/sync_item.dart'; +import 'package:isar/isar.dart'; + +part 'i_synced_item.g.dart'; + +// extension IsarExtensions on String? { +// int get fastHash { +// if (this == null) return 0; +// var hash = 0xcbf29ce484222325; + +// var i = 0; +// while (i < this!.length) { +// final codeUnit = this!.codeUnitAt(i++); +// hash ^= codeUnit >> 8; +// hash *= 0x100000001b3; +// hash ^= codeUnit & 0xFF; +// hash *= 0x100000001b3; +// } + +// return hash; +// } +// } + +@collection +class ISyncedItem { + String? userId; + String id; + int? sortKey; + String? parentId; + String? path; + int? fileSize; + String? videoFileName; + String? trickPlayModel; + String? introOutroSkipModel; + String? images; + List? chapters; + List? subtitles; + String? userData; + ISyncedItem({ + this.userId, + required this.id, + this.sortKey, + this.parentId, + this.path, + this.fileSize, + this.videoFileName, + this.trickPlayModel, + this.introOutroSkipModel, + this.images, + this.chapters, + this.subtitles, + this.userData, + }); + + factory ISyncedItem.fromSynced(SyncedItem syncedItem, String? path) { + return ISyncedItem( + id: syncedItem.id, + parentId: syncedItem.parentId, + userId: syncedItem.userId, + path: syncedItem.path?.replaceAll(path ?? "", '').substring(1), + fileSize: syncedItem.fileSize, + sortKey: syncedItem.sortKey, + videoFileName: syncedItem.videoFileName, + trickPlayModel: syncedItem.fTrickPlayModel != null ? jsonEncode(syncedItem.fTrickPlayModel?.toJson()) : null, + introOutroSkipModel: + syncedItem.introOutSkipModel != null ? jsonEncode(syncedItem.introOutSkipModel?.toJson()) : null, + images: syncedItem.fImages != null ? jsonEncode(syncedItem.fImages?.toJson()) : null, + chapters: syncedItem.fChapters.map((e) => jsonEncode(e.toJson())).toList(), + subtitles: syncedItem.subtitles.map((e) => jsonEncode(e.toJson())).toList(), + userData: syncedItem.userData != null ? jsonEncode(syncedItem.userData?.toJson()) : null, + ); + } +} diff --git a/lib/models/syncing/i_synced_item.g.dart b/lib/models/syncing/i_synced_item.g.dart new file mode 100644 index 0000000..54a8e94 --- /dev/null +++ b/lib/models/syncing/i_synced_item.g.dart @@ -0,0 +1,3600 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'i_synced_item.dart'; + +// ************************************************************************** +// _IsarCollectionGenerator +// ************************************************************************** + +// coverage:ignore-file +// ignore_for_file: duplicate_ignore, invalid_use_of_protected_member, lines_longer_than_80_chars, constant_identifier_names, avoid_js_rounded_ints, no_leading_underscores_for_local_identifiers, require_trailing_commas, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_in_if_null_operators, library_private_types_in_public_api, prefer_const_constructors +// ignore_for_file: type=lint + +extension GetISyncedItemCollection on Isar { + IsarCollection get iSyncedItems => this.collection(); +} + +const ISyncedItemSchema = IsarGeneratedSchema( + schema: IsarSchema( + name: 'ISyncedItem', + idName: 'id', + embedded: false, + properties: [ + IsarPropertySchema( + name: 'userId', + type: IsarType.string, + ), + IsarPropertySchema( + name: 'id', + type: IsarType.string, + ), + IsarPropertySchema( + name: 'sortKey', + type: IsarType.long, + ), + IsarPropertySchema( + name: 'parentId', + type: IsarType.string, + ), + IsarPropertySchema( + name: 'path', + type: IsarType.string, + ), + IsarPropertySchema( + name: 'fileSize', + type: IsarType.long, + ), + IsarPropertySchema( + name: 'videoFileName', + type: IsarType.string, + ), + IsarPropertySchema( + name: 'trickPlayModel', + type: IsarType.string, + ), + IsarPropertySchema( + name: 'introOutroSkipModel', + type: IsarType.string, + ), + IsarPropertySchema( + name: 'images', + type: IsarType.string, + ), + IsarPropertySchema( + name: 'chapters', + type: IsarType.stringList, + ), + IsarPropertySchema( + name: 'subtitles', + type: IsarType.stringList, + ), + IsarPropertySchema( + name: 'userData', + type: IsarType.string, + ), + ], + indexes: [], + ), + converter: IsarObjectConverter( + serialize: serializeISyncedItem, + deserialize: deserializeISyncedItem, + deserializeProperty: deserializeISyncedItemProp, + ), + embeddedSchemas: [], +); + +@isarProtected +int serializeISyncedItem(IsarWriter writer, ISyncedItem object) { + { + final value = object.userId; + if (value == null) { + IsarCore.writeNull(writer, 1); + } else { + IsarCore.writeString(writer, 1, value); + } + } + IsarCore.writeString(writer, 2, object.id); + IsarCore.writeLong(writer, 3, object.sortKey ?? -9223372036854775808); + { + final value = object.parentId; + if (value == null) { + IsarCore.writeNull(writer, 4); + } else { + IsarCore.writeString(writer, 4, value); + } + } + { + final value = object.path; + if (value == null) { + IsarCore.writeNull(writer, 5); + } else { + IsarCore.writeString(writer, 5, value); + } + } + IsarCore.writeLong(writer, 6, object.fileSize ?? -9223372036854775808); + { + final value = object.videoFileName; + if (value == null) { + IsarCore.writeNull(writer, 7); + } else { + IsarCore.writeString(writer, 7, value); + } + } + { + final value = object.trickPlayModel; + if (value == null) { + IsarCore.writeNull(writer, 8); + } else { + IsarCore.writeString(writer, 8, value); + } + } + { + final value = object.introOutroSkipModel; + if (value == null) { + IsarCore.writeNull(writer, 9); + } else { + IsarCore.writeString(writer, 9, value); + } + } + { + final value = object.images; + if (value == null) { + IsarCore.writeNull(writer, 10); + } else { + IsarCore.writeString(writer, 10, value); + } + } + { + final list = object.chapters; + if (list == null) { + IsarCore.writeNull(writer, 11); + } else { + final listWriter = IsarCore.beginList(writer, 11, list.length); + for (var i = 0; i < list.length; i++) { + IsarCore.writeString(listWriter, i, list[i]); + } + IsarCore.endList(writer, listWriter); + } + } + { + final list = object.subtitles; + if (list == null) { + IsarCore.writeNull(writer, 12); + } else { + final listWriter = IsarCore.beginList(writer, 12, list.length); + for (var i = 0; i < list.length; i++) { + IsarCore.writeString(listWriter, i, list[i]); + } + IsarCore.endList(writer, listWriter); + } + } + { + final value = object.userData; + if (value == null) { + IsarCore.writeNull(writer, 13); + } else { + IsarCore.writeString(writer, 13, value); + } + } + return Isar.fastHash(object.id); +} + +@isarProtected +ISyncedItem deserializeISyncedItem(IsarReader reader) { + final String? _userId; + _userId = IsarCore.readString(reader, 1); + final String _id; + _id = IsarCore.readString(reader, 2) ?? ''; + final int? _sortKey; + { + final value = IsarCore.readLong(reader, 3); + if (value == -9223372036854775808) { + _sortKey = null; + } else { + _sortKey = value; + } + } + final String? _parentId; + _parentId = IsarCore.readString(reader, 4); + final String? _path; + _path = IsarCore.readString(reader, 5); + final int? _fileSize; + { + final value = IsarCore.readLong(reader, 6); + if (value == -9223372036854775808) { + _fileSize = null; + } else { + _fileSize = value; + } + } + final String? _videoFileName; + _videoFileName = IsarCore.readString(reader, 7); + final String? _trickPlayModel; + _trickPlayModel = IsarCore.readString(reader, 8); + final String? _introOutroSkipModel; + _introOutroSkipModel = IsarCore.readString(reader, 9); + final String? _images; + _images = IsarCore.readString(reader, 10); + final List? _chapters; + { + final length = IsarCore.readList(reader, 11, IsarCore.readerPtrPtr); + { + final reader = IsarCore.readerPtr; + if (reader.isNull) { + _chapters = null; + } else { + final list = List.filled(length, '', growable: true); + for (var i = 0; i < length; i++) { + list[i] = IsarCore.readString(reader, i) ?? ''; + } + IsarCore.freeReader(reader); + _chapters = list; + } + } + } + final List? _subtitles; + { + final length = IsarCore.readList(reader, 12, IsarCore.readerPtrPtr); + { + final reader = IsarCore.readerPtr; + if (reader.isNull) { + _subtitles = null; + } else { + final list = List.filled(length, '', growable: true); + for (var i = 0; i < length; i++) { + list[i] = IsarCore.readString(reader, i) ?? ''; + } + IsarCore.freeReader(reader); + _subtitles = list; + } + } + } + final String? _userData; + _userData = IsarCore.readString(reader, 13); + final object = ISyncedItem( + userId: _userId, + id: _id, + sortKey: _sortKey, + parentId: _parentId, + path: _path, + fileSize: _fileSize, + videoFileName: _videoFileName, + trickPlayModel: _trickPlayModel, + introOutroSkipModel: _introOutroSkipModel, + images: _images, + chapters: _chapters, + subtitles: _subtitles, + userData: _userData, + ); + return object; +} + +@isarProtected +dynamic deserializeISyncedItemProp(IsarReader reader, int property) { + switch (property) { + case 1: + return IsarCore.readString(reader, 1); + case 2: + return IsarCore.readString(reader, 2) ?? ''; + case 3: + { + final value = IsarCore.readLong(reader, 3); + if (value == -9223372036854775808) { + return null; + } else { + return value; + } + } + case 4: + return IsarCore.readString(reader, 4); + case 5: + return IsarCore.readString(reader, 5); + case 6: + { + final value = IsarCore.readLong(reader, 6); + if (value == -9223372036854775808) { + return null; + } else { + return value; + } + } + case 7: + return IsarCore.readString(reader, 7); + case 8: + return IsarCore.readString(reader, 8); + case 9: + return IsarCore.readString(reader, 9); + case 10: + return IsarCore.readString(reader, 10); + case 11: + { + final length = IsarCore.readList(reader, 11, IsarCore.readerPtrPtr); + { + final reader = IsarCore.readerPtr; + if (reader.isNull) { + return null; + } else { + final list = List.filled(length, '', growable: true); + for (var i = 0; i < length; i++) { + list[i] = IsarCore.readString(reader, i) ?? ''; + } + IsarCore.freeReader(reader); + return list; + } + } + } + case 12: + { + final length = IsarCore.readList(reader, 12, IsarCore.readerPtrPtr); + { + final reader = IsarCore.readerPtr; + if (reader.isNull) { + return null; + } else { + final list = List.filled(length, '', growable: true); + for (var i = 0; i < length; i++) { + list[i] = IsarCore.readString(reader, i) ?? ''; + } + IsarCore.freeReader(reader); + return list; + } + } + } + case 13: + return IsarCore.readString(reader, 13); + default: + throw ArgumentError('Unknown property: $property'); + } +} + +sealed class _ISyncedItemUpdate { + bool call({ + required String id, + String? userId, + int? sortKey, + String? parentId, + String? path, + int? fileSize, + String? videoFileName, + String? trickPlayModel, + String? introOutroSkipModel, + String? images, + String? userData, + }); +} + +class _ISyncedItemUpdateImpl implements _ISyncedItemUpdate { + const _ISyncedItemUpdateImpl(this.collection); + + final IsarCollection collection; + + @override + bool call({ + required String id, + Object? userId = ignore, + Object? sortKey = ignore, + Object? parentId = ignore, + Object? path = ignore, + Object? fileSize = ignore, + Object? videoFileName = ignore, + Object? trickPlayModel = ignore, + Object? introOutroSkipModel = ignore, + Object? images = ignore, + Object? userData = ignore, + }) { + return collection.updateProperties([ + id + ], { + if (userId != ignore) 1: userId as String?, + if (sortKey != ignore) 3: sortKey as int?, + if (parentId != ignore) 4: parentId as String?, + if (path != ignore) 5: path as String?, + if (fileSize != ignore) 6: fileSize as int?, + if (videoFileName != ignore) 7: videoFileName as String?, + if (trickPlayModel != ignore) 8: trickPlayModel as String?, + if (introOutroSkipModel != ignore) 9: introOutroSkipModel as String?, + if (images != ignore) 10: images as String?, + if (userData != ignore) 13: userData as String?, + }) > + 0; + } +} + +sealed class _ISyncedItemUpdateAll { + int call({ + required List id, + String? userId, + int? sortKey, + String? parentId, + String? path, + int? fileSize, + String? videoFileName, + String? trickPlayModel, + String? introOutroSkipModel, + String? images, + String? userData, + }); +} + +class _ISyncedItemUpdateAllImpl implements _ISyncedItemUpdateAll { + const _ISyncedItemUpdateAllImpl(this.collection); + + final IsarCollection collection; + + @override + int call({ + required List id, + Object? userId = ignore, + Object? sortKey = ignore, + Object? parentId = ignore, + Object? path = ignore, + Object? fileSize = ignore, + Object? videoFileName = ignore, + Object? trickPlayModel = ignore, + Object? introOutroSkipModel = ignore, + Object? images = ignore, + Object? userData = ignore, + }) { + return collection.updateProperties(id, { + if (userId != ignore) 1: userId as String?, + if (sortKey != ignore) 3: sortKey as int?, + if (parentId != ignore) 4: parentId as String?, + if (path != ignore) 5: path as String?, + if (fileSize != ignore) 6: fileSize as int?, + if (videoFileName != ignore) 7: videoFileName as String?, + if (trickPlayModel != ignore) 8: trickPlayModel as String?, + if (introOutroSkipModel != ignore) 9: introOutroSkipModel as String?, + if (images != ignore) 10: images as String?, + if (userData != ignore) 13: userData as String?, + }); + } +} + +extension ISyncedItemUpdate on IsarCollection { + _ISyncedItemUpdate get update => _ISyncedItemUpdateImpl(this); + + _ISyncedItemUpdateAll get updateAll => _ISyncedItemUpdateAllImpl(this); +} + +sealed class _ISyncedItemQueryUpdate { + int call({ + String? userId, + int? sortKey, + String? parentId, + String? path, + int? fileSize, + String? videoFileName, + String? trickPlayModel, + String? introOutroSkipModel, + String? images, + String? userData, + }); +} + +class _ISyncedItemQueryUpdateImpl implements _ISyncedItemQueryUpdate { + const _ISyncedItemQueryUpdateImpl(this.query, {this.limit}); + + final IsarQuery query; + final int? limit; + + @override + int call({ + Object? userId = ignore, + Object? sortKey = ignore, + Object? parentId = ignore, + Object? path = ignore, + Object? fileSize = ignore, + Object? videoFileName = ignore, + Object? trickPlayModel = ignore, + Object? introOutroSkipModel = ignore, + Object? images = ignore, + Object? userData = ignore, + }) { + return query.updateProperties(limit: limit, { + if (userId != ignore) 1: userId as String?, + if (sortKey != ignore) 3: sortKey as int?, + if (parentId != ignore) 4: parentId as String?, + if (path != ignore) 5: path as String?, + if (fileSize != ignore) 6: fileSize as int?, + if (videoFileName != ignore) 7: videoFileName as String?, + if (trickPlayModel != ignore) 8: trickPlayModel as String?, + if (introOutroSkipModel != ignore) 9: introOutroSkipModel as String?, + if (images != ignore) 10: images as String?, + if (userData != ignore) 13: userData as String?, + }); + } +} + +extension ISyncedItemQueryUpdate on IsarQuery { + _ISyncedItemQueryUpdate get updateFirst => + _ISyncedItemQueryUpdateImpl(this, limit: 1); + + _ISyncedItemQueryUpdate get updateAll => _ISyncedItemQueryUpdateImpl(this); +} + +class _ISyncedItemQueryBuilderUpdateImpl implements _ISyncedItemQueryUpdate { + const _ISyncedItemQueryBuilderUpdateImpl(this.query, {this.limit}); + + final QueryBuilder query; + final int? limit; + + @override + int call({ + Object? userId = ignore, + Object? sortKey = ignore, + Object? parentId = ignore, + Object? path = ignore, + Object? fileSize = ignore, + Object? videoFileName = ignore, + Object? trickPlayModel = ignore, + Object? introOutroSkipModel = ignore, + Object? images = ignore, + Object? userData = ignore, + }) { + final q = query.build(); + try { + return q.updateProperties(limit: limit, { + if (userId != ignore) 1: userId as String?, + if (sortKey != ignore) 3: sortKey as int?, + if (parentId != ignore) 4: parentId as String?, + if (path != ignore) 5: path as String?, + if (fileSize != ignore) 6: fileSize as int?, + if (videoFileName != ignore) 7: videoFileName as String?, + if (trickPlayModel != ignore) 8: trickPlayModel as String?, + if (introOutroSkipModel != ignore) 9: introOutroSkipModel as String?, + if (images != ignore) 10: images as String?, + if (userData != ignore) 13: userData as String?, + }); + } finally { + q.close(); + } + } +} + +extension ISyncedItemQueryBuilderUpdate + on QueryBuilder { + _ISyncedItemQueryUpdate get updateFirst => + _ISyncedItemQueryBuilderUpdateImpl(this, limit: 1); + + _ISyncedItemQueryUpdate get updateAll => + _ISyncedItemQueryBuilderUpdateImpl(this); +} + +extension ISyncedItemQueryFilter + on QueryBuilder { + QueryBuilder userIdIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const IsNullCondition(property: 1)); + }); + } + + QueryBuilder + userIdIsNotNull() { + return QueryBuilder.apply(not(), (query) { + return query.addFilterCondition(const IsNullCondition(property: 1)); + }); + } + + QueryBuilder userIdEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EqualCondition( + property: 1, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + userIdGreaterThan( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterCondition( + property: 1, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + userIdGreaterThanOrEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterOrEqualCondition( + property: 1, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder userIdLessThan( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessCondition( + property: 1, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + userIdLessThanOrEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessOrEqualCondition( + property: 1, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder userIdBetween( + String? lower, + String? upper, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + BetweenCondition( + property: 1, + lower: lower, + upper: upper, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + userIdStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + StartsWithCondition( + property: 1, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder userIdEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EndsWithCondition( + property: 1, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder userIdContains( + String value, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + ContainsCondition( + property: 1, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder userIdMatches( + String pattern, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + MatchesCondition( + property: 1, + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + userIdIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const EqualCondition( + property: 1, + value: '', + ), + ); + }); + } + + QueryBuilder + userIdIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const GreaterCondition( + property: 1, + value: '', + ), + ); + }); + } + + QueryBuilder idEqualTo( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EqualCondition( + property: 2, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder idGreaterThan( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterCondition( + property: 2, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + idGreaterThanOrEqualTo( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterOrEqualCondition( + property: 2, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder idLessThan( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessCondition( + property: 2, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + idLessThanOrEqualTo( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessOrEqualCondition( + property: 2, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder idBetween( + String lower, + String upper, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + BetweenCondition( + property: 2, + lower: lower, + upper: upper, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder idStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + StartsWithCondition( + property: 2, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder idEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EndsWithCondition( + property: 2, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder idContains( + String value, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + ContainsCondition( + property: 2, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder idMatches( + String pattern, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + MatchesCondition( + property: 2, + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder idIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const EqualCondition( + property: 2, + value: '', + ), + ); + }); + } + + QueryBuilder idIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const GreaterCondition( + property: 2, + value: '', + ), + ); + }); + } + + QueryBuilder + sortKeyIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const IsNullCondition(property: 3)); + }); + } + + QueryBuilder + sortKeyIsNotNull() { + return QueryBuilder.apply(not(), (query) { + return query.addFilterCondition(const IsNullCondition(property: 3)); + }); + } + + QueryBuilder sortKeyEqualTo( + int? value, + ) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EqualCondition( + property: 3, + value: value, + ), + ); + }); + } + + QueryBuilder + sortKeyGreaterThan( + int? value, + ) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterCondition( + property: 3, + value: value, + ), + ); + }); + } + + QueryBuilder + sortKeyGreaterThanOrEqualTo( + int? value, + ) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterOrEqualCondition( + property: 3, + value: value, + ), + ); + }); + } + + QueryBuilder sortKeyLessThan( + int? value, + ) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessCondition( + property: 3, + value: value, + ), + ); + }); + } + + QueryBuilder + sortKeyLessThanOrEqualTo( + int? value, + ) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessOrEqualCondition( + property: 3, + value: value, + ), + ); + }); + } + + QueryBuilder sortKeyBetween( + int? lower, + int? upper, + ) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + BetweenCondition( + property: 3, + lower: lower, + upper: upper, + ), + ); + }); + } + + QueryBuilder + parentIdIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const IsNullCondition(property: 4)); + }); + } + + QueryBuilder + parentIdIsNotNull() { + return QueryBuilder.apply(not(), (query) { + return query.addFilterCondition(const IsNullCondition(property: 4)); + }); + } + + QueryBuilder parentIdEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EqualCondition( + property: 4, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + parentIdGreaterThan( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterCondition( + property: 4, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + parentIdGreaterThanOrEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterOrEqualCondition( + property: 4, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + parentIdLessThan( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessCondition( + property: 4, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + parentIdLessThanOrEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessOrEqualCondition( + property: 4, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder parentIdBetween( + String? lower, + String? upper, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + BetweenCondition( + property: 4, + lower: lower, + upper: upper, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + parentIdStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + StartsWithCondition( + property: 4, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + parentIdEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EndsWithCondition( + property: 4, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + parentIdContains(String value, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + ContainsCondition( + property: 4, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder parentIdMatches( + String pattern, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + MatchesCondition( + property: 4, + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + parentIdIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const EqualCondition( + property: 4, + value: '', + ), + ); + }); + } + + QueryBuilder + parentIdIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const GreaterCondition( + property: 4, + value: '', + ), + ); + }); + } + + QueryBuilder pathIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const IsNullCondition(property: 5)); + }); + } + + QueryBuilder + pathIsNotNull() { + return QueryBuilder.apply(not(), (query) { + return query.addFilterCondition(const IsNullCondition(property: 5)); + }); + } + + QueryBuilder pathEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EqualCondition( + property: 5, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder pathGreaterThan( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterCondition( + property: 5, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + pathGreaterThanOrEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterOrEqualCondition( + property: 5, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder pathLessThan( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessCondition( + property: 5, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + pathLessThanOrEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessOrEqualCondition( + property: 5, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder pathBetween( + String? lower, + String? upper, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + BetweenCondition( + property: 5, + lower: lower, + upper: upper, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder pathStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + StartsWithCondition( + property: 5, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder pathEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EndsWithCondition( + property: 5, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder pathContains( + String value, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + ContainsCondition( + property: 5, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder pathMatches( + String pattern, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + MatchesCondition( + property: 5, + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder pathIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const EqualCondition( + property: 5, + value: '', + ), + ); + }); + } + + QueryBuilder + pathIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const GreaterCondition( + property: 5, + value: '', + ), + ); + }); + } + + QueryBuilder + fileSizeIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const IsNullCondition(property: 6)); + }); + } + + QueryBuilder + fileSizeIsNotNull() { + return QueryBuilder.apply(not(), (query) { + return query.addFilterCondition(const IsNullCondition(property: 6)); + }); + } + + QueryBuilder fileSizeEqualTo( + int? value, + ) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EqualCondition( + property: 6, + value: value, + ), + ); + }); + } + + QueryBuilder + fileSizeGreaterThan( + int? value, + ) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterCondition( + property: 6, + value: value, + ), + ); + }); + } + + QueryBuilder + fileSizeGreaterThanOrEqualTo( + int? value, + ) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterOrEqualCondition( + property: 6, + value: value, + ), + ); + }); + } + + QueryBuilder + fileSizeLessThan( + int? value, + ) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessCondition( + property: 6, + value: value, + ), + ); + }); + } + + QueryBuilder + fileSizeLessThanOrEqualTo( + int? value, + ) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessOrEqualCondition( + property: 6, + value: value, + ), + ); + }); + } + + QueryBuilder fileSizeBetween( + int? lower, + int? upper, + ) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + BetweenCondition( + property: 6, + lower: lower, + upper: upper, + ), + ); + }); + } + + QueryBuilder + videoFileNameIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const IsNullCondition(property: 7)); + }); + } + + QueryBuilder + videoFileNameIsNotNull() { + return QueryBuilder.apply(not(), (query) { + return query.addFilterCondition(const IsNullCondition(property: 7)); + }); + } + + QueryBuilder + videoFileNameEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EqualCondition( + property: 7, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + videoFileNameGreaterThan( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterCondition( + property: 7, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + videoFileNameGreaterThanOrEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterOrEqualCondition( + property: 7, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + videoFileNameLessThan( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessCondition( + property: 7, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + videoFileNameLessThanOrEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessOrEqualCondition( + property: 7, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + videoFileNameBetween( + String? lower, + String? upper, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + BetweenCondition( + property: 7, + lower: lower, + upper: upper, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + videoFileNameStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + StartsWithCondition( + property: 7, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + videoFileNameEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EndsWithCondition( + property: 7, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + videoFileNameContains(String value, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + ContainsCondition( + property: 7, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + videoFileNameMatches(String pattern, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + MatchesCondition( + property: 7, + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + videoFileNameIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const EqualCondition( + property: 7, + value: '', + ), + ); + }); + } + + QueryBuilder + videoFileNameIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const GreaterCondition( + property: 7, + value: '', + ), + ); + }); + } + + QueryBuilder + trickPlayModelIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const IsNullCondition(property: 8)); + }); + } + + QueryBuilder + trickPlayModelIsNotNull() { + return QueryBuilder.apply(not(), (query) { + return query.addFilterCondition(const IsNullCondition(property: 8)); + }); + } + + QueryBuilder + trickPlayModelEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EqualCondition( + property: 8, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + trickPlayModelGreaterThan( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterCondition( + property: 8, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + trickPlayModelGreaterThanOrEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterOrEqualCondition( + property: 8, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + trickPlayModelLessThan( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessCondition( + property: 8, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + trickPlayModelLessThanOrEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessOrEqualCondition( + property: 8, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + trickPlayModelBetween( + String? lower, + String? upper, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + BetweenCondition( + property: 8, + lower: lower, + upper: upper, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + trickPlayModelStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + StartsWithCondition( + property: 8, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + trickPlayModelEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EndsWithCondition( + property: 8, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + trickPlayModelContains(String value, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + ContainsCondition( + property: 8, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + trickPlayModelMatches(String pattern, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + MatchesCondition( + property: 8, + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + trickPlayModelIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const EqualCondition( + property: 8, + value: '', + ), + ); + }); + } + + QueryBuilder + trickPlayModelIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const GreaterCondition( + property: 8, + value: '', + ), + ); + }); + } + + QueryBuilder + introOutroSkipModelIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const IsNullCondition(property: 9)); + }); + } + + QueryBuilder + introOutroSkipModelIsNotNull() { + return QueryBuilder.apply(not(), (query) { + return query.addFilterCondition(const IsNullCondition(property: 9)); + }); + } + + QueryBuilder + introOutroSkipModelEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EqualCondition( + property: 9, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + introOutroSkipModelGreaterThan( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterCondition( + property: 9, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + introOutroSkipModelGreaterThanOrEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterOrEqualCondition( + property: 9, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + introOutroSkipModelLessThan( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessCondition( + property: 9, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + introOutroSkipModelLessThanOrEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessOrEqualCondition( + property: 9, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + introOutroSkipModelBetween( + String? lower, + String? upper, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + BetweenCondition( + property: 9, + lower: lower, + upper: upper, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + introOutroSkipModelStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + StartsWithCondition( + property: 9, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + introOutroSkipModelEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EndsWithCondition( + property: 9, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + introOutroSkipModelContains(String value, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + ContainsCondition( + property: 9, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + introOutroSkipModelMatches(String pattern, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + MatchesCondition( + property: 9, + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + introOutroSkipModelIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const EqualCondition( + property: 9, + value: '', + ), + ); + }); + } + + QueryBuilder + introOutroSkipModelIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const GreaterCondition( + property: 9, + value: '', + ), + ); + }); + } + + QueryBuilder imagesIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const IsNullCondition(property: 10)); + }); + } + + QueryBuilder + imagesIsNotNull() { + return QueryBuilder.apply(not(), (query) { + return query.addFilterCondition(const IsNullCondition(property: 10)); + }); + } + + QueryBuilder imagesEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EqualCondition( + property: 10, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + imagesGreaterThan( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterCondition( + property: 10, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + imagesGreaterThanOrEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterOrEqualCondition( + property: 10, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder imagesLessThan( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessCondition( + property: 10, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + imagesLessThanOrEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessOrEqualCondition( + property: 10, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder imagesBetween( + String? lower, + String? upper, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + BetweenCondition( + property: 10, + lower: lower, + upper: upper, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + imagesStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + StartsWithCondition( + property: 10, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder imagesEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EndsWithCondition( + property: 10, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder imagesContains( + String value, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + ContainsCondition( + property: 10, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder imagesMatches( + String pattern, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + MatchesCondition( + property: 10, + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + imagesIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const EqualCondition( + property: 10, + value: '', + ), + ); + }); + } + + QueryBuilder + imagesIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const GreaterCondition( + property: 10, + value: '', + ), + ); + }); + } + + QueryBuilder + chaptersIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const IsNullCondition(property: 11)); + }); + } + + QueryBuilder + chaptersIsNotNull() { + return QueryBuilder.apply(not(), (query) { + return query.addFilterCondition(const IsNullCondition(property: 11)); + }); + } + + QueryBuilder + chaptersElementEqualTo( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EqualCondition( + property: 11, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + chaptersElementGreaterThan( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterCondition( + property: 11, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + chaptersElementGreaterThanOrEqualTo( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterOrEqualCondition( + property: 11, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + chaptersElementLessThan( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessCondition( + property: 11, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + chaptersElementLessThanOrEqualTo( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessOrEqualCondition( + property: 11, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + chaptersElementBetween( + String lower, + String upper, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + BetweenCondition( + property: 11, + lower: lower, + upper: upper, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + chaptersElementStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + StartsWithCondition( + property: 11, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + chaptersElementEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EndsWithCondition( + property: 11, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + chaptersElementContains(String value, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + ContainsCondition( + property: 11, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + chaptersElementMatches(String pattern, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + MatchesCondition( + property: 11, + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + chaptersElementIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const EqualCondition( + property: 11, + value: '', + ), + ); + }); + } + + QueryBuilder + chaptersElementIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const GreaterCondition( + property: 11, + value: '', + ), + ); + }); + } + + QueryBuilder + chaptersIsEmpty() { + return not().group( + (q) => q.chaptersIsNull().or().chaptersIsNotEmpty(), + ); + } + + QueryBuilder + chaptersIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const GreaterOrEqualCondition(property: 11, value: null), + ); + }); + } + + QueryBuilder + subtitlesIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const IsNullCondition(property: 12)); + }); + } + + QueryBuilder + subtitlesIsNotNull() { + return QueryBuilder.apply(not(), (query) { + return query.addFilterCondition(const IsNullCondition(property: 12)); + }); + } + + QueryBuilder + subtitlesElementEqualTo( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EqualCondition( + property: 12, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + subtitlesElementGreaterThan( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterCondition( + property: 12, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + subtitlesElementGreaterThanOrEqualTo( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterOrEqualCondition( + property: 12, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + subtitlesElementLessThan( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessCondition( + property: 12, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + subtitlesElementLessThanOrEqualTo( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessOrEqualCondition( + property: 12, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + subtitlesElementBetween( + String lower, + String upper, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + BetweenCondition( + property: 12, + lower: lower, + upper: upper, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + subtitlesElementStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + StartsWithCondition( + property: 12, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + subtitlesElementEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EndsWithCondition( + property: 12, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + subtitlesElementContains(String value, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + ContainsCondition( + property: 12, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + subtitlesElementMatches(String pattern, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + MatchesCondition( + property: 12, + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + subtitlesElementIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const EqualCondition( + property: 12, + value: '', + ), + ); + }); + } + + QueryBuilder + subtitlesElementIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const GreaterCondition( + property: 12, + value: '', + ), + ); + }); + } + + QueryBuilder + subtitlesIsEmpty() { + return not().group( + (q) => q.subtitlesIsNull().or().subtitlesIsNotEmpty(), + ); + } + + QueryBuilder + subtitlesIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const GreaterOrEqualCondition(property: 12, value: null), + ); + }); + } + + QueryBuilder + userDataIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const IsNullCondition(property: 13)); + }); + } + + QueryBuilder + userDataIsNotNull() { + return QueryBuilder.apply(not(), (query) { + return query.addFilterCondition(const IsNullCondition(property: 13)); + }); + } + + QueryBuilder userDataEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EqualCondition( + property: 13, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + userDataGreaterThan( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterCondition( + property: 13, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + userDataGreaterThanOrEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + GreaterOrEqualCondition( + property: 13, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + userDataLessThan( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessCondition( + property: 13, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + userDataLessThanOrEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + LessOrEqualCondition( + property: 13, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder userDataBetween( + String? lower, + String? upper, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + BetweenCondition( + property: 13, + lower: lower, + upper: upper, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + userDataStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + StartsWithCondition( + property: 13, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + userDataEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + EndsWithCondition( + property: 13, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + userDataContains(String value, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + ContainsCondition( + property: 13, + value: value, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder userDataMatches( + String pattern, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + MatchesCondition( + property: 13, + wildcard: pattern, + caseSensitive: caseSensitive, + ), + ); + }); + } + + QueryBuilder + userDataIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const EqualCondition( + property: 13, + value: '', + ), + ); + }); + } + + QueryBuilder + userDataIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition( + const GreaterCondition( + property: 13, + value: '', + ), + ); + }); + } +} + +extension ISyncedItemQueryObject + on QueryBuilder {} + +extension ISyncedItemQuerySortBy + on QueryBuilder { + QueryBuilder sortByUserId( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 1, + caseSensitive: caseSensitive, + ); + }); + } + + QueryBuilder sortByUserIdDesc( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 1, + sort: Sort.desc, + caseSensitive: caseSensitive, + ); + }); + } + + QueryBuilder sortById( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 2, + caseSensitive: caseSensitive, + ); + }); + } + + QueryBuilder sortByIdDesc( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 2, + sort: Sort.desc, + caseSensitive: caseSensitive, + ); + }); + } + + QueryBuilder sortBySortKey() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(3); + }); + } + + QueryBuilder sortBySortKeyDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(3, sort: Sort.desc); + }); + } + + QueryBuilder sortByParentId( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 4, + caseSensitive: caseSensitive, + ); + }); + } + + QueryBuilder sortByParentIdDesc( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 4, + sort: Sort.desc, + caseSensitive: caseSensitive, + ); + }); + } + + QueryBuilder sortByPath( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 5, + caseSensitive: caseSensitive, + ); + }); + } + + QueryBuilder sortByPathDesc( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 5, + sort: Sort.desc, + caseSensitive: caseSensitive, + ); + }); + } + + QueryBuilder sortByFileSize() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(6); + }); + } + + QueryBuilder sortByFileSizeDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(6, sort: Sort.desc); + }); + } + + QueryBuilder sortByVideoFileName( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 7, + caseSensitive: caseSensitive, + ); + }); + } + + QueryBuilder sortByVideoFileNameDesc( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 7, + sort: Sort.desc, + caseSensitive: caseSensitive, + ); + }); + } + + QueryBuilder sortByTrickPlayModel( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 8, + caseSensitive: caseSensitive, + ); + }); + } + + QueryBuilder sortByTrickPlayModelDesc( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 8, + sort: Sort.desc, + caseSensitive: caseSensitive, + ); + }); + } + + QueryBuilder + sortByIntroOutroSkipModel({bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 9, + caseSensitive: caseSensitive, + ); + }); + } + + QueryBuilder + sortByIntroOutroSkipModelDesc({bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 9, + sort: Sort.desc, + caseSensitive: caseSensitive, + ); + }); + } + + QueryBuilder sortByImages( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 10, + caseSensitive: caseSensitive, + ); + }); + } + + QueryBuilder sortByImagesDesc( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 10, + sort: Sort.desc, + caseSensitive: caseSensitive, + ); + }); + } + + QueryBuilder sortByUserData( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 13, + caseSensitive: caseSensitive, + ); + }); + } + + QueryBuilder sortByUserDataDesc( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy( + 13, + sort: Sort.desc, + caseSensitive: caseSensitive, + ); + }); + } +} + +extension ISyncedItemQuerySortThenBy + on QueryBuilder { + QueryBuilder thenByUserId( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(1, caseSensitive: caseSensitive); + }); + } + + QueryBuilder thenByUserIdDesc( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(1, sort: Sort.desc, caseSensitive: caseSensitive); + }); + } + + QueryBuilder thenById( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(2, caseSensitive: caseSensitive); + }); + } + + QueryBuilder thenByIdDesc( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(2, sort: Sort.desc, caseSensitive: caseSensitive); + }); + } + + QueryBuilder thenBySortKey() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(3); + }); + } + + QueryBuilder thenBySortKeyDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(3, sort: Sort.desc); + }); + } + + QueryBuilder thenByParentId( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(4, caseSensitive: caseSensitive); + }); + } + + QueryBuilder thenByParentIdDesc( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(4, sort: Sort.desc, caseSensitive: caseSensitive); + }); + } + + QueryBuilder thenByPath( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(5, caseSensitive: caseSensitive); + }); + } + + QueryBuilder thenByPathDesc( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(5, sort: Sort.desc, caseSensitive: caseSensitive); + }); + } + + QueryBuilder thenByFileSize() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(6); + }); + } + + QueryBuilder thenByFileSizeDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(6, sort: Sort.desc); + }); + } + + QueryBuilder thenByVideoFileName( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(7, caseSensitive: caseSensitive); + }); + } + + QueryBuilder thenByVideoFileNameDesc( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(7, sort: Sort.desc, caseSensitive: caseSensitive); + }); + } + + QueryBuilder thenByTrickPlayModel( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(8, caseSensitive: caseSensitive); + }); + } + + QueryBuilder thenByTrickPlayModelDesc( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(8, sort: Sort.desc, caseSensitive: caseSensitive); + }); + } + + QueryBuilder + thenByIntroOutroSkipModel({bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(9, caseSensitive: caseSensitive); + }); + } + + QueryBuilder + thenByIntroOutroSkipModelDesc({bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(9, sort: Sort.desc, caseSensitive: caseSensitive); + }); + } + + QueryBuilder thenByImages( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(10, caseSensitive: caseSensitive); + }); + } + + QueryBuilder thenByImagesDesc( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(10, sort: Sort.desc, caseSensitive: caseSensitive); + }); + } + + QueryBuilder thenByUserData( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(13, caseSensitive: caseSensitive); + }); + } + + QueryBuilder thenByUserDataDesc( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(13, sort: Sort.desc, caseSensitive: caseSensitive); + }); + } +} + +extension ISyncedItemQueryWhereDistinct + on QueryBuilder { + QueryBuilder distinctByUserId( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(1, caseSensitive: caseSensitive); + }); + } + + QueryBuilder distinctBySortKey() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(3); + }); + } + + QueryBuilder distinctByParentId( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(4, caseSensitive: caseSensitive); + }); + } + + QueryBuilder distinctByPath( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(5, caseSensitive: caseSensitive); + }); + } + + QueryBuilder distinctByFileSize() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(6); + }); + } + + QueryBuilder + distinctByVideoFileName({bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(7, caseSensitive: caseSensitive); + }); + } + + QueryBuilder + distinctByTrickPlayModel({bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(8, caseSensitive: caseSensitive); + }); + } + + QueryBuilder + distinctByIntroOutroSkipModel({bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(9, caseSensitive: caseSensitive); + }); + } + + QueryBuilder distinctByImages( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(10, caseSensitive: caseSensitive); + }); + } + + QueryBuilder distinctByChapters() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(11); + }); + } + + QueryBuilder distinctBySubtitles() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(12); + }); + } + + QueryBuilder distinctByUserData( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(13, caseSensitive: caseSensitive); + }); + } +} + +extension ISyncedItemQueryProperty1 + on QueryBuilder { + QueryBuilder userIdProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(1); + }); + } + + QueryBuilder idProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(2); + }); + } + + QueryBuilder sortKeyProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(3); + }); + } + + QueryBuilder parentIdProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(4); + }); + } + + QueryBuilder pathProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(5); + }); + } + + QueryBuilder fileSizeProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(6); + }); + } + + QueryBuilder videoFileNameProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(7); + }); + } + + QueryBuilder trickPlayModelProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(8); + }); + } + + QueryBuilder + introOutroSkipModelProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(9); + }); + } + + QueryBuilder imagesProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(10); + }); + } + + QueryBuilder?, QAfterProperty> chaptersProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(11); + }); + } + + QueryBuilder?, QAfterProperty> subtitlesProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(12); + }); + } + + QueryBuilder userDataProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(13); + }); + } +} + +extension ISyncedItemQueryProperty2 + on QueryBuilder { + QueryBuilder userIdProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(1); + }); + } + + QueryBuilder idProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(2); + }); + } + + QueryBuilder sortKeyProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(3); + }); + } + + QueryBuilder parentIdProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(4); + }); + } + + QueryBuilder pathProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(5); + }); + } + + QueryBuilder fileSizeProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(6); + }); + } + + QueryBuilder + videoFileNameProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(7); + }); + } + + QueryBuilder + trickPlayModelProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(8); + }); + } + + QueryBuilder + introOutroSkipModelProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(9); + }); + } + + QueryBuilder imagesProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(10); + }); + } + + QueryBuilder?), QAfterProperty> + chaptersProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(11); + }); + } + + QueryBuilder?), QAfterProperty> + subtitlesProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(12); + }); + } + + QueryBuilder userDataProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(13); + }); + } +} + +extension ISyncedItemQueryProperty3 + on QueryBuilder { + QueryBuilder userIdProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(1); + }); + } + + QueryBuilder idProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(2); + }); + } + + QueryBuilder sortKeyProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(3); + }); + } + + QueryBuilder parentIdProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(4); + }); + } + + QueryBuilder pathProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(5); + }); + } + + QueryBuilder fileSizeProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(6); + }); + } + + QueryBuilder + videoFileNameProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(7); + }); + } + + QueryBuilder + trickPlayModelProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(8); + }); + } + + QueryBuilder + introOutroSkipModelProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(9); + }); + } + + QueryBuilder imagesProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(10); + }); + } + + QueryBuilder?), QOperations> + chaptersProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(11); + }); + } + + QueryBuilder?), QOperations> + subtitlesProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(12); + }); + } + + QueryBuilder userDataProperty() { + return QueryBuilder.apply(this, (query) { + return query.addProperty(13); + }); + } +} diff --git a/lib/models/syncing/sync_item.dart b/lib/models/syncing/sync_item.dart new file mode 100644 index 0000000..27860c1 --- /dev/null +++ b/lib/models/syncing/sync_item.dart @@ -0,0 +1,197 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:background_downloader/background_downloader.dart'; +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/chapters_model.dart'; +import 'package:fladder/models/items/images_models.dart'; +import 'package:fladder/models/items/intro_skip_model.dart'; +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/models/items/media_streams_model.dart'; +import 'package:fladder/models/items/trick_play_model.dart'; +import 'package:fladder/models/syncing/i_synced_item.dart'; +import 'package:fladder/providers/sync/sync_provider_helpers.dart'; +import 'package:fladder/providers/sync_provider.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:path/path.dart'; + +part 'sync_item.freezed.dart'; +part 'sync_item.g.dart'; + +@freezed +class SyncedItem with _$SyncedItem { + const SyncedItem._(); + + factory SyncedItem({ + required String id, + String? parentId, + required String userId, + String? path, + @Default(false) bool markedForDelete, + int? sortKey, + int? fileSize, + String? videoFileName, + IntroOutSkipModel? introOutSkipModel, + TrickPlayModel? fTrickPlayModel, + ImagesData? fImages, + @Default([]) List fChapters, + @Default([]) List subtitles, + @UserDataJsonSerializer() UserData? userData, + }) = _SyncItem; + + static String trickPlayPath = "TrickPlay"; + + List get chapters => fChapters.map((e) => e.copyWith(imageUrl: joinAll({"$path", e.imageUrl}))).toList(); + + ImagesData? get images => fImages?.copyWith( + primary: () => fImages?.primary?.copyWith(path: joinAll(["$path", "${fImages?.primary?.path}"])), + logo: () => fImages?.logo?.copyWith(path: joinAll(["$path", "${fImages?.logo?.path}"])), + backDrop: () => fImages?.backDrop?.map((e) => e.copyWith(path: joinAll(["$path", (e.path)]))).toList(), + ); + + TrickPlayModel? get trickPlayModel => fTrickPlayModel?.copyWith( + images: fTrickPlayModel?.images + .map( + (trickPlayPath) => joinAll(["$path", trickPlayPath]), + ) + .toList() ?? + []); + + File get dataFile => File(joinAll(["$path", "data.json"])); + Directory get trickPlayDirectory => Directory(joinAll(["$path", trickPlayPath])); + File get videoFile => File(joinAll(["$path", "$videoFileName"])); + Directory get directory => Directory(path ?? ""); + + SyncStatus get status => switch (videoFile.existsSync()) { + true => SyncStatus.complete, + _ => SyncStatus.partially, + }; + + String? get taskId => null; + + bool get childHasTask => false; + + double get totalProgress => 0.0; + + bool get hasVideoFile => videoFileName?.isNotEmpty == true && (fileSize ?? 0) > 0; + + TaskStatus get anyStatus { + return TaskStatus.notFound; + } + + double get downloadProgress => 0.0; + TaskStatus get downloadStatus => TaskStatus.notFound; + DownloadTask? get task => null; + + Future deleteDatFiles(Ref ref) async { + try { + await videoFile.delete(); + await Directory(joinAll([directory.path, trickPlayPath])).delete(recursive: true); + } catch (e) { + return false; + } + + return true; + } + + List nestedChildren(WidgetRef ref) => ref.watch(syncChildrenProvider(this)); + + List getChildren(Ref ref) => ref.read(syncProvider.notifier).getChildren(this); + List getNestedChildren(Ref ref) => ref.read(syncProvider.notifier).getNestedChildren(this); + + Future get getDirSize async { + var files = await directory.list(recursive: true).toList(); + var dirSize = files.fold(0, (int sum, file) => sum + file.statSync().size); + return dirSize; + } + + ItemBaseModel? createItemModel(Ref ref) { + if (!dataFile.existsSync()) return null; + final BaseItemDto itemDto = BaseItemDto.fromJson(jsonDecode(dataFile.readAsStringSync())); + final itemModel = ItemBaseModel.fromBaseDto(itemDto, ref); + return itemModel.copyWith( + images: images, + userData: userData, + ); + } + + factory SyncedItem.fromJson(Map json) => _$SyncedItemFromJson(json); + + factory SyncedItem.fromIsar(ISyncedItem isarSyncedItem, String savePath) { + return SyncedItem( + id: isarSyncedItem.id, + parentId: isarSyncedItem.parentId, + userId: isarSyncedItem.userId ?? "", + sortKey: isarSyncedItem.sortKey, + path: joinAll([savePath, isarSyncedItem.path ?? ""]), + fileSize: isarSyncedItem.fileSize, + videoFileName: isarSyncedItem.videoFileName, + introOutSkipModel: isarSyncedItem.introOutroSkipModel != null + ? IntroOutSkipModel.fromJson(jsonDecode(isarSyncedItem.introOutroSkipModel!)) + : null, + fTrickPlayModel: isarSyncedItem.trickPlayModel != null + ? TrickPlayModel.fromJson(jsonDecode(isarSyncedItem.trickPlayModel!)) + : null, + fImages: isarSyncedItem.images != null ? ImagesData.fromJson(jsonDecode(isarSyncedItem.images!)) : null, + fChapters: isarSyncedItem.chapters + ?.map( + (e) => Chapter.fromJson(jsonDecode(e)), + ) + .toList() ?? + [], + subtitles: isarSyncedItem.subtitles + ?.map( + (e) => SubStreamModel.fromJson(jsonDecode(e)), + ) + .toList() ?? + [], + userData: isarSyncedItem.userData != null ? UserData.fromJson(jsonDecode(isarSyncedItem.userData!)) : null, + ); + } +} + +enum SyncStatus { + complete( + "Synced", + Color.fromARGB(255, 141, 214, 58), + IconsaxOutline.tick_circle, + ), + partially( + "Partially", + Color.fromARGB(255, 221, 135, 23), + IconsaxOutline.more_circle, + ), + ; + + const SyncStatus(this.label, this.color, this.icon); + + final Color color; + final String label; + final IconData icon; +} + +extension StatusExtension on TaskStatus { + Color color(BuildContext context) => switch (this) { + TaskStatus.enqueued => Colors.blueAccent, + TaskStatus.running => Colors.limeAccent, + TaskStatus.complete => Colors.limeAccent, + TaskStatus.canceled || TaskStatus.notFound || TaskStatus.failed => Theme.of(context).colorScheme.error, + TaskStatus.waitingToRetry => Colors.yellowAccent, + TaskStatus.paused => Colors.orangeAccent, + }; + + String get name => switch (this) { + TaskStatus.enqueued => 'Enqueued', + TaskStatus.running => 'Running', + TaskStatus.complete => 'Complete', + TaskStatus.notFound => 'Not Found', + TaskStatus.failed => 'Failed', + TaskStatus.canceled => 'Canceled', + TaskStatus.waitingToRetry => 'Waiting To Retry', + TaskStatus.paused => 'Paused', + }; +} diff --git a/lib/models/syncing/sync_item.freezed.dart b/lib/models/syncing/sync_item.freezed.dart new file mode 100644 index 0000000..37512ac --- /dev/null +++ b/lib/models/syncing/sync_item.freezed.dart @@ -0,0 +1,494 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'sync_item.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +SyncedItem _$SyncedItemFromJson(Map json) { + return _SyncItem.fromJson(json); +} + +/// @nodoc +mixin _$SyncedItem { + String get id => throw _privateConstructorUsedError; + String? get parentId => throw _privateConstructorUsedError; + String get userId => throw _privateConstructorUsedError; + String? get path => throw _privateConstructorUsedError; + bool get markedForDelete => throw _privateConstructorUsedError; + int? get sortKey => throw _privateConstructorUsedError; + int? get fileSize => throw _privateConstructorUsedError; + String? get videoFileName => throw _privateConstructorUsedError; + IntroOutSkipModel? get introOutSkipModel => + throw _privateConstructorUsedError; + TrickPlayModel? get fTrickPlayModel => throw _privateConstructorUsedError; + ImagesData? get fImages => throw _privateConstructorUsedError; + List get fChapters => throw _privateConstructorUsedError; + List get subtitles => throw _privateConstructorUsedError; + @UserDataJsonSerializer() + UserData? get userData => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $SyncedItemCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SyncedItemCopyWith<$Res> { + factory $SyncedItemCopyWith( + SyncedItem value, $Res Function(SyncedItem) then) = + _$SyncedItemCopyWithImpl<$Res, SyncedItem>; + @useResult + $Res call( + {String id, + String? parentId, + String userId, + String? path, + bool markedForDelete, + int? sortKey, + int? fileSize, + String? videoFileName, + IntroOutSkipModel? introOutSkipModel, + TrickPlayModel? fTrickPlayModel, + ImagesData? fImages, + List fChapters, + List subtitles, + @UserDataJsonSerializer() UserData? userData}); + + $IntroOutSkipModelCopyWith<$Res>? get introOutSkipModel; + $TrickPlayModelCopyWith<$Res>? get fTrickPlayModel; +} + +/// @nodoc +class _$SyncedItemCopyWithImpl<$Res, $Val extends SyncedItem> + implements $SyncedItemCopyWith<$Res> { + _$SyncedItemCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? parentId = freezed, + Object? userId = null, + Object? path = freezed, + Object? markedForDelete = null, + Object? sortKey = freezed, + Object? fileSize = freezed, + Object? videoFileName = freezed, + Object? introOutSkipModel = freezed, + Object? fTrickPlayModel = freezed, + Object? fImages = freezed, + Object? fChapters = null, + Object? subtitles = null, + Object? userData = freezed, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + parentId: freezed == parentId + ? _value.parentId + : parentId // ignore: cast_nullable_to_non_nullable + as String?, + userId: null == userId + ? _value.userId + : userId // ignore: cast_nullable_to_non_nullable + as String, + path: freezed == path + ? _value.path + : path // ignore: cast_nullable_to_non_nullable + as String?, + markedForDelete: null == markedForDelete + ? _value.markedForDelete + : markedForDelete // ignore: cast_nullable_to_non_nullable + as bool, + sortKey: freezed == sortKey + ? _value.sortKey + : sortKey // ignore: cast_nullable_to_non_nullable + as int?, + fileSize: freezed == fileSize + ? _value.fileSize + : fileSize // ignore: cast_nullable_to_non_nullable + as int?, + videoFileName: freezed == videoFileName + ? _value.videoFileName + : videoFileName // ignore: cast_nullable_to_non_nullable + as String?, + introOutSkipModel: freezed == introOutSkipModel + ? _value.introOutSkipModel + : introOutSkipModel // ignore: cast_nullable_to_non_nullable + as IntroOutSkipModel?, + fTrickPlayModel: freezed == fTrickPlayModel + ? _value.fTrickPlayModel + : fTrickPlayModel // ignore: cast_nullable_to_non_nullable + as TrickPlayModel?, + fImages: freezed == fImages + ? _value.fImages + : fImages // ignore: cast_nullable_to_non_nullable + as ImagesData?, + fChapters: null == fChapters + ? _value.fChapters + : fChapters // ignore: cast_nullable_to_non_nullable + as List, + subtitles: null == subtitles + ? _value.subtitles + : subtitles // ignore: cast_nullable_to_non_nullable + as List, + userData: freezed == userData + ? _value.userData + : userData // ignore: cast_nullable_to_non_nullable + as UserData?, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $IntroOutSkipModelCopyWith<$Res>? get introOutSkipModel { + if (_value.introOutSkipModel == null) { + return null; + } + + return $IntroOutSkipModelCopyWith<$Res>(_value.introOutSkipModel!, (value) { + return _then(_value.copyWith(introOutSkipModel: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $TrickPlayModelCopyWith<$Res>? get fTrickPlayModel { + if (_value.fTrickPlayModel == null) { + return null; + } + + return $TrickPlayModelCopyWith<$Res>(_value.fTrickPlayModel!, (value) { + return _then(_value.copyWith(fTrickPlayModel: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$SyncItemImplCopyWith<$Res> + implements $SyncedItemCopyWith<$Res> { + factory _$$SyncItemImplCopyWith( + _$SyncItemImpl value, $Res Function(_$SyncItemImpl) then) = + __$$SyncItemImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String id, + String? parentId, + String userId, + String? path, + bool markedForDelete, + int? sortKey, + int? fileSize, + String? videoFileName, + IntroOutSkipModel? introOutSkipModel, + TrickPlayModel? fTrickPlayModel, + ImagesData? fImages, + List fChapters, + List subtitles, + @UserDataJsonSerializer() UserData? userData}); + + @override + $IntroOutSkipModelCopyWith<$Res>? get introOutSkipModel; + @override + $TrickPlayModelCopyWith<$Res>? get fTrickPlayModel; +} + +/// @nodoc +class __$$SyncItemImplCopyWithImpl<$Res> + extends _$SyncedItemCopyWithImpl<$Res, _$SyncItemImpl> + implements _$$SyncItemImplCopyWith<$Res> { + __$$SyncItemImplCopyWithImpl( + _$SyncItemImpl _value, $Res Function(_$SyncItemImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? parentId = freezed, + Object? userId = null, + Object? path = freezed, + Object? markedForDelete = null, + Object? sortKey = freezed, + Object? fileSize = freezed, + Object? videoFileName = freezed, + Object? introOutSkipModel = freezed, + Object? fTrickPlayModel = freezed, + Object? fImages = freezed, + Object? fChapters = null, + Object? subtitles = null, + Object? userData = freezed, + }) { + return _then(_$SyncItemImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + parentId: freezed == parentId + ? _value.parentId + : parentId // ignore: cast_nullable_to_non_nullable + as String?, + userId: null == userId + ? _value.userId + : userId // ignore: cast_nullable_to_non_nullable + as String, + path: freezed == path + ? _value.path + : path // ignore: cast_nullable_to_non_nullable + as String?, + markedForDelete: null == markedForDelete + ? _value.markedForDelete + : markedForDelete // ignore: cast_nullable_to_non_nullable + as bool, + sortKey: freezed == sortKey + ? _value.sortKey + : sortKey // ignore: cast_nullable_to_non_nullable + as int?, + fileSize: freezed == fileSize + ? _value.fileSize + : fileSize // ignore: cast_nullable_to_non_nullable + as int?, + videoFileName: freezed == videoFileName + ? _value.videoFileName + : videoFileName // ignore: cast_nullable_to_non_nullable + as String?, + introOutSkipModel: freezed == introOutSkipModel + ? _value.introOutSkipModel + : introOutSkipModel // ignore: cast_nullable_to_non_nullable + as IntroOutSkipModel?, + fTrickPlayModel: freezed == fTrickPlayModel + ? _value.fTrickPlayModel + : fTrickPlayModel // ignore: cast_nullable_to_non_nullable + as TrickPlayModel?, + fImages: freezed == fImages + ? _value.fImages + : fImages // ignore: cast_nullable_to_non_nullable + as ImagesData?, + fChapters: null == fChapters + ? _value._fChapters + : fChapters // ignore: cast_nullable_to_non_nullable + as List, + subtitles: null == subtitles + ? _value._subtitles + : subtitles // ignore: cast_nullable_to_non_nullable + as List, + userData: freezed == userData + ? _value.userData + : userData // ignore: cast_nullable_to_non_nullable + as UserData?, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$SyncItemImpl extends _SyncItem { + _$SyncItemImpl( + {required this.id, + this.parentId, + required this.userId, + this.path, + this.markedForDelete = false, + this.sortKey, + this.fileSize, + this.videoFileName, + this.introOutSkipModel, + this.fTrickPlayModel, + this.fImages, + final List fChapters = const [], + final List subtitles = const [], + @UserDataJsonSerializer() this.userData}) + : _fChapters = fChapters, + _subtitles = subtitles, + super._(); + + factory _$SyncItemImpl.fromJson(Map json) => + _$$SyncItemImplFromJson(json); + + @override + final String id; + @override + final String? parentId; + @override + final String userId; + @override + final String? path; + @override + @JsonKey() + final bool markedForDelete; + @override + final int? sortKey; + @override + final int? fileSize; + @override + final String? videoFileName; + @override + final IntroOutSkipModel? introOutSkipModel; + @override + final TrickPlayModel? fTrickPlayModel; + @override + final ImagesData? fImages; + final List _fChapters; + @override + @JsonKey() + List get fChapters { + if (_fChapters is EqualUnmodifiableListView) return _fChapters; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_fChapters); + } + + final List _subtitles; + @override + @JsonKey() + List get subtitles { + if (_subtitles is EqualUnmodifiableListView) return _subtitles; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_subtitles); + } + + @override + @UserDataJsonSerializer() + final UserData? userData; + + @override + String toString() { + return 'SyncedItem(id: $id, parentId: $parentId, userId: $userId, path: $path, markedForDelete: $markedForDelete, sortKey: $sortKey, fileSize: $fileSize, videoFileName: $videoFileName, introOutSkipModel: $introOutSkipModel, fTrickPlayModel: $fTrickPlayModel, fImages: $fImages, fChapters: $fChapters, subtitles: $subtitles, userData: $userData)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$SyncItemImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.parentId, parentId) || + other.parentId == parentId) && + (identical(other.userId, userId) || other.userId == userId) && + (identical(other.path, path) || other.path == path) && + (identical(other.markedForDelete, markedForDelete) || + other.markedForDelete == markedForDelete) && + (identical(other.sortKey, sortKey) || other.sortKey == sortKey) && + (identical(other.fileSize, fileSize) || + other.fileSize == fileSize) && + (identical(other.videoFileName, videoFileName) || + other.videoFileName == videoFileName) && + (identical(other.introOutSkipModel, introOutSkipModel) || + other.introOutSkipModel == introOutSkipModel) && + (identical(other.fTrickPlayModel, fTrickPlayModel) || + other.fTrickPlayModel == fTrickPlayModel) && + (identical(other.fImages, fImages) || other.fImages == fImages) && + const DeepCollectionEquality() + .equals(other._fChapters, _fChapters) && + const DeepCollectionEquality() + .equals(other._subtitles, _subtitles) && + (identical(other.userData, userData) || + other.userData == userData)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, + id, + parentId, + userId, + path, + markedForDelete, + sortKey, + fileSize, + videoFileName, + introOutSkipModel, + fTrickPlayModel, + fImages, + const DeepCollectionEquality().hash(_fChapters), + const DeepCollectionEquality().hash(_subtitles), + userData); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$SyncItemImplCopyWith<_$SyncItemImpl> get copyWith => + __$$SyncItemImplCopyWithImpl<_$SyncItemImpl>(this, _$identity); + + @override + Map toJson() { + return _$$SyncItemImplToJson( + this, + ); + } +} + +abstract class _SyncItem extends SyncedItem { + factory _SyncItem( + {required final String id, + final String? parentId, + required final String userId, + final String? path, + final bool markedForDelete, + final int? sortKey, + final int? fileSize, + final String? videoFileName, + final IntroOutSkipModel? introOutSkipModel, + final TrickPlayModel? fTrickPlayModel, + final ImagesData? fImages, + final List fChapters, + final List subtitles, + @UserDataJsonSerializer() final UserData? userData}) = _$SyncItemImpl; + _SyncItem._() : super._(); + + factory _SyncItem.fromJson(Map json) = + _$SyncItemImpl.fromJson; + + @override + String get id; + @override + String? get parentId; + @override + String get userId; + @override + String? get path; + @override + bool get markedForDelete; + @override + int? get sortKey; + @override + int? get fileSize; + @override + String? get videoFileName; + @override + IntroOutSkipModel? get introOutSkipModel; + @override + TrickPlayModel? get fTrickPlayModel; + @override + ImagesData? get fImages; + @override + List get fChapters; + @override + List get subtitles; + @override + @UserDataJsonSerializer() + UserData? get userData; + @override + @JsonKey(ignore: true) + _$$SyncItemImplCopyWith<_$SyncItemImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/syncing/sync_item.g.dart b/lib/models/syncing/sync_item.g.dart new file mode 100644 index 0000000..cac50dd --- /dev/null +++ b/lib/models/syncing/sync_item.g.dart @@ -0,0 +1,71 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'sync_item.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$SyncItemImpl _$$SyncItemImplFromJson(Map json) => + _$SyncItemImpl( + id: json['id'] as String, + parentId: json['parentId'] as String?, + userId: json['userId'] as String, + path: json['path'] as String?, + markedForDelete: json['markedForDelete'] as bool? ?? false, + sortKey: (json['sortKey'] as num?)?.toInt(), + fileSize: (json['fileSize'] as num?)?.toInt(), + videoFileName: json['videoFileName'] as String?, + introOutSkipModel: json['introOutSkipModel'] == null + ? null + : IntroOutSkipModel.fromJson( + json['introOutSkipModel'] as Map), + fTrickPlayModel: json['fTrickPlayModel'] == null + ? null + : TrickPlayModel.fromJson( + json['fTrickPlayModel'] as Map), + fImages: json['fImages'] == null + ? null + : ImagesData.fromJson(json['fImages'] as String), + fChapters: (json['fChapters'] as List?) + ?.map((e) => Chapter.fromJson(e as String)) + .toList() ?? + const [], + subtitles: (json['subtitles'] as List?) + ?.map((e) => SubStreamModel.fromJson(e as String)) + .toList() ?? + const [], + userData: _$JsonConverterFromJson( + json['userData'], const UserDataJsonSerializer().fromJson), + ); + +Map _$$SyncItemImplToJson(_$SyncItemImpl instance) => + { + 'id': instance.id, + 'parentId': instance.parentId, + 'userId': instance.userId, + 'path': instance.path, + 'markedForDelete': instance.markedForDelete, + 'sortKey': instance.sortKey, + 'fileSize': instance.fileSize, + 'videoFileName': instance.videoFileName, + 'introOutSkipModel': instance.introOutSkipModel, + 'fTrickPlayModel': instance.fTrickPlayModel, + 'fImages': instance.fImages, + 'fChapters': instance.fChapters, + 'subtitles': instance.subtitles, + 'userData': _$JsonConverterToJson( + instance.userData, const UserDataJsonSerializer().toJson), + }; + +Value? _$JsonConverterFromJson( + Object? json, + Value? Function(Json json) fromJson, +) => + json == null ? null : fromJson(json as Json); + +Json? _$JsonConverterToJson( + Value? value, + Json? Function(Value value) toJson, +) => + value == null ? null : toJson(value); diff --git a/lib/models/syncing/sync_settings_model.dart b/lib/models/syncing/sync_settings_model.dart new file mode 100644 index 0000000..880c24a --- /dev/null +++ b/lib/models/syncing/sync_settings_model.dart @@ -0,0 +1,16 @@ +// ignore_for_file: invalid_annotation_target + +import 'package:freezed_annotation/freezed_annotation.dart'; + +import 'package:fladder/models/syncing/sync_item.dart'; + +part 'sync_settings_model.freezed.dart'; + +@Freezed(toJson: false, fromJson: false) +class SyncSettingsModel with _$SyncSettingsModel { + const SyncSettingsModel._(); + + factory SyncSettingsModel({ + @Default([]) List items, + }) = _SyncSettignsModel; +} diff --git a/lib/models/syncing/sync_settings_model.freezed.dart b/lib/models/syncing/sync_settings_model.freezed.dart new file mode 100644 index 0000000..2806646 --- /dev/null +++ b/lib/models/syncing/sync_settings_model.freezed.dart @@ -0,0 +1,144 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'sync_settings_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$SyncSettingsModel { + List get items => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $SyncSettingsModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SyncSettingsModelCopyWith<$Res> { + factory $SyncSettingsModelCopyWith( + SyncSettingsModel value, $Res Function(SyncSettingsModel) then) = + _$SyncSettingsModelCopyWithImpl<$Res, SyncSettingsModel>; + @useResult + $Res call({List items}); +} + +/// @nodoc +class _$SyncSettingsModelCopyWithImpl<$Res, $Val extends SyncSettingsModel> + implements $SyncSettingsModelCopyWith<$Res> { + _$SyncSettingsModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? items = null, + }) { + return _then(_value.copyWith( + items: null == items + ? _value.items + : items // ignore: cast_nullable_to_non_nullable + as List, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$SyncSettignsModelImplCopyWith<$Res> + implements $SyncSettingsModelCopyWith<$Res> { + factory _$$SyncSettignsModelImplCopyWith(_$SyncSettignsModelImpl value, + $Res Function(_$SyncSettignsModelImpl) then) = + __$$SyncSettignsModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({List items}); +} + +/// @nodoc +class __$$SyncSettignsModelImplCopyWithImpl<$Res> + extends _$SyncSettingsModelCopyWithImpl<$Res, _$SyncSettignsModelImpl> + implements _$$SyncSettignsModelImplCopyWith<$Res> { + __$$SyncSettignsModelImplCopyWithImpl(_$SyncSettignsModelImpl _value, + $Res Function(_$SyncSettignsModelImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? items = null, + }) { + return _then(_$SyncSettignsModelImpl( + items: null == items + ? _value._items + : items // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc + +class _$SyncSettignsModelImpl extends _SyncSettignsModel { + _$SyncSettignsModelImpl({final List items = const []}) + : _items = items, + super._(); + + final List _items; + @override + @JsonKey() + List get items { + if (_items is EqualUnmodifiableListView) return _items; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_items); + } + + @override + String toString() { + return 'SyncSettingsModel(items: $items)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$SyncSettignsModelImpl && + const DeepCollectionEquality().equals(other._items, _items)); + } + + @override + int get hashCode => + Object.hash(runtimeType, const DeepCollectionEquality().hash(_items)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$SyncSettignsModelImplCopyWith<_$SyncSettignsModelImpl> get copyWith => + __$$SyncSettignsModelImplCopyWithImpl<_$SyncSettignsModelImpl>( + this, _$identity); +} + +abstract class _SyncSettignsModel extends SyncSettingsModel { + factory _SyncSettignsModel({final List items}) = + _$SyncSettignsModelImpl; + _SyncSettignsModel._() : super._(); + + @override + List get items; + @override + @JsonKey(ignore: true) + _$$SyncSettignsModelImplCopyWith<_$SyncSettignsModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/trickplayer_model.dart b/lib/models/trickplayer_model.dart new file mode 100644 index 0000000..c565d1d --- /dev/null +++ b/lib/models/trickplayer_model.dart @@ -0,0 +1,177 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +import 'dart:convert'; + +import 'package:flutter/foundation.dart'; + +import 'package:fladder/models/items/chapters_model.dart'; + +class Bif { + final String version; + final List widthResolutions; + Bif({ + required this.version, + required this.widthResolutions, + }); + + Bif copyWith({ + String? version, + List? widthResolutions, + }) { + return Bif( + version: version ?? this.version, + widthResolutions: widthResolutions ?? this.widthResolutions, + ); + } + + Map toMap() { + return { + 'Version': version, + 'WidthResolutions': widthResolutions, + }; + } + + factory Bif.fromMap(Map map) { + return Bif( + version: (map['Version'] ?? '') as String, + widthResolutions: List.from((map['WidthResolutions'] ?? const []) as List), + ); + } + + String toJson() => json.encode(toMap()); + + factory Bif.fromJson(String source) => Bif.fromMap(json.decode(source) as Map); + + @override + String toString() => 'Bif(version: $version, widthResolutions: $widthResolutions)'; + + @override + bool operator ==(covariant Bif other) { + if (identical(this, other)) return true; + + return other.version == version && listEquals(other.widthResolutions, widthResolutions); + } + + @override + int get hashCode => version.hashCode ^ widthResolutions.hashCode; +} + +class BifUtil { + static List bifMagicNumbers = [0x89, 0x42, 0x49, 0x46, 0x0D, 0x0A, 0x1A, 0x0A]; + static const int supportedBifVersion = 0; + + static Future trickPlayDecode(Uint8List array, int width) async { + Indexed8Array data = Indexed8Array(array); + + for (int b in bifMagicNumbers) { + if (data.read() != b) { + print('Attempted to read invalid bif file.'); + return null; + } + } + + int bifVersion = data.readInt32(); + if (bifVersion != supportedBifVersion) { + print('Client only supports BIF v$supportedBifVersion but file is v$bifVersion'); + return null; + } + + print('BIF version: $bifVersion'); + + int bifImgCount = data.readInt32(); + if (bifImgCount <= 0) { + print('BIF file contains no images.'); + return null; + } + + print('BIF image count: $bifImgCount'); + + int timestampMultiplier = data.readInt32(); + if (timestampMultiplier == 0) timestampMultiplier = 1000; + + data.addPosition(44); // Reserved + + List bifIndex = []; + for (int i = 0; i < bifImgCount; i++) { + bifIndex.add(BifIndexEntry(data.readInt32(), data.readInt32())); + } + + List bifImages = []; + for (int i = 0; i < bifIndex.length; i++) { + BifIndexEntry indexEntry = bifIndex[i]; + int timestamp = indexEntry.timestamp; + int offset = indexEntry.offset; + int nextOffset = i + 1 < bifIndex.length ? bifIndex[i + 1].offset : data.limit(); + + Uint8List imageBytes = Uint8List.sublistView(Uint8List.view(data.array.buffer, offset, nextOffset - offset)); + + bifImages.add( + Chapter( + name: "", + imageUrl: "", + imageData: imageBytes, + startPosition: Duration(milliseconds: timestamp * timestampMultiplier), + ), + ); + } + return BifData(bifVersion, bifImgCount, bifImages, width); + } +} + +class Indexed8Array { + Uint8List array; + int readIndex; + + Indexed8Array(Uint8List byteArray) + : array = byteArray, + readIndex = 0; + + int read() { + return array[readIndex++]; + } + + void addPosition(int amount) { + readIndex += amount; + } + + int readInt32() { + int b1 = read() & 0xFF; + int b2 = read() & 0xFF; + int b3 = read() & 0xFF; + int b4 = read() & 0xFF; + + return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24); + } + + Uint8List getByteArray() { + return array; + } + + int limit() { + return array.length; + } + + Endian order() { + return Endian.big; + } +} + +class BifIndexEntry { + int timestamp; + int offset; + + BifIndexEntry(this.timestamp, this.offset); +} + +class BifData { + int bifVersion; + int bifImgCount; + List chapters; + int width; + + BifData( + this.bifVersion, + this.bifImgCount, + this.chapters, + this.width, + ); +} diff --git a/lib/models/video_stream_model.dart b/lib/models/video_stream_model.dart new file mode 100644 index 0000000..e121e76 --- /dev/null +++ b/lib/models/video_stream_model.dart @@ -0,0 +1,208 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +import 'package:collection/collection.dart'; +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/items/item_stream_model.dart'; +import 'package:fladder/models/syncing/sync_item.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:media_kit/media_kit.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/items/chapters_model.dart'; +import 'package:fladder/models/items/intro_skip_model.dart'; +import 'package:fladder/models/items/media_streams_model.dart'; +import 'package:fladder/providers/user_provider.dart'; + +enum PlaybackType { + directStream, + offline, + transcode; + + IconData get icon => switch (this) { + PlaybackType.offline => IconsaxOutline.cloud, + PlaybackType.directStream => IconsaxOutline.arrow_right_1, + PlaybackType.transcode => IconsaxOutline.convert, + }; + + String get name { + switch (this) { + case PlaybackType.directStream: + return "Direct"; + case PlaybackType.offline: + return "Offline"; + case PlaybackType.transcode: + return "Transcoding"; + } + } +} + +class VideoPlayback { + final List queue; + final ItemStreamModel? currentItem; + final SyncedItem? currentSyncedItem; + final VideoStream? currentStream; + VideoPlayback({ + required this.queue, + this.currentItem, + this.currentSyncedItem, + this.currentStream, + }); + + List get subStreams => currentStream?.mediaStreamsModel?.subStreams ?? []; + List get audioStreams => currentStream?.mediaStreamsModel?.audioStreams ?? []; + + ItemStreamModel? get previousVideo { + final int currentIndex = queue.indexWhere((element) => element.id == currentItem?.id); + if (currentIndex > 0) { + return queue[currentIndex - 1]; + } + return null; + } + + ItemStreamModel? get nextVideo { + final int currentIndex = queue.indexWhere((element) => element.id == currentItem?.id); + if ((currentIndex + 1) < queue.length) { + return queue[currentIndex + 1]; + } + return null; + } + + VideoPlayback copyWith({ + List? queue, + ItemStreamModel? currentItem, + SyncedItem? currentSyncedItem, + VideoStream? currentStream, + Map? audioMappings, + Map? subMappings, + }) { + return VideoPlayback( + queue: queue ?? this.queue, + currentItem: currentItem ?? this.currentItem, + currentSyncedItem: currentSyncedItem ?? this.currentSyncedItem, + currentStream: currentStream ?? this.currentStream, + ); + } + + VideoPlayback clear() { + return VideoPlayback( + queue: queue, + currentItem: null, + currentStream: null, + ); + } +} + +class VideoStream { + final String id; + final Duration? currentPosition; + final PlaybackType playbackType; + final String playbackUrl; + final String playSessionId; + final List? chapters; + final List? trickPlay; + final IntroSkipModel? introSkipModel; + final int? audioStreamIndex; + final int? subtitleStreamIndex; + final MediaStreamsModel? mediaStreamsModel; + + AudioStreamModel? get currentAudioStream { + if (audioStreamIndex == -1) { + return null; + } + return mediaStreamsModel?.audioStreams.firstWhereOrNull( + (element) => element.index == (audioStreamIndex ?? mediaStreamsModel?.currentAudioStream ?? 0)); + } + + SubStreamModel? get currentSubStream { + if (subtitleStreamIndex == -1) { + return null; + } + return mediaStreamsModel?.subStreams.firstWhereOrNull( + (element) => element.index == (subtitleStreamIndex ?? mediaStreamsModel?.currentSubStream ?? 0)); + } + + VideoStream({ + required this.id, + this.currentPosition, + required this.playbackType, + required this.playbackUrl, + required this.playSessionId, + this.chapters, + this.trickPlay, + this.introSkipModel, + this.audioStreamIndex, + this.subtitleStreamIndex, + this.mediaStreamsModel, + }); + + VideoStream copyWith({ + String? id, + Duration? currentPosition, + PlaybackType? playbackType, + String? playbackUrl, + String? playSessionId, + List? chapters, + List? trickPlay, + IntroSkipModel? introSkipModel, + int? audioStreamIndex, + int? subtitleStreamIndex, + MediaStreamsModel? mediaStreamsModel, + }) { + return VideoStream( + id: id ?? this.id, + currentPosition: currentPosition ?? this.currentPosition, + playbackType: playbackType ?? this.playbackType, + playbackUrl: playbackUrl ?? this.playbackUrl, + playSessionId: playSessionId ?? this.playSessionId, + chapters: chapters ?? this.chapters, + trickPlay: trickPlay ?? this.trickPlay, + introSkipModel: introSkipModel ?? this.introSkipModel, + audioStreamIndex: audioStreamIndex ?? this.audioStreamIndex, + subtitleStreamIndex: subtitleStreamIndex ?? this.subtitleStreamIndex, + mediaStreamsModel: mediaStreamsModel ?? this.mediaStreamsModel, + ); + } + + static VideoStream? fromPlayBackInfo(PlaybackInfoResponse info, Ref ref) { + final mediaSource = info.mediaSources?.first; + var playType = PlaybackType.directStream; + + String? playbackUrl; + + if (mediaSource == null) return null; + + if (mediaSource.supportsDirectStream ?? false) { + final Map directOptions = { + 'Static': 'true', + 'mediaSourceId': mediaSource.id, + 'api_key': ref.read(userProvider)?.credentials.token, + }; + + if (mediaSource.eTag != null) { + directOptions['Tag'] = mediaSource.eTag; + } + + if (mediaSource.liveStreamId != null) { + directOptions['LiveStreamId'] = mediaSource.liveStreamId; + } + + final params = Uri(queryParameters: directOptions).query; + + playbackUrl = '${ref.read(userProvider)?.server ?? ""}/Videos/${mediaSource.id}/stream?$params'; + } else if ((mediaSource.supportsTranscoding ?? false) && mediaSource.transcodingUrl != null) { + playbackUrl = "${ref.read(userProvider)?.server ?? ""}${mediaSource.transcodingUrl ?? ""}"; + playType = PlaybackType.transcode; + } + + if (playbackUrl == null) return null; + + return VideoStream( + id: info.mediaSources?.first.id ?? "", + playbackUrl: playbackUrl, + playbackType: playType, + playSessionId: info.playSessionId ?? "", + mediaStreamsModel: MediaStreamsModel.fromMediaStreamsList( + info.mediaSources?.firstOrNull, info.mediaSources?.firstOrNull?.mediaStreams ?? [], ref), + ); + } +} diff --git a/lib/models/view_model.dart b/lib/models/view_model.dart new file mode 100644 index 0000000..537a294 --- /dev/null +++ b/lib/models/view_model.dart @@ -0,0 +1,97 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first + +import 'package:collection/collection.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart' as dto; +import 'package:fladder/models/item_base_model.dart'; + +class ViewModel { + final String name; + final String id; + final String serverId; + final DateTime dateCreated; + final bool canDelete; + final bool canDownload; + final String parentId; + final CollectionType collectionType; + final dto.PlayAccess playAccess; + final List recentlyAdded; + final int childCount; + ViewModel({ + required this.name, + required this.id, + required this.serverId, + required this.dateCreated, + required this.canDelete, + required this.canDownload, + required this.parentId, + required this.collectionType, + required this.playAccess, + required this.recentlyAdded, + required this.childCount, + }); + + ViewModel copyWith({ + String? name, + String? id, + String? serverId, + DateTime? dateCreated, + bool? canDelete, + bool? canDownload, + String? parentId, + CollectionType? collectionType, + dto.PlayAccess? playAccess, + List? recentlyAdded, + int? childCount, + }) { + return ViewModel( + name: name ?? this.name, + id: id ?? this.id, + serverId: serverId ?? this.serverId, + dateCreated: dateCreated ?? this.dateCreated, + canDelete: canDelete ?? this.canDelete, + canDownload: canDownload ?? this.canDownload, + parentId: parentId ?? this.parentId, + collectionType: collectionType ?? this.collectionType, + playAccess: playAccess ?? this.playAccess, + recentlyAdded: recentlyAdded ?? this.recentlyAdded, + childCount: childCount ?? this.childCount, + ); + } + + factory ViewModel.fromBodyDto(dto.BaseItemDto item, Ref ref) { + return ViewModel( + name: item.name ?? "", + id: item.id ?? "", + serverId: item.serverId ?? "", + dateCreated: item.dateCreated ?? DateTime.now(), + canDelete: item.canDelete ?? false, + canDownload: item.canDownload ?? false, + parentId: item.parentId ?? "", + recentlyAdded: [], + collectionType: CollectionType.values + .firstWhereOrNull((element) => element.name.toLowerCase() == item.collectionType?.value?.toLowerCase()) ?? + CollectionType.movies, + playAccess: item.playAccess ?? PlayAccess.none, + childCount: item.childCount ?? 0, + ); + } + + @override + bool operator ==(covariant ViewModel other) { + if (identical(this, other)) return true; + return other.id == id && other.serverId == serverId; + } + + @override + int get hashCode { + return id.hashCode ^ serverId.hashCode; + } + + @override + String toString() { + return 'ViewModel(name: $name, id: $id, serverId: $serverId, dateCreated: $dateCreated, canDelete: $canDelete, canDownload: $canDownload, parentId: $parentId, collectionType: $collectionType, playAccess: $playAccess, recentlyAdded: $recentlyAdded, childCount: $childCount)'; + } +} diff --git a/lib/models/views_model.dart b/lib/models/views_model.dart new file mode 100644 index 0000000..ffd0aac --- /dev/null +++ b/lib/models/views_model.dart @@ -0,0 +1,24 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +import 'package:fladder/models/view_model.dart'; + +class ViewsModel { + final bool loading; + final List views; + final List dashboardViews; + ViewsModel({ + this.loading = false, + this.views = const [], + this.dashboardViews = const [], + }); + + ViewsModel copyWith({ + bool? loading, + List? views, + List? dashboardViews, + }) { + return ViewsModel( + loading: loading ?? this.loading, + views: views ?? this.views, + dashboardViews: dashboardViews ?? this.dashboardViews); + } +} diff --git a/lib/profiles/default_profile.dart b/lib/profiles/default_profile.dart new file mode 100644 index 0000000..60a34e6 --- /dev/null +++ b/lib/profiles/default_profile.dart @@ -0,0 +1,35 @@ +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/profiles/web_profile.dart'; +import 'package:flutter/foundation.dart'; + +const DeviceProfile defaultProfile = kIsWeb + ? webProfile + : DeviceProfile( + maxStreamingBitrate: 120000000, + maxStaticBitrate: 120000000, + musicStreamingTranscodingBitrate: 384000, + directPlayProfiles: [ + DirectPlayProfile( + type: DlnaProfileType.video, + ), + DirectPlayProfile( + type: DlnaProfileType.audio, + ) + ], + transcodingProfiles: [ + TranscodingProfile( + audioCodec: 'aac,mp3,mp2', + container: 'ts', + maxAudioChannels: '2', + protocol: MediaStreamProtocol.hls, + type: DlnaProfileType.video, + videoCodec: 'h264', + ), + ], + containerProfiles: [], + subtitleProfiles: [ + SubtitleProfile(format: 'vtt', method: SubtitleDeliveryMethod.$external), + SubtitleProfile(format: 'ass', method: SubtitleDeliveryMethod.$external), + SubtitleProfile(format: 'ssa', method: SubtitleDeliveryMethod.$external), + ], + ); diff --git a/lib/profiles/web_profile.dart b/lib/profiles/web_profile.dart new file mode 100644 index 0000000..4617dd1 --- /dev/null +++ b/lib/profiles/web_profile.dart @@ -0,0 +1,269 @@ +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; + +const DeviceProfile webProfile = DeviceProfile( + maxStreamingBitrate: 120000000, + maxStaticBitrate: 100000000, + musicStreamingTranscodingBitrate: 384000, + directPlayProfiles: [ + DirectPlayProfile( + container: 'mkv,webm', + type: DlnaProfileType.video, + videoCodec: 'h264,hevc,vp8,vp9,av1', + audioCodec: 'vorbis,opus,aac,eac3', + ), + DirectPlayProfile( + container: 'mp4,m4v', + type: DlnaProfileType.video, + videoCodec: 'h264,hevc,vp8,vp9,av1', + audioCodec: 'aac,mp3,mp2,opus,flac,vorbis', + ), + DirectPlayProfile( + container: 'mov', + type: DlnaProfileType.video, + videoCodec: 'h264', + audioCodec: 'aac,mp3,mp2,opus,flac,vorbis', + ), + DirectPlayProfile(container: 'opus', type: DlnaProfileType.audio), + DirectPlayProfile(container: 'webm', audioCodec: 'opus', type: DlnaProfileType.audio), + DirectPlayProfile(container: 'mp3', type: DlnaProfileType.audio), + DirectPlayProfile(container: 'aac', type: DlnaProfileType.audio), + DirectPlayProfile(container: 'm4a', audioCodec: 'aac', type: DlnaProfileType.audio), + DirectPlayProfile(container: 'm4b', audioCodec: 'aac', type: DlnaProfileType.audio), + DirectPlayProfile(container: 'flac', type: DlnaProfileType.audio), + DirectPlayProfile(container: 'webma', type: DlnaProfileType.audio), + DirectPlayProfile(container: 'webm', audioCodec: 'webma', type: DlnaProfileType.audio), + DirectPlayProfile(container: 'wav', type: DlnaProfileType.audio), + DirectPlayProfile(container: 'ogg', type: DlnaProfileType.audio), + DirectPlayProfile( + container: 'hls', + type: DlnaProfileType.video, + videoCodec: 'h264', + audioCodec: 'aac,mp3,mp2', + ), + ], + transcodingProfiles: [ + TranscodingProfile( + container: 'ts', + type: DlnaProfileType.audio, + audioCodec: 'aac', + context: EncodingContext.streaming, + protocol: MediaStreamProtocol.hls, + maxAudioChannels: '2', + minSegments: 1, + breakOnNonKeyFrames: true, + ), + TranscodingProfile( + container: 'aac', + type: DlnaProfileType.audio, + audioCodec: 'aac', + context: EncodingContext.streaming, + protocol: MediaStreamProtocol.http, + maxAudioChannels: '2', + ), + TranscodingProfile( + container: 'mp3', + type: DlnaProfileType.audio, + audioCodec: 'mp3', + context: EncodingContext.streaming, + protocol: MediaStreamProtocol.http, + maxAudioChannels: '2', + ), + TranscodingProfile( + container: 'opus', + type: DlnaProfileType.audio, + audioCodec: 'opus', + context: EncodingContext.streaming, + protocol: MediaStreamProtocol.http, + maxAudioChannels: '2', + ), + TranscodingProfile( + container: 'wav', + type: DlnaProfileType.audio, + audioCodec: 'wav', + context: EncodingContext.streaming, + protocol: MediaStreamProtocol.http, + maxAudioChannels: '2', + ), + TranscodingProfile( + container: 'opus', + type: DlnaProfileType.audio, + audioCodec: 'opus', + context: EncodingContext.$static, + protocol: MediaStreamProtocol.http, + maxAudioChannels: '2', + ), + TranscodingProfile( + container: 'mp3', + type: DlnaProfileType.audio, + audioCodec: 'mp3', + context: EncodingContext.$static, + protocol: MediaStreamProtocol.http, + maxAudioChannels: '2', + ), + TranscodingProfile( + container: 'aac', + type: DlnaProfileType.audio, + audioCodec: 'aac', + context: EncodingContext.$static, + protocol: MediaStreamProtocol.http, + maxAudioChannels: '2', + ), + TranscodingProfile( + container: 'wav', + type: DlnaProfileType.audio, + audioCodec: 'wav', + context: EncodingContext.$static, + protocol: MediaStreamProtocol.http, + maxAudioChannels: '2', + ), + TranscodingProfile( + container: 'ts', + type: DlnaProfileType.video, + audioCodec: 'aac,mp3,mp2', + videoCodec: 'h264', + context: EncodingContext.streaming, + protocol: MediaStreamProtocol.hls, + maxAudioChannels: '2', + minSegments: 1, + breakOnNonKeyFrames: true, + ), + ], + containerProfiles: [], + codecProfiles: [ + CodecProfile( + type: CodecType.videoaudio, + codec: 'aac', + conditions: [ + ProfileCondition( + condition: ProfileConditionType.equals, + property: ProfileConditionValue.issecondaryaudio, + $Value: 'false', + isRequired: false, + ), + ], + ), + CodecProfile( + type: CodecType.videoaudio, + conditions: [ + ProfileCondition( + condition: ProfileConditionType.equals, + property: ProfileConditionValue.issecondaryaudio, + $Value: 'false', + isRequired: false, + ), + ], + ), + CodecProfile( + type: CodecType.video, + codec: 'h264', + conditions: [ + ProfileCondition( + condition: ProfileConditionType.notequals, + property: ProfileConditionValue.isanamorphic, + $Value: 'true', + isRequired: false, + ), + ProfileCondition( + condition: ProfileConditionType.equalsany, + property: ProfileConditionValue.videorangetype, + $Value: 'SDR', + isRequired: false, + ), + ProfileCondition( + condition: ProfileConditionType.lessthanequal, + property: ProfileConditionValue.videolevel, + $Value: '52', + isRequired: false, + ), + ProfileCondition( + condition: ProfileConditionType.notequals, + property: ProfileConditionValue.isinterlaced, + $Value: 'true', + isRequired: false, + ), + ], + ), + CodecProfile( + type: CodecType.video, + codec: 'hevc', + conditions: [ + ProfileCondition( + condition: ProfileConditionType.notequals, + property: ProfileConditionValue.isanamorphic, + $Value: 'true', + isRequired: false, + ), + ProfileCondition( + condition: ProfileConditionType.equalsany, + property: ProfileConditionValue.videoprofile, + $Value: 'main', + isRequired: false, + ), + ProfileCondition( + condition: ProfileConditionType.equalsany, + property: ProfileConditionValue.videorangetype, + $Value: 'SDR|HDR10|HLG', + isRequired: false, + ), + ProfileCondition( + condition: ProfileConditionType.lessthanequal, + property: ProfileConditionValue.videolevel, + $Value: '120', + isRequired: false, + ), + ProfileCondition( + condition: ProfileConditionType.notequals, + property: ProfileConditionValue.isinterlaced, + $Value: 'true', + isRequired: false, + ), + ], + ), + CodecProfile( + type: CodecType.video, + codec: 'vp9', + conditions: [ + ProfileCondition( + condition: ProfileConditionType.equalsany, + property: ProfileConditionValue.videorangetype, + $Value: 'SDR|HDR10|HLG', + isRequired: false, + ), + ], + ), + CodecProfile( + type: CodecType.video, + codec: 'av1', + conditions: [ + ProfileCondition( + condition: ProfileConditionType.notequals, + property: ProfileConditionValue.isanamorphic, + $Value: 'true', + isRequired: false, + ), + ProfileCondition( + condition: ProfileConditionType.equalsany, + property: ProfileConditionValue.videoprofile, + $Value: 'main', + isRequired: false, + ), + ProfileCondition( + condition: ProfileConditionType.equalsany, + property: ProfileConditionValue.videorangetype, + $Value: 'SDR|HDR10|HLG', + isRequired: false, + ), + ProfileCondition( + condition: ProfileConditionType.lessthanequal, + property: ProfileConditionValue.videolevel, + $Value: '19', + isRequired: false, + ), + ], + ), + ], + subtitleProfiles: [ + SubtitleProfile(format: 'vtt', method: SubtitleDeliveryMethod.embed), + SubtitleProfile(format: 'srt', method: SubtitleDeliveryMethod.embed), + ], +); diff --git a/lib/providers/api_provider.dart b/lib/providers/api_provider.dart new file mode 100644 index 0000000..8bd63f3 --- /dev/null +++ b/lib/providers/api_provider.dart @@ -0,0 +1,73 @@ +import 'dart:developer'; + +import 'package:chopper/chopper.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/providers/auth_provider.dart'; +import 'package:fladder/providers/service_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +part 'api_provider.g.dart'; + +@riverpod +class JellyApi extends _$JellyApi { + @override + JellyService build() { + return JellyService( + ref, + JellyfinOpenApi.create( + interceptors: [ + JellyRequest(ref), + JellyResponse(ref), + HttpLoggingInterceptor(level: Level.basic), + ], + )); + } +} + +class JellyRequest implements RequestInterceptor { + JellyRequest(this.ref); + + final Ref ref; + + @override + FutureOr onRequest(Request request) async { + if (request.method == HttpMethod.Post) { + chopperLogger.info('Performed a POST request'); + } + + final serverUrl = Uri.parse(ref.read(userProvider)?.server ?? ref.read(authProvider).tempCredentials.server); + + //Use current logged in user otherwise use the authprovider + var loginModel = ref.read(userProvider)?.credentials ?? ref.read(authProvider).tempCredentials; + var headers = loginModel.header(ref); + + return request.copyWith( + baseUri: serverUrl, + headers: request.headers..addAll(headers), + ); + } +} + +class JellyResponse implements ResponseInterceptor { + JellyResponse(this.ref); + + final Ref ref; + + @override + FutureOr> onResponse(Response response) { + if (!response.isSuccessful) { + log('x- ${response.base.statusCode} - ${response.base.reasonPhrase} - ${response.error} - ${response.base.request?.method} ${response.base.request?.url.toString()}'); + } + if (response.statusCode == 404) { + chopperLogger.severe('404 NOT FOUND'); + } + + if (response.statusCode == 401) { + // ref.read(sharedUtilityProvider).removeAccount(ref.read(userProvider)); + } + + return response; + } +} diff --git a/lib/providers/api_provider.g.dart b/lib/providers/api_provider.g.dart new file mode 100644 index 0000000..79eb549 --- /dev/null +++ b/lib/providers/api_provider.g.dart @@ -0,0 +1,25 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'api_provider.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$jellyApiHash() => r'c0cdc4127e7191523b1356e71c54c93f99020c1e'; + +/// See also [JellyApi]. +@ProviderFor(JellyApi) +final jellyApiProvider = + AutoDisposeNotifierProvider.internal( + JellyApi.new, + name: r'jellyApiProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$jellyApiHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$JellyApi = AutoDisposeNotifier; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member diff --git a/lib/providers/auth_provider.dart b/lib/providers/auth_provider.dart new file mode 100644 index 0000000..e2aec4e --- /dev/null +++ b/lib/providers/auth_provider.dart @@ -0,0 +1,123 @@ +import 'dart:developer'; + +import 'package:chopper/chopper.dart'; +import 'package:fladder/models/account_model.dart'; +import 'package:fladder/models/credentials_model.dart'; +import 'package:fladder/models/login_screen_model.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:fladder/providers/dashboard_provider.dart'; +import 'package:fladder/providers/favourites_provider.dart'; +import 'package:fladder/providers/image_provider.dart'; +import 'package:fladder/providers/service_provider.dart'; +import 'package:fladder/providers/shared_provider.dart'; +import 'package:fladder/providers/sync_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/providers/views_provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +final authProvider = StateNotifierProvider((ref) { + return AuthNotifier(ref); +}); + +class AuthNotifier extends StateNotifier { + AuthNotifier(this.ref) + : super( + LoginScreenModel( + accounts: [], + tempCredentials: CredentialsModel.createNewCredentials(), + loading: false, + ), + ); + + final Ref ref; + + late final JellyService api = ref.read(jellyApiProvider); + + Future>?> getPublicUsers() async { + try { + var response = await api.usersPublicGet(state.tempCredentials); + if (response.isSuccessful && response.body != null) { + var models = response.body ?? []; + + return response.copyWith(body: models.toList()); + } + return response.copyWith(body: []); + } catch (e) { + return null; + } + } + + Future?> authenticateByName(String userName, String password) async { + state = state.copyWith(loading: true); + clearAllProviders(); + var response = await api.usersAuthenticateByNamePost(userName: userName, password: password); + var serverResponse = await api.systemInfoPublicGet(); + CredentialsModel credentials = state.tempCredentials; + if (response.isSuccessful && (response.body?.accessToken?.isNotEmpty ?? false)) { + credentials = credentials.copyWith( + token: response.body?.accessToken ?? "", + serverId: response.body?.serverId, + serverName: serverResponse.body?.serverName ?? "", + ); + var imageUrl = ref.read(imageUtilityProvider).getUserImageUrl(response.body?.user?.id ?? ""); + AccountModel newUser = AccountModel( + name: response.body?.user?.name ?? "", + id: response.body?.user?.id ?? "", + avatar: imageUrl, + credentials: credentials, + lastUsed: DateTime.now(), + ); + ref.read(sharedUtilityProvider).addAccount(newUser); + ref.read(userProvider.notifier).userState = newUser; + state = state.copyWith(loading: false); + return Response(response.base, newUser); + } + state = state.copyWith(loading: false); + return Response(response.base, null); + } + + Future logOutUser() async { + if (ref.read(userProvider) != null) { + final response = await api.sessionsLogoutPost(); + if (response.isSuccessful) { + log('Logged out'); + } + state = state.copyWith(tempCredentials: CredentialsModel.createNewCredentials()); + await ref.read(sharedUtilityProvider).removeAccount(ref.read(userProvider)); + return response; + } + clearAllProviders(); + return null; + } + + Future switchUser() async { + clearAllProviders(); + } + + void clearAllProviders() { + ref.read(dashboardProvider.notifier).clear(); + ref.read(viewsProvider.notifier).clear(); + ref.read(favouritesProvider.notifier).clear(); + ref.read(userProvider.notifier).clear(); + ref.read(syncProvider.notifier).setup(); + } + + void setServer(String server) { + state = state.copyWith( + tempCredentials: state.tempCredentials.copyWith(server: server), + ); + } + + List getSavedAccounts() { + state = state.copyWith(accounts: ref.read(sharedUtilityProvider).getAccounts()); + return state.accounts; + } + + void reOrderUsers(int oldIndex, int newIndex) { + final accounts = state.accounts; + final original = accounts.elementAt(oldIndex); + accounts.removeAt(oldIndex); + accounts.insert(newIndex, original); + ref.read(sharedUtilityProvider).saveAccounts(accounts); + } +} diff --git a/lib/providers/book_viewer_provider.dart b/lib/providers/book_viewer_provider.dart new file mode 100644 index 0000000..e5c2812 --- /dev/null +++ b/lib/providers/book_viewer_provider.dart @@ -0,0 +1,188 @@ +import 'dart:developer'; +import 'dart:io'; + +import 'package:archive/archive_io.dart'; +import 'package:chopper/chopper.dart'; +import 'package:fladder/providers/service_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/book_model.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:path_provider/path_provider.dart'; + +class BookViewerModel { + final BookModel? book; + final bool loading; + final List pages; + final int currentPage; + BookViewerModel({ + this.book, + this.loading = false, + this.pages = const [], + this.currentPage = 0, + }); + + int get clampedCurrentPage => currentPage.clamp(0, pages.length); + + BookViewerModel copyWith({ + ValueGetter? book, + bool? loading, + List? pages, + int? currentPage, + }) { + return BookViewerModel( + book: book != null ? book.call() : this.book, + loading: loading ?? this.loading, + pages: pages ?? this.pages, + currentPage: currentPage ?? this.currentPage, + ); + } +} + +final bookViewerProvider = StateNotifierProvider((ref) { + return BookViewerNotifier(ref); +}); + +class BookViewerNotifier extends StateNotifier { + BookViewerNotifier(this.ref) : super(BookViewerModel()); + + final Ref ref; + + late Directory savedDirectory; + + late final JellyService api = ref.read(jellyApiProvider); + + Future?> fetchBook(BookModel? book) async { + final oldState = state.copyWith(); + state = state.copyWith(loading: true, book: () => book, currentPage: 0); + + //Stop and cleanup old state + await _stopPlaybackOldState(oldState); + + if (state.book == null) return null; + try { + final response = await api.itemsItemIdDownloadGet(itemId: state.book?.id); + + final bookDirectory = state.book?.id; + + String tempDir = (await getTemporaryDirectory()).path; + savedDirectory = Directory('$tempDir/$bookDirectory'); + await savedDirectory.create(); + File bookFile = File('${savedDirectory.path}/archive.book'); + await bookFile.writeAsBytes(response.bodyBytes); + + final inputStream = InputFileStream(bookFile.path); + final archive = ZipDecoder().decodeBuffer(inputStream); + + final List imagesPath = []; + for (var file in archive.files) { + //filter out files with image extension + if (file.isFile && _isImageFile(file.name)) { + final path = '${savedDirectory.path}/Pages/${file.name}'; + final outputStream = OutputFileStream('${savedDirectory.path}/Pages/${file.name}'); + file.writeContent(outputStream); + imagesPath.add(path); + outputStream.close(); + } + } + state = state.copyWith(pages: imagesPath, loading: false); + await inputStream.close(); + await bookFile.delete(); + return imagesPath; + } catch (e) { + log(e.toString()); + state = state.copyWith(loading: false); + } + return null; + } + + //Simple file checker + bool _isImageFile(String filePath) { + final imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'tiff', 'tif', 'webp']; + final fileExtension = filePath.toLowerCase().split('.').last; + return imageExtensions.contains(fileExtension); + } + + Future updatePlayback(int page) async { + if (state.book == null) return null; + if (page == state.currentPage) return null; + state = state.copyWith(currentPage: page); + return await api.sessionsPlayingStoppedPost( + body: PlaybackStopInfo( + itemId: state.book?.id, + mediaSourceId: state.book?.id, + positionTicks: state.clampedCurrentPage * 10000, + ), + ); + } + + Future _stopPlaybackOldState(BookViewerModel oldState) async { + if (oldState.book == null) return null; + + if (oldState.clampedCurrentPage < oldState.pages.length && oldState.pages.isNotEmpty) { + await ref.read(userProvider.notifier).markAsPlayed(false, oldState.book?.id ?? ""); + } + + final response = await api.sessionsPlayingStoppedPost( + body: PlaybackStopInfo( + itemId: oldState.book?.id, + mediaSourceId: oldState.book?.id, + positionTicks: oldState.clampedCurrentPage * 10000, + )); + + if (oldState.clampedCurrentPage >= oldState.pages.length && oldState.pages.isNotEmpty) { + await ref.read(userProvider.notifier).markAsPlayed(true, oldState.book?.id ?? ""); + } + + await _cleanUp(); + return response; + } + + Future stopPlayback() async { + if (state.book == null) return null; + + if (state.clampedCurrentPage < state.pages.length && state.pages.isNotEmpty) { + await ref.read(userProvider.notifier).markAsPlayed(false, state.book?.id ?? ""); + } + + final response = await api.sessionsPlayingStoppedPost( + body: PlaybackStopInfo( + itemId: state.book?.id, + mediaSourceId: state.book?.id, + positionTicks: state.clampedCurrentPage * 10000, + )); + + if (state.clampedCurrentPage >= state.pages.length && state.pages.isNotEmpty) { + await ref.read(userProvider.notifier).markAsPlayed(true, state.book?.id ?? ""); + } + + await _cleanUp(); + return response; + } + + Future _cleanUp() async { + try { + for (var i = 0; i < state.pages.length; i++) { + final file = File(state.pages[i]); + if (file.existsSync()) { + await file.delete(); + } + } + final directoryExists = await savedDirectory.exists(); + if (directoryExists) { + await savedDirectory.delete(recursive: true); + } + } catch (e) { + log(e.toString()); + } + } + + void setPage(double value) => state = state.copyWith(currentPage: value.toInt()); + + void setBook(BookModel book) => state = state.copyWith( + book: () => book, + ); +} diff --git a/lib/providers/collections_provider.dart b/lib/providers/collections_provider.dart new file mode 100644 index 0000000..c51616e --- /dev/null +++ b/lib/providers/collections_provider.dart @@ -0,0 +1,100 @@ +import 'package:chopper/chopper.dart'; +import 'package:fladder/providers/service_provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/boxset_model.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:fladder/util/map_bool_helper.dart'; + +class _CollectionSetModel { + final List items; + final Map collections; + _CollectionSetModel({ + required this.items, + required this.collections, + }); + + _CollectionSetModel copyWith({ + List? items, + Map? collections, + }) { + return _CollectionSetModel( + items: items ?? this.items, + collections: collections ?? this.collections, + ); + } +} + +final collectionsProvider = StateNotifierProvider.autoDispose((ref) { + return BoxSetNotifier(ref); +}); + +class BoxSetNotifier extends StateNotifier<_CollectionSetModel> { + BoxSetNotifier(this.ref) : super(_CollectionSetModel(items: [], collections: {})); + final Ref ref; + + late final JellyService api = ref.read(jellyApiProvider); + + Future setItems(List items) async { + state = state.copyWith(items: items); + return _init(); + } + + Future _init() async { + final collections = await api.usersUserIdItemsGet( + recursive: true, + includeItemTypes: [ + BaseItemKind.boxset, + ], + ); + + final boxsets = collections.body?.items?.map((e) => BoxSetModel.fromBaseDto(e, ref)).toList(); + + if (state.items.length == 1 && (boxsets?.length ?? 0) < 25) { + final List> itemChecks = boxsets?.map((element) async { + final itemList = await api.usersUserIdItemsGet( + parentId: element.id, + ); + final List items = (itemList.body?.items ?? []).map((e) => e.id).toList(); + return items.contains(state.items.firstOrNull?.id); + }).toList() ?? + []; + + final List results = await Future.wait(itemChecks); + + final Map boxSetContainsItemMap = Map.fromIterables(boxsets ?? [], results); + + state = state.copyWith(collections: boxSetContainsItemMap); + } else { + final Map boxSetContainsItemMap = + Map.fromIterables(boxsets ?? [], List.generate(boxsets?.length ?? 0, (index) => null)); + state = state.copyWith(collections: boxSetContainsItemMap); + } + } + + Future toggleCollection( + {required BoxSetModel boxSet, required bool value, required ItemBaseModel item}) async { + final Response response = value + ? await api.collectionsCollectionIdItemsPost(collectionId: boxSet.id, ids: [item.id]) + : await api.collectionsCollectionIdItemsDelete(collectionId: boxSet.id, ids: [item.id]); + + if (response.isSuccessful) { + state = state.copyWith(collections: state.collections.setKey(boxSet, response.isSuccessful ? value : !value)); + } + return response; + } + + Future addToCollection({required BoxSetModel boxSet, required bool add}) async => add + ? await api.collectionsCollectionIdItemsPost(collectionId: boxSet.id, ids: state.items.map((e) => e.id).toList()) + : await api.collectionsCollectionIdItemsDelete( + collectionId: boxSet.id, ids: state.items.map((e) => e.id).toList()); + + Future addToNewCollection({required String name}) async { + final result = await api.collectionsPost(name: name, ids: state.items.map((e) => e.id).toList()); + if (result.isSuccessful) { + await _init(); + } + } +} diff --git a/lib/providers/dashboard_provider.dart b/lib/providers/dashboard_provider.dart new file mode 100644 index 0000000..27209c0 --- /dev/null +++ b/lib/providers/dashboard_provider.dart @@ -0,0 +1,111 @@ +import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.dart'; +import 'package:fladder/models/home_model.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:fladder/providers/service_provider.dart'; +import 'package:fladder/providers/settings/client_settings_provider.dart'; +import 'package:fladder/providers/views_provider.dart'; +import 'package:fladder/util/list_extensions.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +final dashboardProvider = StateNotifierProvider((ref) { + return DashboardNotifier(ref); +}); + +class DashboardNotifier extends StateNotifier { + DashboardNotifier(this.ref) : super(HomeModel()); + + final Ref ref; + + late final JellyService api = ref.read(jellyApiProvider); + + Future fetchNextUpAndResume() async { + if (state.loading) return; + state = state.copyWith(loading: true); + final viewTypes = + ref.read(viewsProvider.select((value) => value.dashboardViews)).map((e) => e.collectionType).toSet().toList(); + + if (viewTypes.containsAny([CollectionType.movies, CollectionType.tvshows])) { + final resumeVideoResponse = await api.usersUserIdItemsResumeGet( + limit: 16, + fields: [ + ItemFields.parentid, + ItemFields.mediastreams, + ItemFields.mediasources, + ItemFields.candelete, + ItemFields.candownload, + ], + mediaTypes: [MediaType.video], + enableTotalRecordCount: false, + ); + + state = state.copyWith( + resumeVideo: resumeVideoResponse.body?.items?.map((e) => ItemBaseModel.fromBaseDto(e, ref)).toList(), + ); + } + + if (viewTypes.contains(CollectionType.music)) { + final resumeAudioResponse = await api.usersUserIdItemsResumeGet( + limit: 16, + fields: [ + ItemFields.parentid, + ItemFields.mediastreams, + ItemFields.mediasources, + ItemFields.candelete, + ItemFields.candownload, + ], + mediaTypes: [MediaType.audio], + enableTotalRecordCount: false, + ); + + state = state.copyWith( + resumeAudio: resumeAudioResponse.body?.items?.map((e) => ItemBaseModel.fromBaseDto(e, ref)).toList(), + ); + } + + if (viewTypes.contains(CollectionType.books)) { + final resumeBookResponse = await api.usersUserIdItemsResumeGet( + limit: 16, + fields: [ + ItemFields.parentid, + ItemFields.mediastreams, + ItemFields.mediasources, + ItemFields.candelete, + ItemFields.candownload, + ], + mediaTypes: [MediaType.book], + enableTotalRecordCount: false, + ); + + state = state.copyWith( + resumeBooks: resumeBookResponse.body?.items?.map((e) => ItemBaseModel.fromBaseDto(e, ref)).toList(), + ); + } + + final nextResponse = await api.showsNextUpGet( + limit: 16, + nextUpDateCutoff: DateTime.now() + .subtract(ref.read(clientSettingsProvider.select((value) => value.nextUpDateCutoff ?? Duration(days: 28)))), + fields: [ + ItemFields.parentid, + ItemFields.mediastreams, + ItemFields.mediasources, + ItemFields.candelete, + ItemFields.candownload, + ], + ); + + final next = nextResponse.body?.items + ?.map( + (e) => ItemBaseModel.fromBaseDto(e, ref), + ) + .toList() ?? + []; + + state = state.copyWith(nextUp: next, loading: false); + } + + void clear() { + state = HomeModel(); + } +} diff --git a/lib/providers/discovery_provider.dart b/lib/providers/discovery_provider.dart new file mode 100644 index 0000000..54fcb93 --- /dev/null +++ b/lib/providers/discovery_provider.dart @@ -0,0 +1,114 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:developer'; +import 'dart:io'; + +import 'package:dart_mappable/dart_mappable.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/providers/service_provider.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +part 'discovery_provider.g.dart'; +part 'discovery_provider.mapper.dart'; + +@riverpod +class ServerDiscovery extends _$ServerDiscovery { + final String discoveryMessage = 'Who is JellyfinServer?'; + final int discoveryPort = 7359; + final int maxServerCount = 25; + final Duration timeOut = const Duration(seconds: 5); + late final JellyService api = JellyService(ref, JellyfinOpenApi.create()); + + @override + Stream> build() async* { + final List discoveredServers = []; + final StreamController> controller = StreamController>(); + + // Bind the socket and start listening + final RawDatagramSocket socket = await RawDatagramSocket.bind(InternetAddress.anyIPv4, 0); + socket.broadcastEnabled = true; + + // Send the broadcast message + socket.send( + utf8.encode(discoveryMessage), + InternetAddress('255.255.255.255'), // Broadcast address + discoveryPort, + ); + + // log('Discovery message sent. Waiting for response...'); + + // Set a timer to close the socket after the timeout + Timer timer = Timer(timeOut, () { + // log('Timeout reached, closing socket.'); + if (discoveredServers.isEmpty) { + controller.add([]); + } + socket.close(); + controller.close(); // Close the stream controller when done + }); + + socket.listen((RawSocketEvent event) { + if (event == RawSocketEvent.read) { + Datagram? dg = socket.receive(); + if (dg != null) { + // Decode the response + String response = utf8.decode(dg.data); + Map jsonResponse = jsonDecode(response); + + final discovery = DiscoveryInfo.fromMap(jsonResponse); + + discoveredServers.add(discovery); + controller.add(List.from(discoveredServers)); // Emit the updated list + + if (discoveredServers.length >= maxServerCount) { + log('Max servers found, closing socket.'); + timer.cancel(); + socket.close(); + controller.close(); // Close the stream controller + } + } + } + }); + + yield* controller.stream; + + // Handle disposal when the provider is no longer needed + ref.onDispose(() { + timer.cancel(); + socket.close(); + controller.close(); + }); + } +} + +@MappableClass() +class DiscoveryInfo with DiscoveryInfoMappable { + @MappableField(key: 'Id') + final String id; + @MappableField(key: 'Name') + final String name; + @MappableField(key: 'Address') + final String address; + @MappableField(key: "EndpointAddress") + final String? endPointAddress; + + const DiscoveryInfo({ + required this.id, + required this.name, + required this.address, + required this.endPointAddress, + }); + + factory DiscoveryInfo.fromMap(Map map) => DiscoveryInfoMapper.fromMap(map); + factory DiscoveryInfo.fromJson(String json) => DiscoveryInfoMapper.fromJson(json); + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + + return other is DiscoveryInfo && other.id == id && other.address == address; + } + + @override + int get hashCode => id.hashCode ^ address.hashCode; +} diff --git a/lib/providers/discovery_provider.g.dart b/lib/providers/discovery_provider.g.dart new file mode 100644 index 0000000..128468b --- /dev/null +++ b/lib/providers/discovery_provider.g.dart @@ -0,0 +1,26 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'discovery_provider.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$serverDiscoveryHash() => r'f299dab33f48950f0bd91afab1f831fd6e351923'; + +/// See also [ServerDiscovery]. +@ProviderFor(ServerDiscovery) +final serverDiscoveryProvider = AutoDisposeStreamNotifierProvider< + ServerDiscovery, List>.internal( + ServerDiscovery.new, + name: r'serverDiscoveryProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$serverDiscoveryHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$ServerDiscovery = AutoDisposeStreamNotifier>; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member diff --git a/lib/providers/discovery_provider.mapper.dart b/lib/providers/discovery_provider.mapper.dart new file mode 100644 index 0000000..1d25071 --- /dev/null +++ b/lib/providers/discovery_provider.mapper.dart @@ -0,0 +1,130 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member +// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter + +part of 'discovery_provider.dart'; + +class DiscoveryInfoMapper extends ClassMapperBase { + DiscoveryInfoMapper._(); + + static DiscoveryInfoMapper? _instance; + static DiscoveryInfoMapper ensureInitialized() { + if (_instance == null) { + MapperContainer.globals.use(_instance = DiscoveryInfoMapper._()); + } + return _instance!; + } + + @override + final String id = 'DiscoveryInfo'; + + static String _$id(DiscoveryInfo v) => v.id; + static const Field _f$id = + Field('id', _$id, key: 'Id'); + static String _$name(DiscoveryInfo v) => v.name; + static const Field _f$name = + Field('name', _$name, key: 'Name'); + static String _$address(DiscoveryInfo v) => v.address; + static const Field _f$address = + Field('address', _$address, key: 'Address'); + static String? _$endPointAddress(DiscoveryInfo v) => v.endPointAddress; + static const Field _f$endPointAddress = + Field('endPointAddress', _$endPointAddress, key: 'EndpointAddress'); + + @override + final MappableFields fields = const { + #id: _f$id, + #name: _f$name, + #address: _f$address, + #endPointAddress: _f$endPointAddress, + }; + @override + final bool ignoreNull = true; + + static DiscoveryInfo _instantiate(DecodingData data) { + return DiscoveryInfo( + id: data.dec(_f$id), + name: data.dec(_f$name), + address: data.dec(_f$address), + endPointAddress: data.dec(_f$endPointAddress)); + } + + @override + final Function instantiate = _instantiate; + + static DiscoveryInfo fromMap(Map map) { + return ensureInitialized().decodeMap(map); + } + + static DiscoveryInfo fromJson(String json) { + return ensureInitialized().decodeJson(json); + } +} + +mixin DiscoveryInfoMappable { + String toJson() { + return DiscoveryInfoMapper.ensureInitialized() + .encodeJson(this as DiscoveryInfo); + } + + Map toMap() { + return DiscoveryInfoMapper.ensureInitialized() + .encodeMap(this as DiscoveryInfo); + } + + DiscoveryInfoCopyWith + get copyWith => _DiscoveryInfoCopyWithImpl( + this as DiscoveryInfo, $identity, $identity); + @override + String toString() { + return DiscoveryInfoMapper.ensureInitialized() + .stringifyValue(this as DiscoveryInfo); + } +} + +extension DiscoveryInfoValueCopy<$R, $Out> + on ObjectCopyWith<$R, DiscoveryInfo, $Out> { + DiscoveryInfoCopyWith<$R, DiscoveryInfo, $Out> get $asDiscoveryInfo => + $base.as((v, t, t2) => _DiscoveryInfoCopyWithImpl(v, t, t2)); +} + +abstract class DiscoveryInfoCopyWith<$R, $In extends DiscoveryInfo, $Out> + implements ClassCopyWith<$R, $In, $Out> { + $R call({String? id, String? name, String? address, String? endPointAddress}); + DiscoveryInfoCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t); +} + +class _DiscoveryInfoCopyWithImpl<$R, $Out> + extends ClassCopyWithBase<$R, DiscoveryInfo, $Out> + implements DiscoveryInfoCopyWith<$R, DiscoveryInfo, $Out> { + _DiscoveryInfoCopyWithImpl(super.value, super.then, super.then2); + + @override + late final ClassMapperBase $mapper = + DiscoveryInfoMapper.ensureInitialized(); + @override + $R call( + {String? id, + String? name, + String? address, + Object? endPointAddress = $none}) => + $apply(FieldCopyWithData({ + if (id != null) #id: id, + if (name != null) #name: name, + if (address != null) #address: address, + if (endPointAddress != $none) #endPointAddress: endPointAddress + })); + @override + DiscoveryInfo $make(CopyWithData data) => DiscoveryInfo( + id: data.get(#id, or: $value.id), + name: data.get(#name, or: $value.name), + address: data.get(#address, or: $value.address), + endPointAddress: data.get(#endPointAddress, or: $value.endPointAddress)); + + @override + DiscoveryInfoCopyWith<$R2, DiscoveryInfo, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t) => + _DiscoveryInfoCopyWithImpl($value, $cast, t); +} diff --git a/lib/providers/edit_item_provider.dart b/lib/providers/edit_item_provider.dart new file mode 100644 index 0000000..8d679dc --- /dev/null +++ b/lib/providers/edit_item_provider.dart @@ -0,0 +1,234 @@ +import 'dart:convert'; +import 'package:chopper/chopper.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/item_editing_model.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/providers/api_provider.dart'; + +final editItemProvider = + StateNotifierProvider.autoDispose((ref) => EditItemNotifier(ref)); + +class EditItemNotifier extends StateNotifier { + EditItemNotifier(this.ref) : super(ItemEditingModel()); + + final Ref ref; + + late final api = ref.read(jellyApiProvider); + + Map? get getFields => state.editAbleFields(); + Map? get advancedFields => state.editAdvancedAbleFields(ref); + + Future fetchInformation(String id) async { + state = ItemEditingModel(); + final itemResponse = await api.usersUserIdItemsItemIdGet( + itemId: id, + ); + final itemModel = itemResponse.body; + if (itemModel == null) return; + final images = await api.itemsItemIdImagesGet(itemId: itemModel.id); + + state = state.copyWith( + item: () => itemModel, + json: () => jsonDecode(itemResponse.bodyString), + editedJson: () => jsonDecode(itemResponse.bodyString), + primary: state.primary.copyWith( + serverImages: images.body + ?.where((element) => element.imageType == ImageType.primary) + .map((e) => EditingImageModel.fromImage(e, itemModel.id, ref)) + .toList(), + ), + logo: state.logo.copyWith( + serverImages: images.body + ?.where((element) => element.imageType == ImageType.logo) + .map((e) => EditingImageModel.fromImage(e, itemModel.id, ref)) + .toList(), + ), + backdrop: state.backdrop.copyWith( + serverImages: images.body + ?.where((element) => element.imageType == ImageType.backdrop) + .map((e) => EditingImageModel.fromImage(e, itemModel.id, ref)) + .toList(), + ), + ); + final response = await api.itemsItemIdMetadataEditorGet(itemId: id); + state = state.copyWith( + editorInfo: () => response.bodyOrThrow, + ); + } + + Future?> fetchRemoteImages({ImageType type = ImageType.primary}) async { + final currentItem = state.item; + if (currentItem == null) return null; + final response = await api.itemsItemIdRemoteImagesGet( + itemId: currentItem.id, + type: type, + includeAllLanguages: state.includeAllImages, + ); + final newImages = (response.body?.images ?? []).map((e) => EditingImageModel.fromDto(e)).toList(); + switch (type) { + case ImageType.backdrop: + state = state.copyWith(backdrop: state.backdrop.copyWith(images: newImages)); + case ImageType.logo: + state = state.copyWith(logo: state.logo.copyWith(images: newImages)); + case ImageType.primary: + default: + state = state.copyWith(primary: state.primary.copyWith(images: newImages)); + } + return response; + } + + Future updateField(MapEntry field) async { + final editedJson = state.editedJson; + editedJson?.update( + field.key, + (value) => field.value, + ifAbsent: () => editedJson.addEntries({field}), + ); + + state = state.copyWith( + editedJson: () => editedJson, + ); + } + + Future resetChanged() async { + state = state.copyWith( + editedJson: () => state.json, + ); + } + + Future?> saveInformation() async { + final currentItem = state.item; + if (currentItem == null) return null; + final jsonBody = state.editedJson; + if (jsonBody == null) return null; + state = state.copyWith(saving: true); + final response = await api.itemsItemIdPost( + itemId: currentItem.id, + body: BaseItemDto.fromJson(jsonBody), + ); + await state.primary.setImage( + ImageType.primary, + uploadData: uploadImage, + uploadUrl: _setImage, + ); + await state.logo.setImage( + ImageType.logo, + uploadData: uploadImage, + uploadUrl: _setImage, + ); + + await state.backdrop.setImage( + ImageType.backdrop, + uploadData: uploadImage, + uploadUrl: _setImage, + ); + + final newItem = await api.usersUserIdItemsItemIdGet(itemId: currentItem.id); + + state = state.copyWith(saving: false); + return response.copyWith(body: newItem.body); + } + + Future?> uploadImage(EditingImageModel? imageModel) async { + final currentItem = state.item; + if (currentItem == null || imageModel == null) return null; + final response = await api.itemIdImagesImageTypePost( + imageModel.type, + currentItem.id, + imageModel.imageData!, + ); + return response; + } + + Future?> _setImage(EditingImageModel? imageModel) async { + final currentItem = state.item; + if (currentItem == null) return null; + if (imageModel == null) return null; + return await api.itemsItemIdRemoteImagesDownloadPost( + itemId: state.item?.id, + type: imageModel.type, + imageUrl: imageModel.url, + ); + } + + void selectImage(ImageType type, EditingImageModel? image) { + switch (type) { + case ImageType.primary: + state = state.copyWith( + primary: state.primary.copyWith(selected: () => state.primary.selected == image ? null : image)); + case ImageType.logo: + state = state.copyWith(logo: state.logo.copyWith(selected: () => state.logo.selected == image ? null : image)); + default: + if (image == null) return; + state = state.copyWith( + backdrop: state.backdrop.copyWith( + selection: state.backdrop.selection.contains(image) + ? (List.of(state.backdrop.selection)..remove(image)) + : [...state.backdrop.selection, image], + ), + ); + return; + } + } + + void setIncludeImages(bool value) => state = state.copyWith(includeAllImages: value); + + void addCustomImages(ImageType type, Iterable list) { + switch (type) { + case ImageType.primary: + state = state.copyWith( + primary: state.primary.copyWith( + customImages: [...state.primary.customImages, ...list], + selected: () => list.firstOrNull, + ), + ); + return; + case ImageType.logo: + state = state.copyWith( + logo: state.logo.copyWith( + customImages: [...state.logo.customImages, ...list], + selected: () => list.firstOrNull, + ), + ); + return; + case ImageType.backdrop: + state = state.copyWith( + backdrop: state.backdrop.copyWith( + customImages: [...state.backdrop.customImages, ...list], + selection: [...state.backdrop.selection, ...list]), + ); + default: + return; + } + } + + Future?> deleteImage(ImageType type, EditingImageModel image) async { + final currentItem = state.item; + if (currentItem == null) return null; + final response = await api.itemsItemIdImagesImageTypeDelete( + itemId: state.item?.id, + imageType: type, + imageIndex: image.index, + ); + switch (type) { + case ImageType.primary: + state = state.copyWith( + primary: state.primary + .copyWith(serverImages: state.primary.serverImages..removeWhere((element) => element == image)), + ); + case ImageType.logo: + state = state.copyWith( + logo: state.logo.copyWith(serverImages: state.logo.serverImages..removeWhere((element) => element == image)), + ); + case ImageType.backdrop: + state = state.copyWith( + backdrop: state.backdrop + .copyWith(serverImages: state.backdrop.serverImages..removeWhere((element) => element == image)), + ); + default: + } + return response; + } +} diff --git a/lib/providers/favourites_provider.dart b/lib/providers/favourites_provider.dart new file mode 100644 index 0000000..d948396 --- /dev/null +++ b/lib/providers/favourites_provider.dart @@ -0,0 +1,81 @@ +import 'package:chopper/chopper.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/favourites_model.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/view_model.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:fladder/providers/views_provider.dart'; +import 'package:fladder/util/item_base_model/item_base_model_extensions.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +final favouritesProvider = StateNotifierProvider((ref) { + return FavouritesNotifier(ref); +}); + +class FavouritesNotifier extends StateNotifier { + FavouritesNotifier(this.ref) : super(FavouritesModel()); + + final Ref ref; + + late final api = ref.read(jellyApiProvider); + + Future fetchFavourites() async { + if (state.loading) return; + + state = state.copyWith(loading: true); + await _fetchMoviesAndSeries(); + await _fetchPeople(); + state = state.copyWith(loading: false); + } + + Future _fetchMoviesAndSeries() async { + final views = ref.read(viewsProvider); + + final mappedList = await Future.wait(views.dashboardViews.map((viewModel) => _loadLibrary(viewModel: viewModel))); + + state = state.copyWith( + favourites: (mappedList + .expand((innerList) => innerList ?? []) + .where((item) => item != null) + .cast() + .toList()) + .groupedItems); + } + + Future?> _loadLibrary({ViewModel? viewModel}) async { + final response = await api.itemsGet( + parentId: viewModel?.id, + isFavorite: true, + limit: 10, + sortOrder: [SortOrder.ascending], + sortBy: [ItemSortBy.seriessortname, ItemSortBy.sortname], + ); + final response2 = await api.itemsGet( + parentId: viewModel?.id, + isFavorite: true, + recursive: true, + limit: 10, + includeItemTypes: [BaseItemKind.photo, BaseItemKind.episode, BaseItemKind.video, BaseItemKind.collectionfolder], + sortOrder: [SortOrder.ascending], + sortBy: [ItemSortBy.seriessortname, ItemSortBy.sortname], + ); + return [...?response.body?.items, ...?response2.body?.items]; + } + + Future>?> _fetchPeople() async { + final response = await api.personsGet( + limit: 20, + isFavorite: true, + ); + state = state.copyWith(people: response.body ?? []); + return response; + } + + void setSearch(String value) { + state = state.copyWith(searchQuery: value); + } + + void clear() { + state = FavouritesModel(); + } +} diff --git a/lib/providers/image_provider.dart b/lib/providers/image_provider.dart new file mode 100644 index 0000000..492d469 --- /dev/null +++ b/lib/providers/image_provider.dart @@ -0,0 +1,90 @@ +import 'package:fladder/providers/auth_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; + +const _defaultHeight = 576; +const _defaultWidth = 384; +const _defaultQuality = 96; + +final imageUtilityProvider = Provider((ref) { + return ImageNotifier(ref: ref); +}); + +class ImageNotifier { + final Ref ref; + ImageNotifier({ + required this.ref, + }); + + String get currentServerUrl { + return ref.read(userProvider)?.server ?? ref.read(authProvider).tempCredentials.server; + } + + String getUserImageUrl(String id) { + return Uri.decodeFull("$currentServerUrl/Users/$id/Images/${ImageType.primary.value}"); + } + + String getItemsImageUrl(String itemId, + {ImageType type = ImageType.primary, + int maxHeight = _defaultHeight, + int maxWidth = _defaultWidth, + int quality = _defaultQuality}) { + try { + return Uri.decodeFull( + "$currentServerUrl/Items/$itemId/Images/${type.value}?fillHeight=$maxHeight&fillWidth=$maxWidth&quality=$quality"); + } catch (e) { + return ""; + } + } + + String getItemsOrigImageUrl(String itemId, {ImageType type = ImageType.primary}) { + try { + return Uri.decodeFull("$currentServerUrl/Items/$itemId/Images/${type.value}"); + } catch (e) { + return ""; + } + } + + String getBackdropOrigImage( + String itemId, + int index, + String hash, + ) { + try { + return Uri.decodeFull("$currentServerUrl/Items/$itemId/Images/Backdrop/$index?tag=$hash"); + } catch (e) { + return ""; + } + } + + String getBackdropImage( + String itemId, + int index, + String hash, { + int maxHeight = _defaultHeight, + int maxWidth = _defaultWidth, + int quality = _defaultQuality, + }) { + try { + return Uri.decodeFull( + "$currentServerUrl/Items/$itemId/Images/Backdrop/$index?tag=$hash&fillHeight=$maxHeight&fillWidth=$maxWidth&quality=$quality"); + } catch (e) { + return ""; + } + } + + String getChapterUrl(String itemId, int index, + {ImageType type = ImageType.primary, + int maxHeight = _defaultHeight, + int maxWidth = _defaultWidth, + int quality = _defaultQuality}) { + try { + return Uri.decodeFull( + "$currentServerUrl/Items/$itemId/Images/Chapter/$index?fillHeight=$maxHeight&fillWidth=$maxWidth&quality=$quality"); + } catch (e) { + return ""; + } + } +} diff --git a/lib/providers/items/book_details_provider.dart b/lib/providers/items/book_details_provider.dart new file mode 100644 index 0000000..9a50e42 --- /dev/null +++ b/lib/providers/items/book_details_provider.dart @@ -0,0 +1,149 @@ +import 'dart:io'; + +import 'package:chopper/chopper.dart'; +import 'package:collection/collection.dart'; +import 'package:fladder/models/items/images_models.dart'; +import 'package:fladder/models/library_search/library_search_options.dart'; +import 'package:fladder/providers/service_provider.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/book_model.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/providers/api_provider.dart'; + +class BookProviderModel { + final List chapters; + final ItemBaseModel? parentModel; + BookProviderModel({ + this.chapters = const [], + this.parentModel, + }); + + BookModel? get book => chapters.firstOrNull; + + ImagesData? get cover => parentModel?.getPosters ?? book?.getPosters; + + List get allBooks { + if (chapters.isEmpty) return [book].whereNotNull().toList(); + return chapters; + } + + bool get collectionPlayed { + if (chapters.isEmpty) return book?.userData.played ?? false; + for (var i = 0; i < chapters.length; i++) { + if (!chapters[i].userData.played) { + return false; + } + } + return true; + } + + BookModel? get nextUp { + if (chapters.isEmpty) return book; + return chapters.lastWhereOrNull((element) => element.currentPage != 0) ?? + chapters.firstWhereOrNull((element) => !element.userData.played) ?? + chapters.first; + } + + BookModel? nextChapter(BookModel? currentBook) { + if (currentBook != null && chapters.isEmpty) return null; + + final currentChapter = chapters.indexOf(currentBook!); + + // Check if the current chapter is the last one + if (currentChapter == chapters.length - 1) return null; + + // Return the next chapter + return chapters[currentChapter + 1]; + } + + BookModel? previousChapter(BookModel? currentBook) { + if (currentBook != null && chapters.isEmpty) return null; + + final currentChapter = chapters.indexOf(currentBook!); + + // Check if the current chapter is the first one + if (currentChapter == 0) return null; + + // Return the previous chapter + return chapters[currentChapter - 1]; + } + + BookProviderModel copyWith({ + List? chapters, + ValueGetter? parentModel, + }) { + return BookProviderModel( + chapters: chapters ?? this.chapters, + parentModel: parentModel != null ? parentModel.call() : this.parentModel, + ); + } +} + +final bookDetailsProvider = + StateNotifierProvider.autoDispose.family((ref, id) { + return BookDetailsProviderNotifier(ref); +}); + +class BookDetailsProviderNotifier extends StateNotifier { + BookDetailsProviderNotifier(this.ref) : super(BookProviderModel()); + + final Ref ref; + + late Directory savedDirectory; + + late final JellyService api = ref.read(jellyApiProvider); + + Future fetchDetails(BookModel book) async { + state = state.copyWith( + parentModel: () => book, + ); + String bookId = state.book?.id ?? book.id; + + final response = await api.usersUserIdItemsItemIdGet(itemId: bookId); + final parentResponse = await api.usersUserIdItemsItemIdGet(itemId: response.body?.parentId); + + final parentModel = parentResponse.bodyOrThrow; + final getViews = await api.usersUserIdViewsGet(); + + //Hacky solution more false positives so good enough for now. + final parentIsView = + getViews.body?.items?.firstWhereOrNull((element) => element.name == parentResponse.body?.name) != null; + + Response? siblingsResponse; + if (!parentIsView) { + siblingsResponse = await api.itemsGet( + parentId: parentModel.id, + recursive: true, + sortBy: SortingOptions.name.toSortBy, + fields: [ + ItemFields.genres, + ItemFields.parentid, + ItemFields.tags, + ItemFields.datecreated, + ItemFields.datelastmediaadded, + ItemFields.parentid, + ItemFields.overview, + ItemFields.originaltitle, + ItemFields.primaryimageaspectratio, + ], + includeItemTypes: [ + BaseItemKind.book, + ], + ); + } else { + siblingsResponse = null; + } + + final openedBook = response.bodyOrThrow; + + state = state.copyWith( + parentModel: !parentIsView ? () => parentResponse.bodyOrThrow : null, + chapters: (siblingsResponse?.body?.items ?? [openedBook]).whereType().whereNotNull().toList(), + ); + + return response; + } +} diff --git a/lib/providers/items/episode_details_provider.dart b/lib/providers/items/episode_details_provider.dart new file mode 100644 index 0000000..c8b71ab --- /dev/null +++ b/lib/providers/items/episode_details_provider.dart @@ -0,0 +1,106 @@ +import 'package:chopper/chopper.dart'; +import 'package:collection/collection.dart'; +import 'package:fladder/providers/service_provider.dart'; +import 'package:fladder/providers/sync_provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/episode_model.dart'; +import 'package:fladder/models/items/series_model.dart'; +import 'package:fladder/providers/api_provider.dart'; + +class EpisodeDetailModel { + final SeriesModel? series; + final List episodes; + final EpisodeModel? episode; + EpisodeDetailModel({ + this.series, + this.episodes = const [], + this.episode, + }); + + EpisodeDetailModel copyWith({ + SeriesModel? series, + List? episodes, + EpisodeModel? episode, + }) { + return EpisodeDetailModel( + series: series ?? this.series, + episodes: episodes ?? this.episodes, + episode: episode ?? this.episode, + ); + } +} + +final episodeDetailsProvider = + StateNotifierProvider.autoDispose.family((ref, id) { + return EpisodeDetailsProvider(ref); +}); + +class EpisodeDetailsProvider extends StateNotifier { + EpisodeDetailsProvider(this.ref) : super(EpisodeDetailModel()); + + final Ref ref; + + late final JellyService api = ref.read(jellyApiProvider); + + Future fetchDetails(ItemBaseModel item) async { + try { + final seriesResponse = await api.usersUserIdItemsItemIdGet(itemId: item.parentBaseModel.id); + if (seriesResponse.body == null) return null; + final episodes = await api.showsSeriesIdEpisodesGet(seriesId: item.parentBaseModel.id); + + if (episodes.body == null) return null; + + final episode = (await api.usersUserIdItemsItemIdGet(itemId: item.id)).bodyOrThrow as EpisodeModel; + + state = state.copyWith( + series: seriesResponse.bodyOrThrow as SeriesModel, + episodes: EpisodeModel.episodesFromDto(episodes.bodyOrThrow.items, ref), + episode: episode, + ); + + return seriesResponse; + } catch (e) { + _tryToCreateOfflineState(item); + return null; + } + } + + void _tryToCreateOfflineState(ItemBaseModel item) { + final syncNotifier = ref.read(syncProvider.notifier); + final syncedItem = syncNotifier.getParentItem(item.id); + if (syncedItem == null) return; + final seriesModel = syncedItem.createItemModel(ref) as SeriesModel; + final episodes = ref + .read(syncProvider.notifier) + .getChildren(syncedItem) + .map( + (e) => e.createItemModel(ref) as EpisodeModel, + ) + .whereNotNull() + .toList(); + state = state.copyWith( + series: seriesModel, + episode: episodes.firstWhereOrNull((element) => element.id == item.id), + episodes: episodes, + ); + return; + } + + void setSubIndex(int index) { + state = state.copyWith( + episode: state.episode?.copyWith( + mediaStreams: state.episode?.mediaStreams.copyWith( + defaultSubStreamIndex: index, + ))); + } + + void setAudioIndex(int index) { + state = state.copyWith( + episode: state.episode?.copyWith( + mediaStreams: state.episode?.mediaStreams.copyWith( + defaultAudioStreamIndex: index, + ))); + } +} diff --git a/lib/providers/items/folder_details_provider.dart b/lib/providers/items/folder_details_provider.dart new file mode 100644 index 0000000..ca10599 --- /dev/null +++ b/lib/providers/items/folder_details_provider.dart @@ -0,0 +1,42 @@ +import 'package:chopper/chopper.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/items/folder_model.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:fladder/providers/service_provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +final folderDetailsProvider = + StateNotifierProvider.autoDispose.family((ref, id) { + return FolderDetailsNotifier(ref); +}); + +class FolderDetailsNotifier extends StateNotifier { + FolderDetailsNotifier(this.ref) : super(null); + + final Ref ref; + + late final JellyService api = ref.read(jellyApiProvider); + + Future fetchDetails(String id) async { + if (state == null) { + final folderItem = await api.usersUserIdItemsItemIdGet(itemId: id); + + if (folderItem.body != null) { + state = folderItem.bodyOrThrow as FolderModel; + } + } + + final response = await api.itemsGet( + parentId: id, + sortBy: [ItemSortBy.sortname, ItemSortBy.name], + sortOrder: [SortOrder.ascending], + fields: [ + ItemFields.primaryimageaspectratio, + ItemFields.childcount, + ], + ); + + state = state?.copyWith(items: response.body?.items.where((element) => element.childCount != 0).toList()); + return response; + } +} diff --git a/lib/providers/items/identify_provider.dart b/lib/providers/items/identify_provider.dart new file mode 100644 index 0000000..7342641 --- /dev/null +++ b/lib/providers/items/identify_provider.dart @@ -0,0 +1,132 @@ +import 'package:chopper/chopper.dart'; +import 'package:fladder/models/items/movie_model.dart'; +import 'package:fladder/models/items/series_model.dart'; +import 'package:fladder/providers/service_provider.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/providers/api_provider.dart'; + +class IdentifyModel { + final ItemBaseModel? item; + final String searchString; + final List externalIds; + final Map keys; + final List results; + final int? year; + final bool replaceAllImages; + final bool processing; + IdentifyModel({ + this.item, + this.searchString = "", + this.externalIds = const [], + this.keys = const {}, + this.results = const [], + this.year, + this.replaceAllImages = true, + this.processing = false, + }); + + Map get body => { + "SearchInfo": { + "ProviderIds": keys, + "Name": searchString, + "Year": year, + }, + "ItemId": item?.id, + }..removeWhere((key, value) => value == null); + + IdentifyModel copyWith({ + ValueGetter? item, + String? searchString, + List? externalIds, + Map? keys, + List? results, + ValueGetter? year, + bool? replaceAllImages, + bool? processing, + }) { + return IdentifyModel( + item: item != null ? item() : this.item, + searchString: searchString ?? this.searchString, + externalIds: externalIds ?? this.externalIds, + keys: keys ?? this.keys, + results: results ?? this.results, + year: year != null ? year() : this.year, + replaceAllImages: replaceAllImages ?? this.replaceAllImages, + processing: processing ?? this.processing, + ); + } +} + +final simpleProviderProvider = StateProvider((ref) { + return ""; +}); + +final identifyProvider = StateNotifierProvider.autoDispose.family((ref, id) { + return IdentifyNotifier(ref, id); +}); + +class IdentifyNotifier extends StateNotifier { + IdentifyNotifier(this.ref, this.id) : super(IdentifyModel()); + + final String id; + final Ref ref; + + late final JellyService api = ref.read(jellyApiProvider); + + Future fetchInformation() async { + state = state.copyWith(processing: true); + final item = await api.usersUserIdItemsItemIdGet(itemId: id); + final itemModel = item.bodyOrThrow; + final response = await api.itemsItemIdExternalIdInfosGet(itemId: id); + state = state.copyWith( + item: () => itemModel, + externalIds: response.body, + searchString: itemModel.name, + year: () => itemModel.overview.yearAired, + keys: {for (var element in response.body ?? []) (element as ExternalIdInfo).key ?? "": ""}, + ); + state = state.copyWith(processing: false); + } + + IdentifyModel update(IdentifyModel Function(IdentifyModel state) cb) => state = cb(state); + + void clearFields() { + state = state.copyWith( + searchString: "", + year: () => null, + keys: state.keys..updateAll((key, value) => ""), + ); + } + + void updateKey(MapEntry map) { + state = state.copyWith(keys: state.keys..update(map.key, (value) => map.value)); + } + + Future>?> remoteSearch() async { + if (state.item == null) return null; + state = state.copyWith(processing: true); + late Response> response; + switch (state.item) { + case SeriesModel _: + response = await api.itemsRemoteSearchSeriesPost(body: SeriesInfoRemoteSearchQuery.fromJson(state.body)); + case MovieModel _: + default: + response = await api.itemsRemoteSearchMoviePost(body: MovieInfoRemoteSearchQuery.fromJson(state.body)); + } + state = state.copyWith(results: response.body, processing: false); + return response; + } + + Future?> setIdentity(RemoteSearchResult result) async { + if (state.item == null) return null; + state = state.copyWith(processing: true); + final response = await api.itemsRemoteSearchApplyItemIdPost( + itemId: state.item?.id ?? "", body: RemoteSearchResult.fromJson(result.toJson())); + state = state.copyWith(processing: false); + return response; + } +} diff --git a/lib/providers/items/information_provider.dart b/lib/providers/items/information_provider.dart new file mode 100644 index 0000000..94828e1 --- /dev/null +++ b/lib/providers/items/information_provider.dart @@ -0,0 +1,47 @@ +import 'package:chopper/chopper.dart'; +import 'package:fladder/providers/service_provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/models/information_model.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/providers/api_provider.dart'; + +class InformationProviderModel { + final InformationModel? model; + final bool loading; + InformationProviderModel({ + this.model, + this.loading = false, + }); + + InformationProviderModel copyWith({ + InformationModel? model, + bool? loading, + }) { + return InformationProviderModel( + model: model ?? this.model, + loading: loading ?? this.loading, + ); + } +} + +final informationProvider = + StateNotifierProvider.autoDispose.family((ref, id) { + return InformationNotifier(ref); +}); + +class InformationNotifier extends StateNotifier { + InformationNotifier(this.ref) : super(InformationProviderModel()); + + final Ref ref; + + late final JellyService api = ref.read(jellyApiProvider); + + Future getItemInformation(ItemBaseModel item) async { + state = state.copyWith(loading: true); + final response = await api.usersUserIdItemsItemIdGetBaseItem(itemId: item.id); + await Future.delayed(const Duration(milliseconds: 250)); + state = state.copyWith(loading: false, model: InformationModel.fromResponse(response.body)); + return response; + } +} diff --git a/lib/providers/items/item_details_provider.dart b/lib/providers/items/item_details_provider.dart new file mode 100644 index 0000000..e78c067 --- /dev/null +++ b/lib/providers/items/item_details_provider.dart @@ -0,0 +1,22 @@ +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:fladder/providers/service_provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +final itemDetailsProvider = StateNotifierProvider.autoDispose((ref) { + return ItemDetailsNotifier(ref); +}); + +class ItemDetailsNotifier extends StateNotifier { + ItemDetailsNotifier(this.ref) : super(null); + + final Ref ref; + + late final JellyService api = ref.read(jellyApiProvider); + + Future fetchDetails(String itemId) async { + final response = await api.usersUserIdItemsItemIdGet(itemId: itemId); + if (response.body == null) return null; + return response.bodyOrThrow; + } +} diff --git a/lib/providers/items/movies_details_provider.dart b/lib/providers/items/movies_details_provider.dart new file mode 100644 index 0000000..a0ad764 --- /dev/null +++ b/lib/providers/items/movies_details_provider.dart @@ -0,0 +1,51 @@ +import 'package:chopper/chopper.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/movie_model.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:fladder/providers/related_provider.dart'; +import 'package:fladder/providers/service_provider.dart'; +import 'package:fladder/providers/sync_provider.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +part 'movies_details_provider.g.dart'; + +@riverpod +class MovieDetails extends _$MovieDetails { + late final JellyService api = ref.read(jellyApiProvider); + + @override + MovieModel? build(String arg) => null; + + Future fetchDetails(ItemBaseModel item) async { + try { + if (item is MovieModel && state == null) { + state = item; + } + final response = await api.usersUserIdItemsItemIdGet(itemId: item.id); + if (response.body == null) return null; + state = response.bodyOrThrow as MovieModel; + final related = await ref.read(relatedUtilityProvider).relatedContent(item.id); + state = state?.copyWith(related: related.body); + return null; + } catch (e) { + _tryToCreateOfflineState(item); + return null; + } + } + + void _tryToCreateOfflineState(ItemBaseModel item) { + final syncNotifier = ref.read(syncProvider.notifier); + final syncedItem = syncNotifier.getParentItem(item.id); + if (syncedItem == null) return; + final movieModel = syncedItem.createItemModel(ref) as MovieModel; + state = movieModel; + } + + void setSubIndex(int index) { + state = state?.copyWith(mediaStreams: state?.mediaStreams.copyWith(defaultSubStreamIndex: index)); + } + + void setAudioIndex(int index) { + state = state?.copyWith(mediaStreams: state?.mediaStreams.copyWith(defaultAudioStreamIndex: index)); + } +} diff --git a/lib/providers/items/movies_details_provider.g.dart b/lib/providers/items/movies_details_provider.g.dart new file mode 100644 index 0000000..2a01ad7 --- /dev/null +++ b/lib/providers/items/movies_details_provider.g.dart @@ -0,0 +1,174 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'movies_details_provider.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$movieDetailsHash() => r'e5ab0af7fab9eb7a8ea50a873e8875bb572bd240'; + +/// Copied from Dart SDK +class _SystemHash { + _SystemHash._(); + + static int combine(int hash, int value) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + value); + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); + return hash ^ (hash >> 6); + } + + static int finish(int hash) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); + // ignore: parameter_assignments + hash = hash ^ (hash >> 11); + return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); + } +} + +abstract class _$MovieDetails + extends BuildlessAutoDisposeNotifier { + late final String arg; + + MovieModel? build( + String arg, + ); +} + +/// See also [MovieDetails]. +@ProviderFor(MovieDetails) +const movieDetailsProvider = MovieDetailsFamily(); + +/// See also [MovieDetails]. +class MovieDetailsFamily extends Family { + /// See also [MovieDetails]. + const MovieDetailsFamily(); + + /// See also [MovieDetails]. + MovieDetailsProvider call( + String arg, + ) { + return MovieDetailsProvider( + arg, + ); + } + + @override + MovieDetailsProvider getProviderOverride( + covariant MovieDetailsProvider provider, + ) { + return call( + provider.arg, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'movieDetailsProvider'; +} + +/// See also [MovieDetails]. +class MovieDetailsProvider + extends AutoDisposeNotifierProviderImpl { + /// See also [MovieDetails]. + MovieDetailsProvider( + String arg, + ) : this._internal( + () => MovieDetails()..arg = arg, + from: movieDetailsProvider, + name: r'movieDetailsProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$movieDetailsHash, + dependencies: MovieDetailsFamily._dependencies, + allTransitiveDependencies: + MovieDetailsFamily._allTransitiveDependencies, + arg: arg, + ); + + MovieDetailsProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.arg, + }) : super.internal(); + + final String arg; + + @override + MovieModel? runNotifierBuild( + covariant MovieDetails notifier, + ) { + return notifier.build( + arg, + ); + } + + @override + Override overrideWith(MovieDetails Function() create) { + return ProviderOverride( + origin: this, + override: MovieDetailsProvider._internal( + () => create()..arg = arg, + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + arg: arg, + ), + ); + } + + @override + AutoDisposeNotifierProviderElement + createElement() { + return _MovieDetailsProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is MovieDetailsProvider && other.arg == arg; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, arg.hashCode); + + return _SystemHash.finish(hash); + } +} + +mixin MovieDetailsRef on AutoDisposeNotifierProviderRef { + /// The parameter `arg` of this provider. + String get arg; +} + +class _MovieDetailsProviderElement + extends AutoDisposeNotifierProviderElement + with MovieDetailsRef { + _MovieDetailsProviderElement(super.provider); + + @override + String get arg => (origin as MovieDetailsProvider).arg; +} +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member diff --git a/lib/providers/items/person_details_provider.dart b/lib/providers/items/person_details_provider.dart new file mode 100644 index 0000000..020954e --- /dev/null +++ b/lib/providers/items/person_details_provider.dart @@ -0,0 +1,69 @@ +import 'package:chopper/chopper.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/models/items/movie_model.dart'; +import 'package:fladder/models/items/person_model.dart'; +import 'package:fladder/models/items/series_model.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:fladder/providers/service_provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +final personDetailsProvider = + StateNotifierProvider.autoDispose.family((ref, id) { + return PersonDetailsNotifier(ref); +}); + +class PersonDetailsNotifier extends StateNotifier { + PersonDetailsNotifier(this.ref) : super(null); + + final Ref ref; + + late final JellyService api = ref.read(jellyApiProvider); + + Future fetchPerson(Person person) async { + final response = await api.usersUserIdItemsItemIdGet(itemId: person.id); + + if (response.isSuccessful && response.body != null) { + state = response.bodyOrThrow as PersonModel; + fetchMovies(); + } + + return response; + } + + Future fetchMovies() async { + final movies = await api.itemsGet( + personIds: [state?.id ?? ""], + limit: 25, + sortBy: [ItemSortBy.premieredate, ItemSortBy.communityrating, ItemSortBy.sortname, ItemSortBy.productionyear], + sortOrder: [SortOrder.descending], + recursive: true, + fields: [ + ItemFields.primaryimageaspectratio, + ], + includeItemTypes: [ + BaseItemKind.movie, + ], + ); + + final series = await api.itemsGet( + personIds: [state?.id ?? ""], + limit: 25, + sortBy: [ItemSortBy.premieredate, ItemSortBy.communityrating, ItemSortBy.sortname, ItemSortBy.productionyear], + sortOrder: [SortOrder.descending], + recursive: true, + fields: [ + ItemFields.primaryimageaspectratio, + ], + includeItemTypes: [ + BaseItemKind.series, + ], + ); + + state = state?.copyWith( + movies: movies.body?.items.whereType().toList(), + series: series.body?.items.whereType().toList(), + ); + return movies; + } +} diff --git a/lib/providers/items/photo_details_provider.dart b/lib/providers/items/photo_details_provider.dart new file mode 100644 index 0000000..568adb9 --- /dev/null +++ b/lib/providers/items/photo_details_provider.dart @@ -0,0 +1,49 @@ +import 'package:chopper/chopper.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/photos_model.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:fladder/providers/service_provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +final photoDetailsProvider = + StateNotifierProvider.autoDispose.family((ref, id) { + return PhotoDetailsNotifier(ref); +}); + +class PhotoDetailsNotifier extends StateNotifier { + PhotoDetailsNotifier(this.ref) : super(null); + + final Ref ref; + + late final JellyService api = ref.read(jellyApiProvider); + + Future fetchDetails(ItemBaseModel item) async { + String? albumId; + if (item is PhotoModel) { + albumId = item.albumId; + } else if (item is PhotoAlbumModel) { + albumId = item.id; + } + + final albumData = await api.usersUserIdItemsItemIdGet(itemId: albumId); + if (albumData.body == null) return albumData; + PhotoAlbumModel newState = albumData.bodyOrThrow as PhotoAlbumModel; + final response = await api.itemsGet( + parentId: albumId, + fields: [ItemFields.primaryimageaspectratio], + sortBy: [ItemSortBy.sortname], + includeItemTypes: [ + BaseItemKind.folder, + BaseItemKind.photoalbum, + BaseItemKind.photo, + BaseItemKind.video, + ], + sortOrder: [SortOrder.ascending], + ); + if (response.body == null) return null; + newState = newState.copyWith(photos: response.body?.items.toList()); + state = newState; + return null; + } +} diff --git a/lib/providers/items/season_details_provider.dart b/lib/providers/items/season_details_provider.dart new file mode 100644 index 0000000..2b14a67 --- /dev/null +++ b/lib/providers/items/season_details_provider.dart @@ -0,0 +1,33 @@ +import 'package:chopper/chopper.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/items/episode_model.dart'; +import 'package:fladder/models/items/season_model.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:fladder/providers/service_provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +final seasonDetailsProvider = + StateNotifierProvider.autoDispose.family((ref, id) { + return SeasonDetailsNotifier(ref); +}); + +class SeasonDetailsNotifier extends StateNotifier { + SeasonDetailsNotifier(this.ref) : super(null); + + final Ref ref; + + late final JellyService api = ref.read(jellyApiProvider); + + Future fetchDetails(String seasonId) async { + SeasonModel? newState; + + final season = await api.usersUserIdItemsItemIdGet(itemId: seasonId); + if (season.body != null) newState = season.bodyOrThrow as SeasonModel; + + final episodes = await api.showsSeriesIdEpisodesGet( + seriesId: newState?.seriesId ?? "", seasonId: seasonId, fields: [ItemFields.overview]); + newState = newState?.copyWith(episodes: EpisodeModel.episodesFromDto(episodes.body?.items, ref)); + state = newState; + return season; + } +} diff --git a/lib/providers/items/series_details_provider.dart b/lib/providers/items/series_details_provider.dart new file mode 100644 index 0000000..554161d --- /dev/null +++ b/lib/providers/items/series_details_provider.dart @@ -0,0 +1,95 @@ +import 'package:chopper/chopper.dart'; +import 'package:collection/collection.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/providers/service_provider.dart'; +import 'package:fladder/providers/sync_provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/items/episode_model.dart'; +import 'package:fladder/models/items/season_model.dart'; +import 'package:fladder/models/items/series_model.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:fladder/providers/related_provider.dart'; + +final seriesDetailsProvider = + StateNotifierProvider.autoDispose.family((ref, id) { + return SeriesDetailViewNotifier(ref); +}); + +class SeriesDetailViewNotifier extends StateNotifier { + SeriesDetailViewNotifier(this.ref) : super(null); + + final Ref ref; + + late final JellyService api = ref.read(jellyApiProvider); + + Future fetchDetails(ItemBaseModel seriesModel) async { + try { + if (seriesModel is SeriesModel) { + state = seriesModel; + } + SeriesModel? newState; + final response = await api.usersUserIdItemsItemIdGet(itemId: seriesModel.id); + if (response.body == null) { + state = seriesModel as SeriesModel; + return null; + } + newState = response.bodyOrThrow as SeriesModel; + + final seasons = await api.showsSeriesIdSeasonsGet(seriesId: seriesModel.id); + newState = newState.copyWith(seasons: SeasonModel.seasonsFromDto(seasons.body?.items, ref)); + + final episodes = await api.showsSeriesIdEpisodesGet(seriesId: seriesModel.id, fields: [ + ItemFields.mediastreams, + ItemFields.mediasources, + ItemFields.overview, + ]); + + newState = newState.copyWith( + availableEpisodes: EpisodeModel.episodesFromDto( + episodes.body?.items, + ref, + ), + ); + + final related = await ref.read(relatedUtilityProvider).relatedContent(seriesModel.id); + state = newState.copyWith(related: related.body); + return response; + } catch (e) { + _tryToCreateOfflineState(seriesModel); + return null; + } + } + + Future _tryToCreateOfflineState(ItemBaseModel series) async { + final syncNotifier = ref.read(syncProvider.notifier); + final syncedItem = syncNotifier.getSyncedItem(series); + if (syncedItem == null) return; + final seriesModel = syncedItem.createItemModel(ref) as SeriesModel; + final allChildren = syncedItem + .getNestedChildren(ref) + .map( + (e) => e.createItemModel(ref), + ) + .whereNotNull() + .toList(); + state = seriesModel.copyWith( + availableEpisodes: allChildren.whereType().toList(), + seasons: allChildren.whereType().toList(), + ); + return; + } + + void updateEpisodeInfo(EpisodeModel episode) { + final index = state?.availableEpisodes?.indexOf(episode); + + if (index != null) { + state = state?.copyWith( + availableEpisodes: state?.availableEpisodes + ?..remove(episode) + ..insert(index, episode), + ); + } + } +} diff --git a/lib/providers/library_provider.dart b/lib/providers/library_provider.dart new file mode 100644 index 0000000..c32489b --- /dev/null +++ b/lib/providers/library_provider.dart @@ -0,0 +1,174 @@ +import 'package:chopper/chopper.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/photos_model.dart'; +import 'package:fladder/models/library_model.dart'; +import 'package:fladder/models/recommended_model.dart'; +import 'package:fladder/models/view_model.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:fladder/providers/service_provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; + +bool _useFolders(ViewModel model) { + switch (model.collectionType) { + case CollectionType.boxsets: + case CollectionType.homevideos: + case CollectionType.folders: + return true; + default: + return false; + } +} + +final libraryProvider = StateNotifierProvider.autoDispose.family((ref, id) { + return LibraryNotifier(ref); +}); + +class LibraryNotifier extends StateNotifier { + LibraryNotifier(this.ref) : super(null); + + final Ref ref; + + late final JellyService api = ref.read(jellyApiProvider); + + set loading(bool value) { + state = state?.copyWith(loading: value); + } + + bool get loading => state?.loading ?? true; + + Future setupLibrary(ViewModel viewModel) async { + state ??= LibraryModel(id: viewModel.id, name: viewModel.name, loading: true, type: BaseItemKind.movie); + } + + Future loadLibrary(ViewModel viewModel) async { + final response = await api.itemsGet( + parentId: viewModel.id, + sortBy: [ItemSortBy.sortname, ItemSortBy.productionyear], + isMissing: false, + excludeItemTypes: !_useFolders(viewModel) ? [BaseItemKind.folder] : [], + fields: [ItemFields.genres, ItemFields.childcount, ItemFields.parentid], + ); + state = state?.copyWith(posters: response.body?.items); + loading = false; + return response; + } + + Future loadRecommendations(ViewModel viewModel) async { + loading = true; + //Clear recommendations because of all the copying + state = state?.copyWith(recommendations: []); + final latest = await api.usersUserIdItemsLatestGet( + parentId: viewModel.id, + limit: 14, + isPlayed: false, + imageTypeLimit: 1, + includeItemTypes: viewModel.collectionType == CollectionType.tvshows ? [BaseItemKind.episode] : null, + ); + state = state?.copyWith( + recommendations: [ + ...?state?.recommendations, + RecommendedModel( + name: "Latest", + posters: latest.body?.map((e) => ItemBaseModel.fromBaseDto(e, ref)).toList() ?? [], + type: "Latest", + ), + ], + ); + if (viewModel.collectionType == CollectionType.movies) { + final response = await api.moviesRecommendationsGet( + parentId: viewModel.id, + categoryLimit: 6, + itemLimit: 8, + fields: [ItemFields.mediasourcecount], + ); + state = state?.copyWith(recommendations: [ + ...?state?.recommendations, + ...response.body?.map( + (e) => RecommendedModel( + name: e.baselineItemName ?? "", + posters: e.items?.map((e) => ItemBaseModel.fromBaseDto(e, ref)).toList() ?? [], + type: e.recommendationType.toString(), + ), + ) ?? + [], + ]); + loading = false; + } else { + final nextUp = await api.showsNextUpGet( + parentId: viewModel.id, + limit: 14, + imageTypeLimit: 1, + fields: [ItemFields.mediasourcecount, ItemFields.primaryimageaspectratio], + ); + state = state?.copyWith(recommendations: [ + ...?state?.recommendations, + ...[ + RecommendedModel( + name: "Next up", + posters: nextUp.body?.items + ?.map( + (e) => ItemBaseModel.fromBaseDto( + e, + ref, + ), + ) + .toList() ?? + [], + type: "Latest series") + ], + ]); + loading = false; + } + } + + Future loadFavourites(ViewModel viewModel) async { + loading = true; + final response = await api.itemsGet( + parentId: viewModel.id, + isFavorite: true, + recursive: true, + ); + + state = state?.copyWith(favourites: response.body?.items); + loading = false; + return response; + } + + Future loadTimeline(ViewModel viewModel) async { + loading = true; + final response = await api.itemsGet( + parentId: viewModel.id, + recursive: true, + fields: [ItemFields.primaryimageaspectratio, ItemFields.datecreated], + sortBy: [ItemSortBy.datecreated], + sortOrder: [SortOrder.descending], + includeItemTypes: [ + BaseItemKind.photo, + BaseItemKind.video, + ], + ); + state = state?.copyWith( + timelinePhotos: response.body?.items.map((e) => e as PhotoModel).toList(), + ); + loading = false; + return response; + } + + Future loadGenres(ViewModel viewModel) async { + final genres = await api.genresGet( + sortBy: [ItemSortBy.sortname], + sortOrder: [SortOrder.ascending], + includeItemTypes: viewModel.collectionType == CollectionType.movies + ? [BaseItemKind.movie] + : [ + BaseItemKind.series, + ], + parentId: viewModel.id, + ); + state = state?.copyWith( + genres: genres.body?.items?.where((element) => element.name?.isNotEmpty ?? false).map((e) => e.name!).toList()); + return null; + } +} diff --git a/lib/providers/library_search_provider.dart b/lib/providers/library_search_provider.dart new file mode 100644 index 0000000..b9fe295 --- /dev/null +++ b/lib/providers/library_search_provider.dart @@ -0,0 +1,670 @@ +import 'dart:developer'; + +import 'package:chopper/chopper.dart'; +import 'package:collection/collection.dart'; +import 'package:fladder/models/collection_types.dart'; +import 'package:fladder/models/items/folder_model.dart'; +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/models/items/photos_model.dart'; +import 'package:fladder/models/library_search/library_search_options.dart'; +import 'package:fladder/models/playlist_model.dart'; +import 'package:fladder/providers/service_provider.dart'; +import 'package:fladder/providers/settings/client_settings_provider.dart'; +import 'package:fladder/screens/photo_viewer/photo_viewer_screen.dart'; +import 'package:fladder/screens/shared/fladder_snackbar.dart'; +import 'package:fladder/util/item_base_model/play_item_helpers.dart'; +import 'package:fladder/util/list_extensions.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/library_search/library_search_model.dart'; +import 'package:fladder/models/view_model.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/util/map_bool_helper.dart'; +import 'package:page_transition/page_transition.dart'; + +final librarySearchProvider = + StateNotifierProvider.family.autoDispose((ref, id) { + return LibrarySearchNotifier(ref); +}); + +class LibrarySearchNotifier extends StateNotifier { + LibrarySearchNotifier(this.ref) : super(LibrarySearchModel()); + + final Ref ref; + + int get pageSize => ref.read(clientSettingsProvider).libraryPageSize ?? 500; + + late final JellyService api = ref.read(jellyApiProvider); + + set loading(bool loading) => state = state.copyWith(loading: loading); + + bool loadedFilters = false; + + bool get loading => state.loading; + + Future initRefresh( + List? folderId, + String? viewModelId, + bool? favourites, + ) async { + loading = true; + state = state.resetLazyLoad(); + if (state.views.isEmpty && state.folderOverwrite.isEmpty) { + if (folderId != null) { + await loadFolders(folderId: folderId); + } else { + await loadViews(viewModelId, favourites); + } + } + + await loadFilters(); + await loadMore(init: true); + loading = false; + } + + Future loadMore({bool? init}) async { + if ((loading && init != true) || state.allDoneFetching) return; + loading = true; + + final newLastIndices = Map.from(state.lastIndices); + final newLibraryItemCounts = Map.from(state.libraryItemCounts); + final isEmpty = newLastIndices.isEmpty; + + Future handleItemLoading(String itemId, ItemBaseModel currentModel) async { + final lastIndices = newLastIndices[itemId]; + final libraryTotalCount = newLibraryItemCounts[itemId]; + if (libraryTotalCount != null && lastIndices != null && libraryTotalCount <= lastIndices) return; + + final result = currentModel is PlaylistModel + ? await _loadPlaylistItems(id: itemId, startIndex: lastIndices, limit: pageSize) + : await _loadLibrary(id: itemId, startIndex: lastIndices, limit: pageSize); + + if (result != null) { + newLibraryItemCounts[itemId] = result.totalRecordCount ?? 0; + newLastIndices[itemId] = (lastIndices ?? 0) + result.items.length; + state = state.copyWith( + posters: isEmpty ? result.items : [...state.posters, ...result.items], + lastIndices: newLastIndices, + libraryItemCounts: newLibraryItemCounts, + ); + } + } + + Future handleViewLoading() async { + final results = await Future.wait( + state.views.included.map((viewModel) async { + final lastIndices = newLastIndices[viewModel.id]; + final libraryTotalCount = newLibraryItemCounts[viewModel.id]; + if (libraryTotalCount != null && lastIndices != null && libraryTotalCount <= lastIndices) return null; + + final libraryItems = await _loadLibrary( + viewModel: viewModel, + startIndex: lastIndices, + limit: pageSize ~/ state.views.included.length, + ); + + if (libraryItems != null) { + newLibraryItemCounts[viewModel.id] = libraryItems.totalRecordCount ?? 0; + newLastIndices[viewModel.id] = (lastIndices ?? 0) + libraryItems.items.length; + } + return libraryItems; + }).whereNotNull(), + ); + + List newPosters = results.whereNotNull().expand((element) => element.items).toList(); + if (state.views.included.length > 1) { + if (state.sortingOption == SortingOptions.random) { + newPosters = newPosters.random(); + } else { + newPosters = newPosters.sorted( + (a, b) => sortItems(a, b, state.sortingOption, state.sortOrder), + ); + } + } + state = state.copyWith( + posters: isEmpty ? newPosters : [...state.posters, ...newPosters], + lastIndices: newLastIndices, + libraryItemCounts: newLibraryItemCounts, + ); + } + + if (state.folderOverwrite.isNotEmpty) { + await handleItemLoading(state.folderOverwrite.last.id, state.folderOverwrite.last); + } else if (state.views.hasEnabled) { + await handleViewLoading(); + } else { + if (state.searchQuery.isEmpty && !state.favourites) { + state = state.copyWith(posters: []); + } else { + final response = await _loadLibrary(recursive: true); + state = state.copyWith(posters: response?.items ?? []); + } + } + + loading = false; + } + + //Pas viewmodel otherwise select first + Future loadViews(String? viewModelId, bool? favourites) async { + final response = await api.usersUserIdViewsGet(includeHidden: false); + final createdViews = response.body?.items?.map((e) => ViewModel.fromBodyDto(e, ref)); + Map mappedModels = + createdViews?.isNotEmpty ?? false ? {for (var element in createdViews!) element: false} : {}; + + final selectedModel = mappedModels.keys.firstWhereOrNull((element) => element.id == viewModelId); + + state = state.copyWith( + views: selectedModel != null + ? mappedModels.setKey(mappedModels.keys.firstWhere((element) => element.id == viewModelId), true) + : mappedModels, + favourites: favourites, + ); + } + + Future loadFolders({List? folderId}) async { + final response = await api.itemsGet( + ids: folderId ?? state.folderOverwrite.map((e) => e.id).toList(), + sortBy: state.sortingOption.toSortBy, + sortOrder: [state.sortOrder.sortOrder], + fields: [ + ItemFields.parentid, + ItemFields.primaryimageaspectratio, + ], + ); + + state = state.copyWith(folderOverwrite: response.body?.items.toList()); + } + + Future loadFilters() async { + if (loadedFilters == true) return; + loadedFilters = true; + final enabledCollections = state.views.included.map((e) => e.collectionType.itemKinds).expand((element) => element); + final mappedList = await Future.wait(state.views.included.map((viewModel) => _loadFilters(viewModel))); + final studios = (await Future.wait(state.views.included.map((viewModel) => _loadStudios(viewModel)))) + .expand((element) => element) + .toSet() + .toList(); + var tempState = state.copyWith(); + final genres = mappedList + .expand((element) => element?.genres ?? []) + .whereNotNull() + .sorted((a, b) => a.name!.toLowerCase().compareTo(b.name!.toLowerCase())); + final tags = mappedList + .expand((element) => element?.tags ?? []) + .sorted((a, b) => a.toLowerCase().compareTo(b.toLowerCase())); + tempState = tempState.copyWith( + types: state.types.setAll(false).setKeys(enabledCollections, true), + genres: {for (var element in genres) element.name!: false}.replaceMap(tempState.genres), + studios: {for (var element in studios) element: false}.replaceMap(tempState.studios), + tags: {for (var element in tags) element: false}.replaceMap(tempState.tags), + ); + state = tempState; + } + + Future _loadFilters(ViewModel viewModel) async { + final response = await api.itemsFilters2Get(parentId: viewModel.id); + return response.body; + } + + Future> _loadStudios(ViewModel viewModel) async { + final response = await api.studiosGet(parentId: viewModel.id); + return response.body?.items?.map((e) => Studio(id: e.id ?? "", name: e.name ?? "")).toList() ?? []; + } + + Future _loadLibrary( + {ViewModel? viewModel, + bool? recursive, + bool? shuffle, + String? id, + int? limit, + int? startIndex, + String? searchTerm}) async { + final searchString = searchTerm ?? (state.searchQuery.isNotEmpty ? state.searchQuery : null); + final response = await api.itemsGet( + parentId: viewModel?.id ?? id, + searchTerm: searchString, + genres: state.genres.included, + tags: state.tags.included, + recursive: searchString?.isNotEmpty == true ? true : recursive ?? state.recursive, + officialRatings: state.officialRatings.included, + years: state.years.included, + isMissing: false, + limit: (limit ?? 0) > 0 ? limit : null, + startIndex: (limit ?? 0) > 0 ? startIndex : null, + collapseBoxSetItems: false, + studioIds: state.studios.included.map((e) => e.id).toList(), + sortBy: shuffle == true ? [ItemSortBy.random] : state.sortingOption.toSortBy, + sortOrder: [state.sortOrder.sortOrder], + fields: { + ItemFields.genres, + ItemFields.parentid, + ItemFields.tags, + ItemFields.datecreated, + ItemFields.datelastmediaadded, + ItemFields.overview, + ItemFields.originaltitle, + ItemFields.customrating, + ItemFields.primaryimageaspectratio, + if (viewModel?.collectionType == CollectionType.tvshows) ItemFields.childcount, + }.toList(), + filters: [ + ...state.filters.included, + if (state.favourites) ItemFilter.isfavorite, + ], + includeItemTypes: state.types.included.map((e) => e.dtoKind).toList(), + ); + return response.body; + } + + Future _loadPlaylistItems({ViewModel? viewModel, String? id, int? startIndex, int? limit}) async { + final response = await api.playlistsPlaylistIdItemsGet( + playlistId: viewModel?.id ?? id, + limit: (limit ?? 0) > 0 ? limit : null, + startIndex: (limit ?? 0) > 0 ? startIndex : null, + fields: { + ItemFields.genres, + ItemFields.parentid, + ItemFields.tags, + ItemFields.datecreated, + ItemFields.datelastmediaadded, + ItemFields.overview, + ItemFields.originaltitle, + ItemFields.customrating, + ItemFields.primaryimageaspectratio, + if (viewModel?.collectionType == CollectionType.tvshows) ItemFields.childcount, + }.toList(), + ); + return response.body; + } + + Future> fetchSuggestions(String searchTerm) async { + if (state.folderOverwrite.isNotEmpty) { + final response = await _loadLibrary(id: state.nestedCurrentItem?.id ?? "", searchTerm: searchTerm, limit: 25); + return response?.items ?? []; + } else { + if (state.views.hasEnabled) { + final mappedList = await Future.wait(state.views.included + .map((viewModel) => _loadLibrary(viewModel: viewModel, limit: 25, searchTerm: searchTerm))); + return mappedList + .expand((innerList) => innerList?.items ?? []) + .where((item) => item != null) + .cast() + .toList(); + } else { + if (searchTerm.isEmpty) { + return []; + } else { + final response = await _loadLibrary(limit: 25, recursive: true, searchTerm: searchTerm); + return response?.items ?? []; + } + } + } + } + + void setSearch(String query) { + state = state.copyWith(searchQuery: query); + ref.read(userProvider.notifier).addSearchQuery(query); + } + + void toggleFavourite() => state = state.copyWith(favourites: !state.favourites); + void toggleRecursive() => state = state.copyWith(recursive: !state.recursive); + void toggleType(FladderItemType type) => state = state.copyWith(types: state.types.toggleKey(type)); + void toggleView(ViewModel view) => state = state.copyWith(views: state.views.toggleKey(view)); + void toggleGenre(String genre) => state = state.copyWith(genres: state.genres.toggleKey(genre)); + void toggleStudio(Studio studio) => state = state.copyWith(studios: state.studios.toggleKey(studio)); + void toggleTag(String tag) => state = state.copyWith(tags: state.tags.toggleKey(tag)); + void toggleRatings(String officialRatings) => + state = state.copyWith(officialRatings: state.officialRatings.toggleKey(officialRatings)); + void toggleYears(int year) => state = state.copyWith(years: state.years.toggleKey(year)); + void toggleFilters(ItemFilter filter) => state = state.copyWith(filters: state.filters.toggleKey(filter)); + + void setViews(Map views) { + loadedFilters = false; + state = state.copyWith(views: views).setFiltersToDefault(); + } + + void setGenres(Map genres) => state = state.copyWith(genres: genres); + void setStudios(Map studios) => state = state.copyWith(studios: studios); + void setTags(Map tags) => state = state.copyWith(tags: tags); + void setTypes(Map types) => state = state.copyWith(types: types); + void setRatings(Map officialRatings) => state = state.copyWith(officialRatings: officialRatings); + void setYears(Map years) => state = state.copyWith(years: years); + void setFilters(Map filters) => state = state.copyWith(filters: filters); + + void clearAllFilters() { + state = state.copyWith( + genres: state.genres.setAll(false), + tags: state.tags.setAll(false), + officialRatings: state.officialRatings.setAll(false), + years: state.years.setAll(false), + searchQuery: '', + favourites: false, + recursive: false, + studios: state.studios.setAll(false), + filters: state.filters.setAll(false), + hideEmtpyShows: false, + ); + } + + void setSortBy(SortingOptions e) => state = state.copyWith(sortingOption: e); + + void setSortOrder(SortingOrder e) => state = state.copyWith(sortOrder: e); + + void setHideEmpty(bool value) => state = state.copyWith(hideEmtpyShows: value); + void setGroupBy(GroupBy groupBy) => state = state.copyWith(groupBy: groupBy); + + void setFolderId(ItemBaseModel item) { + if (state.folderOverwrite.contains(item)) return; + state = state.copyWith(folderOverwrite: [...state.folderOverwrite, item]); + } + + void backToFolder(ItemBaseModel item) => state = state.copyWith( + folderOverwrite: state.folderOverwrite.getRange(0, state.folderOverwrite.indexOf(item) + 1).toList()); + + void clearFolderOverWrite() => state = state.copyWith(folderOverwrite: []); + + void toggleSelectMode() => + state = state.copyWith(selecteMode: !state.selecteMode, selectedPosters: !state.selecteMode == false ? [] : null); + + void toggleSelection(ItemBaseModel item) { + if (state.selectedPosters.contains(item)) { + state = state.copyWith(selectedPosters: state.selectedPosters.where((element) => element != item).toList()); + } else { + state = state.copyWith(selectedPosters: [...state.selectedPosters, item]); + } + } + + selectAll(bool select) => state = state.copyWith(selectedPosters: select ? state.posters : []); + + Future setSelectedAsFavorite(bool bool) async { + final Map updateInfo = {}; + for (var i = 0; i < state.selectedPosters.length; i++) { + final response = await ref.read(userProvider.notifier).setAsFavorite(bool, state.selectedPosters[i].id); + final userData = response?.bodyOrThrow; + if (userData != null) { + updateInfo.putIfAbsent(state.selectedPosters[i].id, () => userData); + } + } + updateMultiUserData(updateInfo); + } + + Future setSelectedAsWatched(bool bool) async { + final Map updateInfo = {}; + for (var i = 0; i < state.selectedPosters.length; i++) { + final response = await ref.read(userProvider.notifier).markAsPlayed(bool, state.selectedPosters[i].id); + final userData = response?.bodyOrThrow; + if (userData != null) { + updateInfo.putIfAbsent(state.selectedPosters[i].id, () => userData); + } + } + updateMultiUserData(updateInfo); + } + + Future removeSelectedFromCollection() async { + final response = await api.collectionsCollectionIdItemsDelete( + collectionId: state.nestedCurrentItem?.id, ids: state.selectedPosters.map((e) => e.id).toList()); + if (response.isSuccessful) { + removeFromPosters([state.nestedCurrentItem?.id].whereNotNull().toList()); + } + return response; + } + + Future removeSelectedFromPlaylist() async { + final response = await api.playlistsPlaylistIdItemsDelete( + playlistId: state.nestedCurrentItem?.id, + entryIds: state.selectedPosters.map((e) => e.playlistId).whereNotNull().toList()); + if (response.isSuccessful) { + removeFromPosters([state.nestedCurrentItem?.id].whereNotNull().toList()); + } + return response; + } + + Future removeFromCollection({required List items}) async { + final response = await api.collectionsCollectionIdItemsDelete( + collectionId: state.nestedCurrentItem?.id, ids: items.map((e) => e.id).toList()); + if (response.isSuccessful) { + removeFromPosters(items.map((e) => e.id).toList()); + } + return response; + } + + Future removeFromPlaylist({required List items}) async { + final response = await api.playlistsPlaylistIdItemsDelete( + playlistId: state.nestedCurrentItem?.id, entryIds: items.map((e) => e.playlistId).whereNotNull().toList()); + if (response.isSuccessful) { + removeFromPosters(items.map((e) => e.id).toList()); + } + return response; + } + + Future updateMultiUserData(Map newData) async { + for (var element in newData.entries) { + updateUserData(element.key, element.value); + } + } + + Future updateUserData(String id, UserData? newData) async { + final currentItems = state.posters.toList(); + final item = currentItems.firstWhereOrNull((element) => element.id == id); + if (item == null) return; + final indexOf = currentItems.indexOf(item); + if (indexOf == -1) return; + currentItems.removeAt(indexOf); + currentItems.insert(indexOf, item.copyWith(userData: newData)); + state = state.copyWith(posters: currentItems); + } + + void setDefaultOptions(SortingOrder? sortOrder, SortingOptions? sortingOptions) { + state = state.copyWith( + sortOrder: sortOrder, + sortingOption: sortingOptions, + ); + } + + void updateUserDataMain(UserData? userData) { + state = state.copyWith( + folderOverwrite: [state.folderOverwrite.lastOrNull?.copyWith(userData: userData)].whereNotNull().toList(), + ); + } + + void updateParentItem(ItemBaseModel item) { + state = state.copyWith( + folderOverwrite: [item], + ); + } + + void removeFromPosters(List ids) { + final newPosters = state.posters; + state = state.copyWith(posters: newPosters..removeWhere((element) => ids.contains(element.id))); + } + + void updateItems(List items) {} + + void updateItem(ItemBaseModel item) { + state = state.copyWith(posters: state.posters.replace(item)); + } + + Future> _loadAllItems({bool shuffle = false, int? limit}) async { + List itemsToPlay = []; + + Future handleItemLoading(String itemId, ItemBaseModel currentModel) async { + final result = + currentModel is PlaylistModel ? await _loadPlaylistItems(id: itemId) : await _loadLibrary(id: itemId); + + itemsToPlay = result?.items ?? []; + } + + Future handleViewLoading() async { + final results = await Future.wait( + state.views.included.map((viewModel) async { + final libraryItems = await _loadLibrary( + shuffle: shuffle, + viewModel: viewModel, + limit: limit, + ); + return libraryItems; + }).whereNotNull(), + ); + + List newPosters = results.whereNotNull().expand((element) => element.items).toList(); + if (state.views.included.length > 1) { + if (shuffle || state.sortingOption == SortingOptions.random) { + newPosters = newPosters.random(); + } else { + newPosters = newPosters.sorted( + (a, b) => sortItems(a, b, state.sortingOption, state.sortOrder), + ); + } + } + + itemsToPlay = newPosters; + } + + if (state.folderOverwrite.isNotEmpty) { + await handleItemLoading(state.folderOverwrite.last.id, state.folderOverwrite.last); + } else if (state.views.hasEnabled) { + await handleViewLoading(); + } else { + if (state.searchQuery.isEmpty && !state.favourites) { + itemsToPlay = []; + } else { + final response = await _loadLibrary(recursive: true, shuffle: shuffle); + itemsToPlay = response?.items ?? []; + } + } + + return itemsToPlay; + } + + Future playLibraryItems(BuildContext context, WidgetRef ref, {bool shuffle = false}) async { + state = state.copyWith(fetchingItems: true); + List itemsToPlay = []; + + if (state.selectedPosters.isNotEmpty) { + itemsToPlay = shuffle ? state.selectedPosters.random() : state.selectedPosters; + } else { + itemsToPlay = await _loadAllItems(shuffle: shuffle); + } + + state = state.copyWith(fetchingItems: false); + + if (itemsToPlay.isNotEmpty) { + await itemsToPlay.playLibraryItems(context, ref); + } else { + fladderSnackbar(context, title: context.localized.libraryFetchNoItemsFound); + } + } + + Future> fetchGallery({bool shuffle = false}) async { + try { + List itemsToPlay = []; + + if (state.selectedPosters.isNotEmpty) { + itemsToPlay = shuffle ? state.selectedPosters.random() : state.selectedPosters; + } else { + itemsToPlay = await _loadAllItems(shuffle: shuffle); + } + + List albumItems = []; + + if (!state.types.included.containsAny([FladderItemType.video, FladderItemType.photo]) && state.recursive) { + for (var album in itemsToPlay.where( + (element) => element is PhotoAlbumModel || element is FolderModel, + )) { + try { + final fetchedAlbumContent = await api.itemsGet( + parentId: album.id, + includeItemTypes: [BaseItemKind.video, BaseItemKind.photo], + recursive: true, + fields: { + ItemFields.genres, + ItemFields.parentid, + ItemFields.tags, + ItemFields.datecreated, + ItemFields.datelastmediaadded, + ItemFields.overview, + ItemFields.originaltitle, + ItemFields.customrating, + ItemFields.primaryimageaspectratio, + }.toList(), + filters: [ + ...state.filters.included, + if (state.favourites) ItemFilter.isfavorite, + ], + sortBy: shuffle ? [ItemSortBy.random] : null, + ); + albumItems.addAll(fetchedAlbumContent.body?.items.whereType() ?? []); + } catch (e) { + log("Error fetching ${e.toString()}"); + } + } + } + + final galleryItems = itemsToPlay.whereType().toList(); + + if (shuffle) { + albumItems = albumItems.random(); + } + + final allItems = {...albumItems.whereType(), ...galleryItems}.toList(); + + return allItems; + } catch (e) { + log(e.toString()); + } finally {} + return []; + } + + Future viewGallery(BuildContext context, {PhotoModel? selected, bool shuffle = false}) async { + state = state.copyWith(fetchingItems: true); + final allItems = await fetchGallery(shuffle: shuffle); + + if (allItems.isNotEmpty) { + if (state.fetchingItems == true) { + state = state.copyWith(fetchingItems: false); + await Navigator.of(context, rootNavigator: true).push( + PageTransition( + child: PhotoViewerScreen( + items: allItems, + indexOfSelected: selected != null ? allItems.indexOf(selected) : 0, + ), + type: PageTransitionType.fade), + ); + } + } else { + fladderSnackbar(context, title: context.localized.libraryFetchNoItemsFound); + } + state = state.copyWith(fetchingItems: false); + } + + void cancelFetch() { + state = state.copyWith(fetchingItems: false); + } + + Future openRandom(BuildContext context) async { + final items = await _loadAllItems(shuffle: true, limit: 1); + if (items.isNotEmpty) { + items.firstOrNull?.navigateTo(context); + } + } +} + +extension SimpleSorter on List { + List hideEmptyChildren(bool hide) { + if (hide) { + return where((element) { + if (element.childCount == null) { + return true; + } + return (element.childCount ?? 0) > 0; + }).toList(); + } else { + return this; + } + } +} diff --git a/lib/providers/playlist_provider.dart b/lib/providers/playlist_provider.dart new file mode 100644 index 0000000..fe1e5aa --- /dev/null +++ b/lib/providers/playlist_provider.dart @@ -0,0 +1,83 @@ +import 'package:chopper/chopper.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/playlist_model.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:fladder/providers/service_provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class _PlaylistProviderModel { + final List items; + final Map collections; + _PlaylistProviderModel({ + required this.items, + required this.collections, + }); + + _PlaylistProviderModel copyWith({ + List? items, + Map? collections, + }) { + return _PlaylistProviderModel( + items: items ?? this.items, + collections: collections ?? this.collections, + ); + } +} + +final playlistProvider = StateNotifierProvider.autoDispose((ref) { + return BoxSetNotifier(ref); +}); + +class BoxSetNotifier extends StateNotifier<_PlaylistProviderModel> { + BoxSetNotifier(this.ref) : super(_PlaylistProviderModel(items: [], collections: {})); + final Ref ref; + + late final JellyService api = ref.read(jellyApiProvider); + + Future setItems(List items) async { + state = state.copyWith(items: items); + return _init(); + } + + Future _init() async { + final serverPlaylists = await api.usersUserIdItemsGet( + recursive: true, + includeItemTypes: [ + BaseItemKind.playlist, + ], + ); + + final playlists = serverPlaylists.body?.items?.map((e) => PlaylistModel.fromBaseDto(e, ref)).toList(); + + if (state.items.length == 1 && (playlists?.length ?? 0) < 25) { + final List> itemChecks = playlists?.map((element) async { + final itemList = await api.usersUserIdItemsGet(parentId: element.id); + final List items = (itemList.body?.items ?? []).map((e) => e.id).toList(); + return items.contains(state.items.firstOrNull?.id); + }).toList() ?? + []; + + final List results = await Future.wait(itemChecks); + + final Map boxSetContainsItemMap = Map.fromIterables(playlists ?? [], results); + + state = state.copyWith(collections: boxSetContainsItemMap); + } else { + final Map playlistContainsMap = + Map.fromIterables(playlists ?? [], List.generate(playlists?.length ?? 0, (index) => null)); + state = state.copyWith(collections: playlistContainsMap); + } + } + + Future addToPlaylist({required PlaylistModel playlist}) async => + await api.playlistsPlaylistIdItemsPost(playlistId: playlist.id, ids: state.items.map((e) => e.id).toList()); + + Future addToNewPlaylist({required String name}) async { + final result = await api.playlistsPost(name: name, ids: state.items.map((e) => e.id).toList(), body: null); + if (result.isSuccessful) { + await _init(); + } + return result; + } +} diff --git a/lib/providers/related_provider.dart b/lib/providers/related_provider.dart new file mode 100644 index 0000000..8a94a24 --- /dev/null +++ b/lib/providers/related_provider.dart @@ -0,0 +1,27 @@ +import 'package:chopper/chopper.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:fladder/providers/service_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +final relatedUtilityProvider = Provider((ref) { + return RelatedNotifier(ref: ref); +}); + +class RelatedNotifier { + final Ref ref; + RelatedNotifier({ + required this.ref, + }); + + late final JellyService api = ref.read(jellyApiProvider); + + late final String currentServerUrl = ref.read(userProvider)?.server ?? ""; + + Future>> relatedContent(String itemId) async { + final related = await api.itemsItemIdSimilarGet(itemId: itemId, limit: 50); + List posters = related.body?.items?.map((e) => ItemBaseModel.fromBaseDto(e, ref)).toList() ?? []; + return Response(related.base, posters); + } +} diff --git a/lib/providers/search_provider.dart b/lib/providers/search_provider.dart new file mode 100644 index 0000000..8056820 --- /dev/null +++ b/lib/providers/search_provider.dart @@ -0,0 +1,42 @@ +import 'package:chopper/chopper.dart'; +import 'package:fladder/models/search_model.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:fladder/providers/service_provider.dart'; +import 'package:fladder/util/item_base_model/item_base_model_extensions.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +final searchProvider = StateNotifierProvider((ref) { + return SearchNotifier(ref); +}); + +class SearchNotifier extends StateNotifier { + SearchNotifier(this.ref) : super(SearchModel()); + + final Ref ref; + + late final JellyService api = ref.read(jellyApiProvider); + + Future searchQuery() async { + if (state.searchQuery.isEmpty) return null; + state = state.copyWith(loading: true); + final response = await api.itemsGet( + recursive: true, + searchTerm: state.searchQuery, + ); + + state = state.copyWith( + resultCount: response.body?.totalRecordCount ?? 0, + results: (response.body?.items)?.groupedItems, + ); + state = state.copyWith(loading: false); + return response; + } + + void setQuery(String searchQuery) { + state = state.copyWith(searchQuery: searchQuery); + } + + void clear() { + state = SearchModel(); + } +} diff --git a/lib/providers/service_provider.dart b/lib/providers/service_provider.dart new file mode 100644 index 0000000..e33e3e7 --- /dev/null +++ b/lib/providers/service_provider.dart @@ -0,0 +1,938 @@ +import 'dart:convert'; +import 'dart:developer'; +import 'dart:typed_data'; + +import 'package:chopper/chopper.dart'; +import 'package:collection/collection.dart'; +import 'package:fladder/jellyfin/enum_models.dart'; +import 'package:fladder/models/credentials_model.dart'; +import 'package:fladder/models/items/intro_skip_model.dart'; +import 'package:fladder/models/items/trick_play_model.dart'; +import 'package:fladder/providers/image_provider.dart'; +import 'package:fladder/util/duration_extensions.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/account_model.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/util/jellyfin_extension.dart'; +import 'package:path/path.dart'; + +final jellyServiceProvider = StateProvider( + (ref) => JellyService( + ref, + JellyfinOpenApi.create( + interceptors: [ + JellyRequest(ref), + JellyResponse(ref), + HttpLoggingInterceptor(level: Level.basic), + ], + ), + ), +); + +class ServerQueryResult { + final List original; + final List items; + final int? totalRecordCount; + final int? startIndex; + ServerQueryResult({ + required this.original, + required this.items, + this.totalRecordCount, + this.startIndex, + }); + + factory ServerQueryResult.fromBaseQuery( + BaseItemDtoQueryResult baseQuery, + Ref ref, + ) { + return ServerQueryResult( + original: baseQuery.items ?? [], + items: baseQuery.items + ?.map( + (e) => ItemBaseModel.fromBaseDto(e, ref), + ) + .toList() ?? + [], + totalRecordCount: baseQuery.totalRecordCount, + startIndex: baseQuery.startIndex, + ); + } + + ServerQueryResult copyWith({ + List? original, + List? items, + int? totalRecordCount, + int? startIndex, + }) { + return ServerQueryResult( + original: original ?? this.original, + items: items ?? this.items, + totalRecordCount: totalRecordCount ?? this.totalRecordCount, + startIndex: startIndex ?? this.startIndex, + ); + } +} + +class JellyService { + JellyService(this.ref, this.api); + + final JellyfinOpenApi api; + final Ref ref; + AccountModel? get account => ref.read(userProvider); + + Future> usersUserIdItemsItemIdGet({ + String? itemId, + }) async { + final response = await api.itemsItemIdGet( + userId: account?.id, + itemId: itemId, + ); + return response.copyWith(body: ItemBaseModel.fromBaseDto(response.bodyOrThrow, ref)); + } + + Future> usersUserIdItemsItemIdGetBaseItem({ + String? itemId, + }) async { + final response = await api.itemsItemIdGet( + userId: account?.id, + itemId: itemId, + ); + return response; + } + + Future> itemsGet({ + String? maxOfficialRating, + bool? hasThemeSong, + bool? hasThemeVideo, + bool? hasSubtitles, + bool? hasSpecialFeature, + bool? hasTrailer, + String? adjacentTo, + int? parentIndexNumber, + bool? hasParentalRating, + bool? isHd, + bool? is4K, + List? locationTypes, + List? excludeLocationTypes, + bool? isMissing, + bool? isUnaired, + num? minCommunityRating, + num? minCriticRating, + DateTime? minPremiereDate, + DateTime? minDateLastSaved, + DateTime? minDateLastSavedForUser, + DateTime? maxPremiereDate, + bool? hasOverview, + bool? hasImdbId, + bool? hasTmdbId, + bool? hasTvdbId, + bool? isMovie, + bool? isSeries, + bool? isNews, + bool? isKids, + bool? isSports, + List? excludeItemIds, + int? startIndex, + int? limit, + bool? recursive, + String? searchTerm, + List? sortOrder, + String? parentId, + List? fields, + List? excludeItemTypes, + List? includeItemTypes, + List? filters, + bool? isFavorite, + List? mediaTypes, + List? imageTypes, + List? sortBy, + bool? isPlayed, + List? genres, + List? officialRatings, + List? tags, + List? years, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + String? person, + List? personIds, + List? personTypes, + List? studios, + List? artists, + List? excludeArtistIds, + List? artistIds, + List? albumArtistIds, + List? contributingArtistIds, + List? albums, + List? albumIds, + List? ids, + List? videoTypes, + String? minOfficialRating, + bool? isLocked, + bool? isPlaceHolder, + bool? hasOfficialRating, + bool? collapseBoxSetItems, + int? minWidth, + int? minHeight, + int? maxWidth, + int? maxHeight, + bool? is3D, + List? seriesStatus, + String? nameStartsWithOrGreater, + String? nameStartsWith, + String? nameLessThan, + List? studioIds, + List? genreIds, + bool? enableTotalRecordCount, + bool? enableImages, + }) async { + final response = await api.itemsGet( + userId: account?.id, + maxOfficialRating: maxOfficialRating, + hasThemeSong: hasThemeSong, + hasThemeVideo: hasThemeVideo, + hasSubtitles: hasSubtitles, + hasSpecialFeature: hasSpecialFeature, + hasTrailer: hasTrailer, + adjacentTo: adjacentTo, + parentIndexNumber: parentIndexNumber, + hasParentalRating: hasParentalRating, + isHd: isHd, + is4K: is4K, + locationTypes: locationTypes, + excludeLocationTypes: excludeLocationTypes, + isMissing: isMissing, + isUnaired: isUnaired, + minCommunityRating: minCommunityRating, + minCriticRating: minCriticRating, + minPremiereDate: minPremiereDate, + minDateLastSaved: minDateLastSaved, + minDateLastSavedForUser: minDateLastSavedForUser, + maxPremiereDate: maxPremiereDate, + hasOverview: hasOverview, + hasImdbId: hasImdbId, + hasTmdbId: hasTmdbId, + hasTvdbId: hasTvdbId, + isMovie: isMovie, + isSeries: isSeries, + isNews: isNews, + isKids: isKids, + isSports: isSports, + excludeItemIds: excludeItemIds, + startIndex: startIndex, + limit: limit, + recursive: recursive, + searchTerm: searchTerm, + sortOrder: sortOrder, + sortBy: sortBy, + parentId: parentId, + fields: {...?fields, ItemFields.candelete, ItemFields.candownload}.toList(), + excludeItemTypes: excludeItemTypes, + includeItemTypes: includeItemTypes, + filters: filters, + isFavorite: isFavorite, + mediaTypes: mediaTypes, + imageTypes: imageTypes, + isPlayed: isPlayed, + genres: genres, + officialRatings: officialRatings, + tags: tags, + years: years, + enableUserData: enableUserData, + imageTypeLimit: imageTypeLimit, + enableImageTypes: enableImageTypes, + person: person, + personIds: personIds, + personTypes: personTypes, + studios: studios, + artists: artists, + excludeArtistIds: excludeArtistIds, + artistIds: artistIds, + albumArtistIds: albumArtistIds, + contributingArtistIds: contributingArtistIds, + albums: albums, + albumIds: albumIds, + ids: ids, + videoTypes: videoTypes, + minOfficialRating: minOfficialRating, + isLocked: isLocked, + isPlaceHolder: isPlaceHolder, + hasOfficialRating: hasOfficialRating, + collapseBoxSetItems: collapseBoxSetItems, + minWidth: minWidth, + minHeight: minHeight, + maxWidth: maxWidth, + maxHeight: maxHeight, + is3D: is3D, + seriesStatus: seriesStatus, + nameStartsWithOrGreater: nameStartsWithOrGreater, + nameStartsWith: nameStartsWith, + nameLessThan: nameLessThan, + studioIds: studioIds, + genreIds: genreIds, + enableTotalRecordCount: enableTotalRecordCount, + enableImages: enableImages, + ); + + return response.copyWith( + body: ServerQueryResult.fromBaseQuery(response.bodyOrThrow, ref), + ); + } + + Future>> personsGet({ + String? searchTerm, + int? limit, + bool? isFavorite, + }) async { + final response = await api.personsGet( + userId: account?.id, + limit: limit, + isFavorite: isFavorite, + ); + return response.copyWith( + body: response.body?.items + ?.map( + (e) => ItemBaseModel.fromBaseDto(e, ref), + ) + .toList(), + ); + } + + Future>> itemsItemIdImagesGet({ + String? itemId, + bool? isFavorite, + }) async { + final response = await api.itemsItemIdImagesGet(itemId: itemId); + return response; + } + + Future> itemsItemIdMetadataEditorGet({ + String? itemId, + }) async { + return api.itemsItemIdMetadataEditorGet(itemId: itemId); + } + + Future> itemsItemIdRemoteImagesGet({ + String? itemId, + ImageType? type, + bool? includeAllLanguages, + }) async { + return api.itemsItemIdRemoteImagesGet( + itemId: itemId, + type: ItemsItemIdRemoteImagesGetType.values.firstWhereOrNull( + (element) => element.value == type?.value, + ), + includeAllLanguages: includeAllLanguages, + ); + } + + Future itemsItemIdPost({ + String? itemId, + required BaseItemDto? body, + }) async { + return api.itemsItemIdPost( + itemId: itemId, + body: body, + ); + } + + Future?> itemIdImagesImageTypePost( + ImageType type, + String itemId, + Uint8List data, + ) async { + return api.itemIdImagesImageTypePost( + type, + itemId, + data, + ); + } + + Future itemsItemIdRemoteImagesDownloadPost({ + required String? itemId, + required ImageType? type, + String? imageUrl, + }) async { + return api.itemsItemIdRemoteImagesDownloadPost( + itemId: itemId, + type: ItemsItemIdRemoteImagesDownloadPostType.values.firstWhereOrNull( + (element) => element.value == type?.value, + ), + imageUrl: imageUrl, + ); + } + + Future itemsItemIdImagesImageTypeDelete({ + required String? itemId, + required ImageType? imageType, + int? imageIndex, + }) async { + return api.itemsItemIdImagesImageTypeDelete( + itemId: itemId, + imageType: ItemsItemIdImagesImageTypeDeleteImageType.values.firstWhereOrNull( + (element) => element.value == imageType?.value, + ), + imageIndex: imageIndex, + ); + } + + Future> usersUserIdItemsResumeGet({ + int? startIndex, + int? limit, + String? searchTerm, + String? parentId, + List? fields, + List? mediaTypes, + bool? enableUserData, + bool? enableTotalRecordCount, + List? enableImageTypes, + List? excludeItemTypes, + List? includeItemTypes, + }) async { + return api.userItemsResumeGet( + userId: account?.id, + searchTerm: searchTerm, + parentId: parentId, + limit: limit, + fields: fields, + mediaTypes: mediaTypes, + enableTotalRecordCount: enableTotalRecordCount, + enableImageTypes: enableImageTypes, + enableUserData: enableUserData, + includeItemTypes: includeItemTypes, + excludeItemTypes: excludeItemTypes, + ); + } + + Future>> usersUserIdItemsLatestGet({ + String? parentId, + List? fields, + List? includeItemTypes, + bool? isPlayed, + bool? enableImages, + int? imageTypeLimit, + List? enableImageTypes, + bool? enableUserData, + int? limit, + bool? groupItems, + }) async { + return api.itemsLatestGet( + parentId: parentId, + userId: account?.id, + fields: fields, + includeItemTypes: includeItemTypes, + isPlayed: isPlayed, + enableImages: enableImages, + imageTypeLimit: imageTypeLimit, + enableImageTypes: enableImageTypes, + enableUserData: enableUserData, + limit: limit, + groupItems: groupItems, + ); + } + + Future>> moviesRecommendationsGet({ + String? parentId, + List? fields, + int? categoryLimit, + int? itemLimit, + }) async { + return api.moviesRecommendationsGet( + userId: account?.id, + parentId: parentId, + fields: fields, + categoryLimit: categoryLimit, + itemLimit: itemLimit, + ); + } + + Future> showsNextUpGet({ + int? startIndex, + int? limit, + String? parentId, + DateTime? nextUpDateCutoff, + List? fields, + bool? enableUserData, + List? enableImageTypes, + int? imageTypeLimit, + }) async { + return api.showsNextUpGet( + userId: account?.id, + parentId: parentId, + limit: limit, + fields: fields, + enableResumable: false, + enableRewatching: false, + disableFirstEpisode: false, + nextUpDateCutoff: nextUpDateCutoff, + enableImageTypes: enableImageTypes, + enableUserData: enableUserData, + imageTypeLimit: imageTypeLimit, + ); + } + + Future> genresGet({ + String? parentId, + List? sortBy, + List? sortOrder, + List? includeItemTypes, + }) async { + return api.genresGet( + parentId: parentId, + userId: account?.id, + sortBy: sortBy, + sortOrder: sortOrder, + ); + } + + Future sessionsPlayingPost({required PlaybackStartInfo? body}) async => api.sessionsPlayingPost(body: body); + + Future sessionsPlayingStoppedPost({ + required PlaybackStopInfo? body, + Duration? totalDuration, + }) async { + final position = body?.positionTicks; + final totalTime = totalDuration?.toRuntimeTicks; + final maxTime = ref.read(userProvider.select((value) => value?.serverConfiguration?.maxResumePct ?? 90)); + + final response = await api.sessionsPlayingStoppedPost( + body: body?.copyWith( + failed: false, + ), + ); + + //This is a temporary fix + if (totalTime != null && position != null && position > (totalTime * (maxTime / 100))) { + await usersUserIdPlayedItemsItemIdPost(itemId: body?.itemId, datePlayed: DateTime.now()); + } + + return response; + } + + Future sessionsPlayingProgressPost({required PlaybackProgressInfo? body}) async => + api.sessionsPlayingProgressPost(body: body); + + Future> itemsItemIdPlaybackInfoPost({ + required String? itemId, + int? maxStreamingBitrate, + int? startTimeTicks, + int? audioStreamIndex, + int? subtitleStreamIndex, + int? maxAudioChannels, + String? mediaSourceId, + String? liveStreamId, + bool? autoOpenLiveStream, + bool? enableDirectPlay, + bool? enableDirectStream, + bool? enableTranscoding, + bool? allowVideoStreamCopy, + bool? allowAudioStreamCopy, + required PlaybackInfoDto? body, + }) async => + api.itemsItemIdPlaybackInfoPost( + itemId: itemId, + userId: account?.id, + enableDirectPlay: enableDirectPlay, + enableDirectStream: enableDirectStream, + enableTranscoding: enableTranscoding, + autoOpenLiveStream: autoOpenLiveStream, + maxStreamingBitrate: maxStreamingBitrate, + liveStreamId: liveStreamId, + startTimeTicks: startTimeTicks, + mediaSourceId: mediaSourceId, + audioStreamIndex: audioStreamIndex, + subtitleStreamIndex: subtitleStreamIndex, + body: body, + ); + + Future> showsSeriesIdEpisodesGet({ + required String? seriesId, + List? fields, + int? season, + String? seasonId, + bool? isMissing, + String? adjacentTo, + String? startItemId, + int? startIndex, + int? limit, + bool? enableImages, + int? imageTypeLimit, + List? enableImageTypes, + bool? enableUserData, + ShowsSeriesIdEpisodesGetSortBy? sortBy, + }) async { + return api.showsSeriesIdEpisodesGet( + seriesId: seriesId, + userId: account?.id, + fields: fields, + isMissing: isMissing, + limit: limit, + sortBy: sortBy, + enableUserData: enableUserData, + startIndex: startIndex, + adjacentTo: adjacentTo, + startItemId: startItemId, + season: season, + seasonId: seasonId, + enableImages: enableImages, + enableImageTypes: enableImageTypes, + ); + } + + Future> fetchEpisodeFromShow({ + required String? seriesId, + String? seasonId, + }) async { + final response = await showsSeriesIdEpisodesGet(seriesId: seriesId, seasonId: seasonId); + return response.body?.items?.map((e) => ItemBaseModel.fromBaseDto(e, ref)).toList() ?? []; + } + + Future> itemsItemIdSimilarGet({ + String? itemId, + int? limit, + }) async { + return api.itemsItemIdSimilarGet( + userId: account?.id, + itemId: itemId, + limit: limit, + ); + } + + Future> usersUserIdItemsGet({ + String? parentId, + bool? recursive, + List? includeItemTypes, + }) async { + return api.itemsGet( + parentId: parentId, + userId: account?.id, + recursive: recursive, + includeItemTypes: includeItemTypes, + ); + } + + Future> playlistsPlaylistIdItemsPost({ + String? playlistId, + List? ids, + }) async { + return api.playlistsPlaylistIdItemsPost( + playlistId: playlistId, + ids: ids, + userId: account?.id, + ); + } + + Future> playlistsPost({ + String? name, + List? ids, + required CreatePlaylistDto? body, + }) async { + return api.playlistsPost( + name: name, + ids: ids, + userId: account?.id, + body: body, + ); + } + + Future>> usersPublicGet( + CredentialsModel credentials, + ) async { + final response = await api.usersPublicGet(); + return response.copyWith( + body: response.body?.map( + (e) { + var imageUrl = ref.read(imageUtilityProvider).getUserImageUrl(e.id ?? ""); + return AccountModel( + name: e.name ?? "", + credentials: credentials, + id: e.id ?? "", + avatar: imageUrl, + lastUsed: DateTime.now(), + ); + }, + ).toList(), + ); + } + + Future> usersAuthenticateByNamePost({ + required String userName, + required String password, + }) async { + return api.usersAuthenticateByNamePost(body: AuthenticateUserByName(username: userName, pw: password)); + } + + Future> systemConfigurationGet() => api.systemConfigurationGet(); + Future> systemInfoPublicGet() => api.systemInfoPublicGet(); + + Future sessionsLogoutPost() => api.sessionsLogoutPost(); + + Future> itemsItemIdDownloadGet({ + String? itemId, + }) => + api.itemsItemIdDownloadGet(itemId: itemId); + + Future collectionsCollectionIdItemsPost({required String? collectionId, required List? ids}) => + api.collectionsCollectionIdItemsPost(collectionId: collectionId, ids: ids); + Future collectionsCollectionIdItemsDelete({required String? collectionId, required List? ids}) => + api.collectionsCollectionIdItemsDelete(collectionId: collectionId, ids: ids); + + Future collectionsPost({String? name, List? ids, String? parentId, bool? isLocked}) => + api.collectionsPost(name: name, ids: ids, parentId: parentId, isLocked: isLocked); + + Future> usersUserIdViewsGet({ + bool? includeExternalContent, + List? presetViews, + bool? includeHidden, + }) => + api.userViewsGet( + userId: account?.id, + includeExternalContent: includeExternalContent, + presetViews: presetViews, + includeHidden: includeHidden); + + Future>> itemsItemIdExternalIdInfosGet({required String? itemId}) => + api.itemsItemIdExternalIdInfosGet(itemId: itemId); + + Future>> itemsRemoteSearchSeriesPost( + {required SeriesInfoRemoteSearchQuery? body}) => + api.itemsRemoteSearchSeriesPost(body: body); + + Future>> itemsRemoteSearchMoviePost({required MovieInfoRemoteSearchQuery? body}) => + api.itemsRemoteSearchMoviePost(body: body); + + Future> itemsRemoteSearchApplyItemIdPost({ + required String? itemId, + bool? replaceAllImages, + required RemoteSearchResult? body, + }) => + api.itemsRemoteSearchApplyItemIdPost( + itemId: itemId, + replaceAllImages: replaceAllImages, + body: body, + ); + + Future> showsSeriesIdSeasonsGet({ + required String? seriesId, + bool? enableUserData, + bool? isMissing, + List? fields, + }) => + api.showsSeriesIdSeasonsGet( + seriesId: seriesId, + isMissing: isMissing, + enableUserData: enableUserData, + fields: fields, + ); + + Future> itemsFilters2Get({ + String? parentId, + List? includeItemTypes, + bool? isAiring, + bool? isMovie, + bool? isSports, + bool? isKids, + bool? isNews, + bool? isSeries, + bool? recursive, + }) => + api.itemsFilters2Get( + parentId: parentId, + includeItemTypes: includeItemTypes, + isAiring: isAiring, + isMovie: isMovie, + isSports: isSports, + isKids: isKids, + isNews: isNews, + isSeries: isSeries, + recursive: recursive, + ); + + Future> studiosGet({ + int? startIndex, + int? limit, + String? searchTerm, + String? parentId, + List? fields, + List? excludeItemTypes, + List? includeItemTypes, + bool? isFavorite, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + String? userId, + String? nameStartsWithOrGreater, + String? nameStartsWith, + String? nameLessThan, + bool? enableImages, + bool? enableTotalRecordCount, + }) => + api.studiosGet( + startIndex: startIndex, + limit: limit, + searchTerm: searchTerm, + parentId: parentId, + fields: fields, + excludeItemTypes: excludeItemTypes, + includeItemTypes: includeItemTypes, + isFavorite: isFavorite, + enableUserData: enableUserData, + imageTypeLimit: imageTypeLimit, + enableImageTypes: enableImageTypes, + nameStartsWithOrGreater: nameStartsWithOrGreater, + nameStartsWith: nameStartsWith, + nameLessThan: nameLessThan, + enableImages: enableImages, + enableTotalRecordCount: enableTotalRecordCount, + ); + + Future> playlistsPlaylistIdItemsGet({ + required String? playlistId, + int? startIndex, + int? limit, + List? fields, + bool? enableImages, + bool? enableUserData, + int? imageTypeLimit, + List? enableImageTypes, + }) async { + final response = await api.playlistsPlaylistIdItemsGet( + playlistId: playlistId, + userId: account?.id, + startIndex: startIndex, + limit: limit, + fields: fields, + enableImages: enableImages, + enableUserData: enableUserData, + imageTypeLimit: imageTypeLimit, + enableImageTypes: enableImageTypes, + ); + return response.copyWith( + body: ServerQueryResult.fromBaseQuery(response.bodyOrThrow, ref), + ); + } + + Future playlistsPlaylistIdItemsDelete({required String? playlistId, List? entryIds}) => + api.playlistsPlaylistIdItemsDelete( + playlistId: playlistId, + entryIds: entryIds, + ); + + Future> usersMeGet() => api.usersMeGet(); + + Future configuration() => api.systemConfigurationGet(); + + Future itemsItemIdRefreshPost({ + required String? itemId, + MetadataRefresh? metadataRefreshMode, + MetadataRefresh? imageRefreshMode, + bool? replaceAllMetadata, + bool? replaceAllImages, + }) => + api.itemsItemIdRefreshPost( + itemId: itemId, + metadataRefreshMode: metadataRefreshMode?.metadataRefreshMode, + imageRefreshMode: imageRefreshMode?.imageRefreshMode, + replaceAllMetadata: replaceAllMetadata, + replaceAllImages: replaceAllImages, + ); + + Future> usersUserIdFavoriteItemsItemIdPost({ + required String? itemId, + }) => + api.userFavoriteItemsItemIdPost( + itemId: itemId, + userId: account?.id, + ); + + Future> usersUserIdFavoriteItemsItemIdDelete({ + required String? itemId, + }) => + api.userFavoriteItemsItemIdDelete( + itemId: itemId, + userId: account?.id, + ); + + Future> usersUserIdPlayedItemsItemIdPost({ + required String? itemId, + DateTime? datePlayed, + }) => + api.userPlayedItemsItemIdPost(itemId: itemId, userId: account?.id, datePlayed: datePlayed); + + Future> usersUserIdPlayedItemsItemIdDelete({ + required String? itemId, + }) => + api.userPlayedItemsItemIdDelete( + itemId: itemId, + userId: account?.id, + ); + + Future?> introSkipGet({ + required String id, + }) async { + try { + final response = await api.episodeIdIntroTimestampsGet(id: id); + final outro = await api.episodeIdIntroSkipperSegmentsGet(id: id); + final map = jsonDecode(outro.bodyString) as Map; + final newModel = IntroOutSkipModel( + intro: + map["Introduction"] != null ? IntroSkipModel.fromJson(map["Introduction"] as Map) : null, + credits: map["Credits"] != null ? IntroSkipModel.fromJson(map["Credits"] as Map) : null, + ); + return response.copyWith( + body: newModel, + ); + } catch (e) { + log(e.toString()); + return null; + } + } + + Future?> getTrickPlay({ + required ItemBaseModel? item, + int? width, + required Ref ref, + }) async { + try { + if (item == null) return null; + if (item.overview.trickPlayInfo?.isEmpty == true) { + return null; + } + final trickPlayModel = item.overview.trickPlayInfo?.values.lastOrNull; + if (trickPlayModel == null) return null; + final response = await api.videosItemIdTrickplayWidthTilesM3u8Get( + itemId: item.id, + width: trickPlayModel.width, + ); + + final server = ref.read(userProvider)?.server; + + if (server == null) return null; + + final lines = response.bodyString.split('\n') + ..removeWhere((element) => element.startsWith('#') || !element.contains('.jpg')); + return response.copyWith( + body: trickPlayModel.copyWith( + images: lines + .map( + (e) => joinAll([server, 'Videos/${item.id}/Trickplay/${trickPlayModel.width}', e]), + ) + .toList())); + } catch (e) { + log(e.toString()); + return null; + } + } + + Future>> sessionsInfo(String deviceId) async => api.sessionsGet(deviceId: deviceId); + + Future> quickConnect(String code) async => api.quickConnectAuthorizePost(code: code); + + Future> quickConnectEnabled() async => api.quickConnectEnabledGet(); + + Future> deleteItem(String itemId) => api.itemsItemIdDelete(itemId: itemId); +} diff --git a/lib/providers/session_info_provider.dart b/lib/providers/session_info_provider.dart new file mode 100644 index 0000000..31fb8fc --- /dev/null +++ b/lib/providers/session_info_provider.dart @@ -0,0 +1,64 @@ +import 'dart:async'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +part 'session_info_provider.freezed.dart'; +part 'session_info_provider.g.dart'; + +@Riverpod() +class SessionInfo extends _$SessionInfo { + late final api = ref.read(jellyApiProvider); + Timer? _timer; + + @override + SessionInfoModel build() { + ref.onDispose(() => _timer?.cancel()); + _startTimer(); + return SessionInfoModel(); + } + + void _startTimer() { + _fetchData(); + _timer = Timer.periodic(Duration(seconds: 2), (timer) async { + await _fetchData(); + }); + } + + Future _fetchData() async { + final deviceId = ref.read(userProvider)?.credentials.deviceId; + if (deviceId == null) { + state = SessionInfoModel(); + return; + } + + final response = await api.sessionsInfo(deviceId); + + final session = response.body?.firstOrNull; + + if (session == null) { + state = SessionInfoModel(); + return; + } + + state = SessionInfoModel( + playbackModel: session.playState?.playMethod?.name, + transCodeInfo: session.transcodingInfo, + ); + } +} + +@freezed +class SessionInfoModel with _$SessionInfoModel { + const SessionInfoModel._(); + + factory SessionInfoModel({ + String? playbackModel, + TranscodingInfo? transCodeInfo, + }) = _SessionInfoModel; + + factory SessionInfoModel.fromJson(Map json) => _$SessionInfoModelFromJson(json); +} diff --git a/lib/providers/session_info_provider.freezed.dart b/lib/providers/session_info_provider.freezed.dart new file mode 100644 index 0000000..702406e --- /dev/null +++ b/lib/providers/session_info_provider.freezed.dart @@ -0,0 +1,173 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'session_info_provider.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +SessionInfoModel _$SessionInfoModelFromJson(Map json) { + return _SessionInfoModel.fromJson(json); +} + +/// @nodoc +mixin _$SessionInfoModel { + String? get playbackModel => throw _privateConstructorUsedError; + TranscodingInfo? get transCodeInfo => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $SessionInfoModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SessionInfoModelCopyWith<$Res> { + factory $SessionInfoModelCopyWith( + SessionInfoModel value, $Res Function(SessionInfoModel) then) = + _$SessionInfoModelCopyWithImpl<$Res, SessionInfoModel>; + @useResult + $Res call({String? playbackModel, TranscodingInfo? transCodeInfo}); +} + +/// @nodoc +class _$SessionInfoModelCopyWithImpl<$Res, $Val extends SessionInfoModel> + implements $SessionInfoModelCopyWith<$Res> { + _$SessionInfoModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? playbackModel = freezed, + Object? transCodeInfo = freezed, + }) { + return _then(_value.copyWith( + playbackModel: freezed == playbackModel + ? _value.playbackModel + : playbackModel // ignore: cast_nullable_to_non_nullable + as String?, + transCodeInfo: freezed == transCodeInfo + ? _value.transCodeInfo + : transCodeInfo // ignore: cast_nullable_to_non_nullable + as TranscodingInfo?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$SessionInfoModelImplCopyWith<$Res> + implements $SessionInfoModelCopyWith<$Res> { + factory _$$SessionInfoModelImplCopyWith(_$SessionInfoModelImpl value, + $Res Function(_$SessionInfoModelImpl) then) = + __$$SessionInfoModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({String? playbackModel, TranscodingInfo? transCodeInfo}); +} + +/// @nodoc +class __$$SessionInfoModelImplCopyWithImpl<$Res> + extends _$SessionInfoModelCopyWithImpl<$Res, _$SessionInfoModelImpl> + implements _$$SessionInfoModelImplCopyWith<$Res> { + __$$SessionInfoModelImplCopyWithImpl(_$SessionInfoModelImpl _value, + $Res Function(_$SessionInfoModelImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? playbackModel = freezed, + Object? transCodeInfo = freezed, + }) { + return _then(_$SessionInfoModelImpl( + playbackModel: freezed == playbackModel + ? _value.playbackModel + : playbackModel // ignore: cast_nullable_to_non_nullable + as String?, + transCodeInfo: freezed == transCodeInfo + ? _value.transCodeInfo + : transCodeInfo // ignore: cast_nullable_to_non_nullable + as TranscodingInfo?, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$SessionInfoModelImpl extends _SessionInfoModel { + _$SessionInfoModelImpl({this.playbackModel, this.transCodeInfo}) : super._(); + + factory _$SessionInfoModelImpl.fromJson(Map json) => + _$$SessionInfoModelImplFromJson(json); + + @override + final String? playbackModel; + @override + final TranscodingInfo? transCodeInfo; + + @override + String toString() { + return 'SessionInfoModel(playbackModel: $playbackModel, transCodeInfo: $transCodeInfo)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$SessionInfoModelImpl && + (identical(other.playbackModel, playbackModel) || + other.playbackModel == playbackModel) && + (identical(other.transCodeInfo, transCodeInfo) || + other.transCodeInfo == transCodeInfo)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, playbackModel, transCodeInfo); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$SessionInfoModelImplCopyWith<_$SessionInfoModelImpl> get copyWith => + __$$SessionInfoModelImplCopyWithImpl<_$SessionInfoModelImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$SessionInfoModelImplToJson( + this, + ); + } +} + +abstract class _SessionInfoModel extends SessionInfoModel { + factory _SessionInfoModel( + {final String? playbackModel, + final TranscodingInfo? transCodeInfo}) = _$SessionInfoModelImpl; + _SessionInfoModel._() : super._(); + + factory _SessionInfoModel.fromJson(Map json) = + _$SessionInfoModelImpl.fromJson; + + @override + String? get playbackModel; + @override + TranscodingInfo? get transCodeInfo; + @override + @JsonKey(ignore: true) + _$$SessionInfoModelImplCopyWith<_$SessionInfoModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/providers/session_info_provider.g.dart b/lib/providers/session_info_provider.g.dart new file mode 100644 index 0000000..a326382 --- /dev/null +++ b/lib/providers/session_info_provider.g.dart @@ -0,0 +1,46 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'session_info_provider.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$SessionInfoModelImpl _$$SessionInfoModelImplFromJson( + Map json) => + _$SessionInfoModelImpl( + playbackModel: json['playbackModel'] as String?, + transCodeInfo: json['transCodeInfo'] == null + ? null + : TranscodingInfo.fromJson( + json['transCodeInfo'] as Map), + ); + +Map _$$SessionInfoModelImplToJson( + _$SessionInfoModelImpl instance) => + { + 'playbackModel': instance.playbackModel, + 'transCodeInfo': instance.transCodeInfo, + }; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$sessionInfoHash() => r'ab5afcada1c9677cadda954c9abf7eb361dc057d'; + +/// See also [SessionInfo]. +@ProviderFor(SessionInfo) +final sessionInfoProvider = + AutoDisposeNotifierProvider.internal( + SessionInfo.new, + name: r'sessionInfoProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$sessionInfoHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$SessionInfo = AutoDisposeNotifier; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member diff --git a/lib/providers/settings/book_viewer_settings_provider.dart b/lib/providers/settings/book_viewer_settings_provider.dart new file mode 100644 index 0000000..97e6d7e --- /dev/null +++ b/lib/providers/settings/book_viewer_settings_provider.dart @@ -0,0 +1,140 @@ +import 'dart:convert'; + +import 'package:collection/collection.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:screen_brightness/screen_brightness.dart'; + +import 'package:fladder/providers/shared_provider.dart'; +import 'package:fladder/util/debouncer.dart'; + +enum ReadDirection { + leftToRight, + rightToLeft; + + String toMap() => name; + static ReadDirection fromMap(String? map) { + return ReadDirection.values.firstWhereOrNull((element) => element.name == map) ?? ReadDirection.leftToRight; + } +} + +enum InitZoomState { + contained, + covered; + + String toMap() => name; + + static InitZoomState fromMap(String? map) { + return InitZoomState.values.firstWhereOrNull((element) => element.name == map) ?? InitZoomState.contained; + } +} + +enum GestureCache { + contained, + covered; + + String toMap() => name; + + static InitZoomState fromMap(String? map) { + return InitZoomState.values.firstWhereOrNull((element) => element.name == map) ?? InitZoomState.contained; + } +} + +class BookViewerSettingsModel { + final double? screenBrightness; + final ReadDirection readDirection; + final InitZoomState initZoomState; + final bool cachePageZoom; + final bool keepPageZoom; + final bool disableScrollOnZoom; + + BookViewerSettingsModel({ + this.screenBrightness, + this.readDirection = ReadDirection.leftToRight, + this.initZoomState = InitZoomState.contained, + this.cachePageZoom = false, + this.keepPageZoom = true, + this.disableScrollOnZoom = false, + }); + + BookViewerSettingsModel copyWith({ + ValueGetter? screenBrightness, + ReadDirection? readDirection, + InitZoomState? initZoomState, + bool? cachePageZoom, + bool? keepPageZoom, + bool? disableScrollOnZoom, + }) { + return BookViewerSettingsModel( + screenBrightness: screenBrightness != null ? screenBrightness.call() : this.screenBrightness, + readDirection: readDirection ?? this.readDirection, + initZoomState: initZoomState ?? this.initZoomState, + cachePageZoom: cachePageZoom ?? this.cachePageZoom, + keepPageZoom: keepPageZoom ?? this.keepPageZoom, + disableScrollOnZoom: disableScrollOnZoom ?? this.disableScrollOnZoom, + ); + } + + Map toMap() { + return { + 'screenBrightness': screenBrightness, + 'readDirection': readDirection.toMap(), + 'initZoomState': initZoomState.toMap(), + 'cachePageZoom': cachePageZoom, + 'keepPageZoom': keepPageZoom, + 'disableScrollOnZoom': disableScrollOnZoom, + }; + } + + factory BookViewerSettingsModel.fromMap(Map map) { + return BookViewerSettingsModel( + screenBrightness: map['screenBrightness']?.toDouble(), + readDirection: ReadDirection.fromMap(map['readDirection']), + initZoomState: InitZoomState.fromMap(map['initZoomState']), + cachePageZoom: map['cachePageZoom'] ?? false, + keepPageZoom: map['keepPageZoom'] ?? true, + disableScrollOnZoom: map['disableScrollOnZoom'] ?? false, + ); + } + + String toJson() => json.encode(toMap()); + + factory BookViewerSettingsModel.fromJson(String source) => BookViewerSettingsModel.fromMap(json.decode(source)); +} + +final bookViewerSettingsProvider = StateNotifierProvider((ref) { + return BookViewerSettingsNotifier(ref); +}); + +class BookViewerSettingsNotifier extends StateNotifier { + BookViewerSettingsNotifier(this.ref) : super(BookViewerSettingsModel()); + + final Ref ref; + + final Debouncer _debouncer = Debouncer(const Duration(seconds: 1)); + + @override + set state(BookViewerSettingsModel value) { + _debouncer.run(() => ref.read(sharedUtilityProvider).bookViewSettings = value); + super.state = value; + } + + void setScreenBrightness(double? value) async { + state = state.copyWith( + screenBrightness: () => value, + ); + if (state.screenBrightness != null) { + ScreenBrightness().setScreenBrightness(state.screenBrightness!); + } else { + ScreenBrightness().resetScreenBrightness(); + } + } + + setSavedBrightness() { + if (state.screenBrightness != null) { + ScreenBrightness().setScreenBrightness(state.screenBrightness!); + } + } + + void update(BookViewerSettingsModel Function(BookViewerSettingsModel state) outgoing) => state = outgoing(state); +} diff --git a/lib/providers/settings/client_settings_provider.dart b/lib/providers/settings/client_settings_provider.dart new file mode 100644 index 0000000..032f8d1 --- /dev/null +++ b/lib/providers/settings/client_settings_provider.dart @@ -0,0 +1,54 @@ +import 'package:fladder/models/settings/client_settings_model.dart'; +import 'package:fladder/providers/shared_provider.dart'; +import 'package:fladder/util/custom_color_themes.dart'; +import 'package:fladder/util/debouncer.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +final clientSettingsProvider = StateNotifierProvider((ref) { + return ClientSettingsNotifier(ref); +}); + +class ClientSettingsNotifier extends StateNotifier { + ClientSettingsNotifier(this.ref) : super(ClientSettingsModel()); + + final Ref ref; + + final Debouncer _debouncer = Debouncer(const Duration(seconds: 1)); + + @override + set state(ClientSettingsModel value) { + super.state = value; + _debouncer.run(() => ref.read(sharedUtilityProvider).clientSettings = state); + } + + void setWindowPosition(Offset windowPosition) => + state = state.copyWith(position: Vector2.fromPosition(windowPosition)); + + void setWindowSize(Size windowSize) => state = state.copyWith(size: Vector2.fromSize(windowSize)); + + void setThemeMode(ThemeMode? themeMode) { + if (themeMode == null) return; + state = state.copyWith(themeMode: themeMode); + } + + void setThemeColor(ColorThemes? themeColor) => state = state.copyWith(themeColor: themeColor); + + void setAmoledBlack(bool? value) => state = state.copyWith(amoledBlack: value ?? false); + + void setBlurPlaceholders(bool value) => state = state.copyWith(blurPlaceHolders: value); + + void setTimeOut(Duration? duration) => state = state.copyWith(timeOut: duration); + + void setBlurEpisodes(bool value) => state = state.copyWith(blurUpcomingEpisodes: value); + + void setMediaKeys(bool value) => state = state.copyWith(enableMediaKeys: value); + + void setPosterSize(double value) => state = state.copyWith(posterSize: value.clamp(0.5, 1.5)); + + void addPosterSize(double value) => state = state.copyWith(posterSize: (state.posterSize + value).clamp(0.5, 1.5)); + + void setSyncPath(String? path) => state = state.copyWith(syncPath: path); + + void update(Function(ClientSettingsModel current) value) => state = value(state); +} diff --git a/lib/providers/settings/home_settings_provider.dart b/lib/providers/settings/home_settings_provider.dart new file mode 100644 index 0000000..63f8fcd --- /dev/null +++ b/lib/providers/settings/home_settings_provider.dart @@ -0,0 +1,21 @@ +import 'package:fladder/models/settings/home_settings_model.dart'; +import 'package:fladder/providers/shared_provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +final homeSettingsProvider = StateNotifierProvider((ref) { + return HomeSettingsNotifier(ref); +}); + +class HomeSettingsNotifier extends StateNotifier { + HomeSettingsNotifier(this.ref) : super(HomeSettingsModel()); + + final Ref ref; + + @override + set state(HomeSettingsModel value) { + super.state = value; + ref.read(sharedUtilityProvider).homeSettings = value; + } + + update(HomeSettingsModel Function(HomeSettingsModel currentState) value) => state = value(state); +} diff --git a/lib/providers/settings/photo_view_settings_provider.dart b/lib/providers/settings/photo_view_settings_provider.dart new file mode 100644 index 0000000..96b9b63 --- /dev/null +++ b/lib/providers/settings/photo_view_settings_provider.dart @@ -0,0 +1,82 @@ +import 'dart:convert'; + +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/providers/shared_provider.dart'; + +class PhotoViewSettingsModel { + final bool repeat; + final bool mute; + final bool autoPlay; + final bool theaterMode; + final Duration timer; + PhotoViewSettingsModel({ + this.repeat = true, + this.mute = false, + this.autoPlay = false, + this.theaterMode = false, + this.timer = const Duration(seconds: 15), + }); + + PhotoViewSettingsModel copyWith({ + bool? repeat, + bool? mute, + bool? autoPlay, + bool? theaterMode, + Duration? timer, + }) { + return PhotoViewSettingsModel( + repeat: repeat ?? this.repeat, + mute: mute ?? this.mute, + autoPlay: autoPlay ?? this.autoPlay, + theaterMode: theaterMode ?? this.theaterMode, + timer: timer ?? this.timer, + ); + } + + Map toMap() { + return { + 'repeat': repeat, + 'mute': mute, + 'autoPlay': autoPlay, + 'theaterMode': theaterMode, + 'timer': timer.inMilliseconds, + }; + } + + factory PhotoViewSettingsModel.fromMap(Map map) { + return PhotoViewSettingsModel( + repeat: map['repeat'] ?? false, + mute: map['mute'] ?? false, + autoPlay: map['autoPlay'] ?? false, + theaterMode: map['theaterMode'] ?? false, + timer: map['timer'] != null ? Duration(milliseconds: map['timer'] as int) : const Duration(seconds: 15), + ); + } + + String toJson() => json.encode(toMap()); + + factory PhotoViewSettingsModel.fromJson(String source) => PhotoViewSettingsModel.fromMap(json.decode(source)); +} + +final photoViewSettingsProvider = StateNotifierProvider((ref) { + return PhotoViewSettingsNotifier(ref); +}); + +final testProviderProvider = StateProvider((ref) { + return 0; +}); + +class PhotoViewSettingsNotifier extends StateNotifier { + PhotoViewSettingsNotifier(this.ref) : super(PhotoViewSettingsModel()); + + final Ref ref; + + @override + set state(PhotoViewSettingsModel value) { + super.state = value; + ref.read(sharedUtilityProvider).photoViewSettings = value; + } + + PhotoViewSettingsModel update(PhotoViewSettingsModel Function(PhotoViewSettingsModel state) cb) => state = cb(state); +} diff --git a/lib/providers/settings/subtitle_settings_provider.dart b/lib/providers/settings/subtitle_settings_provider.dart new file mode 100644 index 0000000..2bc89cc --- /dev/null +++ b/lib/providers/settings/subtitle_settings_provider.dart @@ -0,0 +1,40 @@ +import 'dart:ui'; + +import 'package:fladder/models/settings/subtitle_settings_model.dart'; +import 'package:fladder/providers/shared_provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +final subtitleSettingsProvider = StateNotifierProvider((ref) { + return SubtitleSettingsNotifier(ref); +}); + +class SubtitleSettingsNotifier extends StateNotifier { + SubtitleSettingsNotifier(this.ref) : super(const SubtitleSettingsModel()); + + final Ref ref; + + @override + set state(SubtitleSettingsModel value) { + super.state = value; + ref.read(sharedUtilityProvider).subtitleSettings = value; + } + + void setFontSize(double value) => state = state.copyWith(fontSize: value); + + void setVerticalOffset(double value) => state = state.copyWith(verticalOffset: value); + + void setSubColor(Color color) => state = state.copyWith(color: color); + + void setOutlineColor(Color e) => state = state.copyWith(outlineColor: e); + + setOutlineThickness(double value) => state = state.copyWith(outlineSize: value); + + void resetSettings({SubtitleSettingsModel? value}) => state = value ?? const SubtitleSettingsModel(); + + void setFontWeight(FontWeight? value) => state = state.copyWith(fontWeight: value); + + setBackGroundOpacity(double value) => + state = state.copyWith(backGroundColor: state.backGroundColor.withOpacity(value)); + + setShadowIntensity(double value) => state = state.copyWith(shadow: value); +} diff --git a/lib/providers/settings/video_player_settings_provider.dart b/lib/providers/settings/video_player_settings_provider.dart new file mode 100644 index 0000000..744e83e --- /dev/null +++ b/lib/providers/settings/video_player_settings_provider.dart @@ -0,0 +1,57 @@ +import 'package:fladder/models/settings/video_player_settings.dart'; +import 'package:fladder/providers/shared_provider.dart'; +import 'package:fladder/providers/video_player_provider.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:screen_brightness/screen_brightness.dart'; + +final videoPlayerSettingsProvider = + StateNotifierProvider((ref) { + return VideoPlayerSettingsProviderNotifier(ref); +}); + +class VideoPlayerSettingsProviderNotifier extends StateNotifier { + VideoPlayerSettingsProviderNotifier(this.ref) : super(const VideoPlayerSettingsModel()); + + final Ref ref; + + @override + set state(VideoPlayerSettingsModel value) { + final oldState = super.state; + super.state = value; + ref.read(sharedUtilityProvider).videoPlayerSettings = value; + if (!oldState.playerSame(value)) { + ref.read(videoPlayerProvider.notifier).init(); + } + } + + void setScreenBrightness(double? value) async { + state = state.copyWith( + screenBrightness: () => value, + ); + if (state.screenBrightness != null) { + ScreenBrightness().setScreenBrightness(state.screenBrightness!); + } else { + ScreenBrightness().resetScreenBrightness(); + } + } + + setSavedBrightness() { + if (state.screenBrightness != null) { + ScreenBrightness().setScreenBrightness(state.screenBrightness!); + } + } + + void setFillScreen(bool? value, {BuildContext? context}) { + state = state.copyWith(fillScreen: value); + } + + void setHardwareAccel(bool? value) => state = state.copyWith(hardwareAccel: value); + void setUseLibass(bool? value) => state = state.copyWith(useLibass: value); + + void setFitType(BoxFit? value) => state = state.copyWith(videoFit: value); + + void setVolume(double value) => state = state.copyWith(internalVolume: value); + + void steppedVolume(int i) => state = state.copyWith(internalVolume: (state.volume + i).clamp(0, 100)); +} diff --git a/lib/providers/shared_provider.dart b/lib/providers/shared_provider.dart new file mode 100644 index 0000000..f025a3f --- /dev/null +++ b/lib/providers/shared_provider.dart @@ -0,0 +1,202 @@ +import 'dart:convert'; +import 'dart:developer'; + +import 'package:fladder/models/account_model.dart'; +import 'package:fladder/models/settings/client_settings_model.dart'; +import 'package:fladder/models/settings/home_settings_model.dart'; +import 'package:fladder/models/settings/subtitle_settings_model.dart'; +import 'package:fladder/models/settings/video_player_settings.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:fladder/providers/service_provider.dart'; +import 'package:fladder/providers/settings/book_viewer_settings_provider.dart'; +import 'package:fladder/providers/settings/client_settings_provider.dart'; +import 'package:fladder/providers/settings/home_settings_provider.dart'; +import 'package:fladder/providers/settings/photo_view_settings_provider.dart'; +import 'package:fladder/providers/settings/subtitle_settings_provider.dart'; +import 'package:fladder/providers/settings/video_player_settings_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +final sharedPreferencesProvider = Provider((ref) { + throw UnimplementedError(); +}); + +final sharedUtilityProvider = Provider((ref) { + final sharedPrefs = ref.watch(sharedPreferencesProvider); + return SharedUtility(ref: ref, sharedPreferences: sharedPrefs); +}); + +class SharedUtility { + SharedUtility({ + required this.ref, + required this.sharedPreferences, + }); + + final Ref ref; + + final SharedPreferences sharedPreferences; + + late final JellyService api = ref.read(jellyApiProvider); + + Future loadSettings() async { + try { + ref.read(clientSettingsProvider.notifier).state = clientSettings; + ref.read(homeSettingsProvider.notifier).state = homeSettings; + ref.read(videoPlayerSettingsProvider.notifier).state = videoPlayerSettings; + ref.read(subtitleSettingsProvider.notifier).state = subtitleSettings; + ref.read(bookViewerSettingsProvider.notifier).state = bookViewSettings; + ref.read(photoViewSettingsProvider.notifier).state = photoViewSettings; + return true; + } catch (e) { + return false; + } + } + + Future addAccount(AccountModel account) async { + return await saveAccounts(getAccounts() + ..add(account.copyWith( + lastUsed: DateTime.now(), + ))); + } + + Future removeAccount(AccountModel? account) async { + if (account == null) return null; + + //Try to logout user + await ref.read(userProvider.notifier).forceLogoutUser(account); + + //Remove from local database + final savedAccounts = getAccounts(); + savedAccounts.removeWhere((element) { + return element.sameIdentity(account); + }); + return (await saveAccounts(savedAccounts)); + } + + List getAccounts() { + final savedAccounts = sharedPreferences.getStringList(_loginCredentialsKey); + try { + return savedAccounts != null ? savedAccounts.map((e) => AccountModel.fromJson(jsonDecode(e))).toList() : []; + } catch (_, stacktrace) { + log(stacktrace.toString()); + return []; + } + } + + AccountModel? getActiveAccount() { + try { + final accounts = getAccounts(); + AccountModel recentUsedAccount = accounts.reduce((lastLoggedIn, element) { + return (element.lastUsed.compareTo(lastLoggedIn.lastUsed)) > 0 ? element : lastLoggedIn; + }); + + if (recentUsedAccount.authMethod == Authentication.autoLogin) return recentUsedAccount; + return null; + } catch (e) { + log(e.toString()); + return null; + } + } + + Future saveAccounts(List accounts) async => + sharedPreferences.setStringList(_loginCredentialsKey, accounts.map((e) => jsonEncode(e)).toList()); + + ClientSettingsModel get clientSettings { + try { + return ClientSettingsModel.fromJson(jsonDecode(sharedPreferences.getString(_clientSettingsKey) ?? "")); + } catch (e) { + log(e.toString()); + return ClientSettingsModel(); + } + } + + set clientSettings(ClientSettingsModel settings) => + sharedPreferences.setString(_clientSettingsKey, jsonEncode(settings.toJson())); + + HomeSettingsModel get homeSettings { + try { + return HomeSettingsModel.fromJson(sharedPreferences.getString(_homeSettingsKey) ?? ""); + } catch (e) { + log(e.toString()); + return HomeSettingsModel(); + } + } + + set homeSettings(HomeSettingsModel settings) => sharedPreferences.setString(_homeSettingsKey, settings.toJson()); + + BookViewerSettingsModel get bookViewSettings { + try { + return BookViewerSettingsModel.fromJson(sharedPreferences.getString(_bookViewSettingsKey) ?? ""); + } catch (e) { + log(e.toString()); + return BookViewerSettingsModel(); + } + } + + set bookViewSettings(BookViewerSettingsModel settings) { + sharedPreferences.setString(_bookViewSettingsKey, settings.toJson()); + } + + Future updateAccountInfo(AccountModel account) async { + final accounts = getAccounts(); + await Future.microtask(() async { + await saveAccounts(accounts.map((e) { + if (e.sameIdentity(account)) { + return account.copyWith( + lastUsed: DateTime.now(), + ); + } else { + return e; + } + }).toList()); + }); + } + + SubtitleSettingsModel get subtitleSettings { + try { + return SubtitleSettingsModel.fromJson(sharedPreferences.getString(_subtitleSettingsKey) ?? ""); + } catch (e) { + log(e.toString()); + return const SubtitleSettingsModel(); + } + } + + set subtitleSettings(SubtitleSettingsModel settings) { + sharedPreferences.setString(_subtitleSettingsKey, settings.toJson()); + } + + VideoPlayerSettingsModel get videoPlayerSettings { + try { + return VideoPlayerSettingsModel.fromJson(sharedPreferences.getString(_videoPlayerSettingsKey) ?? ""); + } catch (e) { + log(e.toString()); + return const VideoPlayerSettingsModel(); + } + } + + set videoPlayerSettings(VideoPlayerSettingsModel settings) { + sharedPreferences.setString(_videoPlayerSettingsKey, settings.toJson()); + } + + PhotoViewSettingsModel get photoViewSettings { + try { + return PhotoViewSettingsModel.fromJson(sharedPreferences.getString(_photoViewSettingsKey) ?? ""); + } catch (e) { + log(e.toString()); + return PhotoViewSettingsModel(); + } + } + + set photoViewSettings(PhotoViewSettingsModel settings) { + sharedPreferences.setString(_photoViewSettingsKey, settings.toJson()); + } +} + +const String _loginCredentialsKey = 'loginCredentialsKey'; +const String _clientSettingsKey = 'clientSettings'; +const String _homeSettingsKey = 'homeSettings'; +const String _videoPlayerSettingsKey = 'videoPlayerSettings'; +const String _subtitleSettingsKey = 'subtitleSettings'; +const String _bookViewSettingsKey = 'bookViewSettings'; +const String _photoViewSettingsKey = 'photoViewSettings'; diff --git a/lib/providers/sync/background_download_provider.dart b/lib/providers/sync/background_download_provider.dart new file mode 100644 index 0000000..f29b3b8 --- /dev/null +++ b/lib/providers/sync/background_download_provider.dart @@ -0,0 +1,16 @@ +import 'package:background_downloader/background_downloader.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +part 'background_download_provider.g.dart'; + +@Riverpod(keepAlive: true) +FileDownloader backgroundDownloader(BackgroundDownloaderRef ref) { + return FileDownloader() + ..trackTasks() + ..configureNotification( + running: TaskNotification('Downloading', 'file: {filename}'), + complete: TaskNotification('Download finished', 'file: {filename}'), + paused: TaskNotification('Download paused', 'file: {filename}'), + progressBar: true, + ); +} diff --git a/lib/providers/sync/background_download_provider.g.dart b/lib/providers/sync/background_download_provider.g.dart new file mode 100644 index 0000000..f484457 --- /dev/null +++ b/lib/providers/sync/background_download_provider.g.dart @@ -0,0 +1,26 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'background_download_provider.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$backgroundDownloaderHash() => + r'2bc7a06682cdcfa9a754dce9b7f7ea48f873682e'; + +/// See also [backgroundDownloader]. +@ProviderFor(backgroundDownloader) +final backgroundDownloaderProvider = Provider.internal( + backgroundDownloader, + name: r'backgroundDownloaderProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$backgroundDownloaderHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef BackgroundDownloaderRef = ProviderRef; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member diff --git a/lib/providers/sync/sync_provider_helpers.dart b/lib/providers/sync/sync_provider_helpers.dart new file mode 100644 index 0000000..5c2a0c0 --- /dev/null +++ b/lib/providers/sync/sync_provider_helpers.dart @@ -0,0 +1,104 @@ +import 'package:fladder/models/syncing/i_synced_item.dart'; +import 'package:fladder/providers/sync_provider.dart'; + +import 'package:fladder/models/syncing/download_stream.dart'; +import 'package:fladder/models/syncing/sync_item.dart'; +import 'package:isar/isar.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +part 'sync_provider_helpers.g.dart'; + +@riverpod +class SyncChildren extends _$SyncChildren { + @override + List build(SyncedItem arg) { + final syncedItemIsar = ref.watch(syncProvider.notifier).isar; + final allChildren = []; + List toProcess = [arg]; + while (toProcess.isNotEmpty) { + final currentLevel = toProcess.map( + (parent) { + final children = syncedItemIsar?.iSyncedItems.where().parentIdEqualTo(parent.id).sortBySortKey().findAll(); + return children?.map((e) => SyncedItem.fromIsar(e, ref.read(syncProvider.notifier).syncPath ?? "")) ?? + []; + }, + ); + allChildren.addAll(currentLevel.expand((list) => list)); + toProcess = currentLevel.expand((list) => list).toList(); + } + return allChildren; + } +} + +@riverpod +class SyncDownloadStatus extends _$SyncDownloadStatus { + @override + DownloadStream? build(SyncedItem arg) { + final nestedChildren = ref.watch(syncChildrenProvider(arg)); + + ref.watch(downloadTasksProvider(arg.id)); + for (var element in nestedChildren) { + ref.watch(downloadTasksProvider(element.id)); + } + + DownloadStream mainStream = ref.read(downloadTasksProvider(arg.id)); + int downloadCount = 0; + double fullProgress = mainStream.hasDownload ? mainStream.progress : 0.0; + + for (var i = 0; i < nestedChildren.length; i++) { + final childItem = nestedChildren[i]; + final downloadStream = ref.read(downloadTasksProvider(childItem.id)); + if (downloadStream.hasDownload) { + downloadCount++; + fullProgress += downloadStream.progress; + mainStream = mainStream.copyWith(status: downloadStream.status); + } + } + + return mainStream.copyWith( + progress: fullProgress / downloadCount.clamp(1, double.infinity).toInt(), + ); + } +} + +@riverpod +class SyncStatuses extends _$SyncStatuses { + @override + FutureOr build(SyncedItem arg) async { + final nestedChildren = ref.watch(syncChildrenProvider(arg)); + + ref.watch(downloadTasksProvider(arg.id)); + for (var element in nestedChildren) { + ref.watch(downloadTasksProvider(element.id)); + } + + for (var i = 0; i < nestedChildren.length; i++) { + final item = nestedChildren[i]; + if (item.hasVideoFile && !await item.videoFile.exists()) { + return SyncStatus.partially; + } + } + if (arg.hasVideoFile && !await arg.videoFile.exists()) { + return SyncStatus.partially; + } + return SyncStatus.complete; + } +} + +@riverpod +class SyncSize extends _$SyncSize { + @override + int? build(SyncedItem arg) { + final nestedChildren = ref.watch(syncChildrenProvider(arg)); + + ref.watch(downloadTasksProvider(arg.id)); + for (var element in nestedChildren) { + ref.watch(downloadTasksProvider(element.id)); + } + int size = arg.fileSize ?? 0; + for (var element in nestedChildren) { + size += element.fileSize ?? 0; + } + return size; + } +} diff --git a/lib/providers/sync/sync_provider_helpers.g.dart b/lib/providers/sync/sync_provider_helpers.g.dart new file mode 100644 index 0000000..b10b68a --- /dev/null +++ b/lib/providers/sync/sync_provider_helpers.g.dart @@ -0,0 +1,603 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'sync_provider_helpers.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$syncChildrenHash() => r'798a9998103adae18a238a69219559f3ccbf3def'; + +/// Copied from Dart SDK +class _SystemHash { + _SystemHash._(); + + static int combine(int hash, int value) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + value); + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); + return hash ^ (hash >> 6); + } + + static int finish(int hash) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); + // ignore: parameter_assignments + hash = hash ^ (hash >> 11); + return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); + } +} + +abstract class _$SyncChildren + extends BuildlessAutoDisposeNotifier> { + late final SyncedItem arg; + + List build( + SyncedItem arg, + ); +} + +/// See also [SyncChildren]. +@ProviderFor(SyncChildren) +const syncChildrenProvider = SyncChildrenFamily(); + +/// See also [SyncChildren]. +class SyncChildrenFamily extends Family> { + /// See also [SyncChildren]. + const SyncChildrenFamily(); + + /// See also [SyncChildren]. + SyncChildrenProvider call( + SyncedItem arg, + ) { + return SyncChildrenProvider( + arg, + ); + } + + @override + SyncChildrenProvider getProviderOverride( + covariant SyncChildrenProvider provider, + ) { + return call( + provider.arg, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'syncChildrenProvider'; +} + +/// See also [SyncChildren]. +class SyncChildrenProvider + extends AutoDisposeNotifierProviderImpl> { + /// See also [SyncChildren]. + SyncChildrenProvider( + SyncedItem arg, + ) : this._internal( + () => SyncChildren()..arg = arg, + from: syncChildrenProvider, + name: r'syncChildrenProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$syncChildrenHash, + dependencies: SyncChildrenFamily._dependencies, + allTransitiveDependencies: + SyncChildrenFamily._allTransitiveDependencies, + arg: arg, + ); + + SyncChildrenProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.arg, + }) : super.internal(); + + final SyncedItem arg; + + @override + List runNotifierBuild( + covariant SyncChildren notifier, + ) { + return notifier.build( + arg, + ); + } + + @override + Override overrideWith(SyncChildren Function() create) { + return ProviderOverride( + origin: this, + override: SyncChildrenProvider._internal( + () => create()..arg = arg, + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + arg: arg, + ), + ); + } + + @override + AutoDisposeNotifierProviderElement> + createElement() { + return _SyncChildrenProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is SyncChildrenProvider && other.arg == arg; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, arg.hashCode); + + return _SystemHash.finish(hash); + } +} + +mixin SyncChildrenRef on AutoDisposeNotifierProviderRef> { + /// The parameter `arg` of this provider. + SyncedItem get arg; +} + +class _SyncChildrenProviderElement + extends AutoDisposeNotifierProviderElement> + with SyncChildrenRef { + _SyncChildrenProviderElement(super.provider); + + @override + SyncedItem get arg => (origin as SyncChildrenProvider).arg; +} + +String _$syncDownloadStatusHash() => + r'5a0f8537a977c52e6083bd84265631ea5d160637'; + +abstract class _$SyncDownloadStatus + extends BuildlessAutoDisposeNotifier { + late final SyncedItem arg; + + DownloadStream? build( + SyncedItem arg, + ); +} + +/// See also [SyncDownloadStatus]. +@ProviderFor(SyncDownloadStatus) +const syncDownloadStatusProvider = SyncDownloadStatusFamily(); + +/// See also [SyncDownloadStatus]. +class SyncDownloadStatusFamily extends Family { + /// See also [SyncDownloadStatus]. + const SyncDownloadStatusFamily(); + + /// See also [SyncDownloadStatus]. + SyncDownloadStatusProvider call( + SyncedItem arg, + ) { + return SyncDownloadStatusProvider( + arg, + ); + } + + @override + SyncDownloadStatusProvider getProviderOverride( + covariant SyncDownloadStatusProvider provider, + ) { + return call( + provider.arg, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'syncDownloadStatusProvider'; +} + +/// See also [SyncDownloadStatus]. +class SyncDownloadStatusProvider extends AutoDisposeNotifierProviderImpl< + SyncDownloadStatus, DownloadStream?> { + /// See also [SyncDownloadStatus]. + SyncDownloadStatusProvider( + SyncedItem arg, + ) : this._internal( + () => SyncDownloadStatus()..arg = arg, + from: syncDownloadStatusProvider, + name: r'syncDownloadStatusProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$syncDownloadStatusHash, + dependencies: SyncDownloadStatusFamily._dependencies, + allTransitiveDependencies: + SyncDownloadStatusFamily._allTransitiveDependencies, + arg: arg, + ); + + SyncDownloadStatusProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.arg, + }) : super.internal(); + + final SyncedItem arg; + + @override + DownloadStream? runNotifierBuild( + covariant SyncDownloadStatus notifier, + ) { + return notifier.build( + arg, + ); + } + + @override + Override overrideWith(SyncDownloadStatus Function() create) { + return ProviderOverride( + origin: this, + override: SyncDownloadStatusProvider._internal( + () => create()..arg = arg, + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + arg: arg, + ), + ); + } + + @override + AutoDisposeNotifierProviderElement + createElement() { + return _SyncDownloadStatusProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is SyncDownloadStatusProvider && other.arg == arg; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, arg.hashCode); + + return _SystemHash.finish(hash); + } +} + +mixin SyncDownloadStatusRef on AutoDisposeNotifierProviderRef { + /// The parameter `arg` of this provider. + SyncedItem get arg; +} + +class _SyncDownloadStatusProviderElement + extends AutoDisposeNotifierProviderElement with SyncDownloadStatusRef { + _SyncDownloadStatusProviderElement(super.provider); + + @override + SyncedItem get arg => (origin as SyncDownloadStatusProvider).arg; +} + +String _$syncStatusesHash() => r'f05ee53368d1de130714bba09132e08aba15bc44'; + +abstract class _$SyncStatuses + extends BuildlessAutoDisposeAsyncNotifier { + late final SyncedItem arg; + + FutureOr build( + SyncedItem arg, + ); +} + +/// See also [SyncStatuses]. +@ProviderFor(SyncStatuses) +const syncStatusesProvider = SyncStatusesFamily(); + +/// See also [SyncStatuses]. +class SyncStatusesFamily extends Family> { + /// See also [SyncStatuses]. + const SyncStatusesFamily(); + + /// See also [SyncStatuses]. + SyncStatusesProvider call( + SyncedItem arg, + ) { + return SyncStatusesProvider( + arg, + ); + } + + @override + SyncStatusesProvider getProviderOverride( + covariant SyncStatusesProvider provider, + ) { + return call( + provider.arg, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'syncStatusesProvider'; +} + +/// See also [SyncStatuses]. +class SyncStatusesProvider + extends AutoDisposeAsyncNotifierProviderImpl { + /// See also [SyncStatuses]. + SyncStatusesProvider( + SyncedItem arg, + ) : this._internal( + () => SyncStatuses()..arg = arg, + from: syncStatusesProvider, + name: r'syncStatusesProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$syncStatusesHash, + dependencies: SyncStatusesFamily._dependencies, + allTransitiveDependencies: + SyncStatusesFamily._allTransitiveDependencies, + arg: arg, + ); + + SyncStatusesProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.arg, + }) : super.internal(); + + final SyncedItem arg; + + @override + FutureOr runNotifierBuild( + covariant SyncStatuses notifier, + ) { + return notifier.build( + arg, + ); + } + + @override + Override overrideWith(SyncStatuses Function() create) { + return ProviderOverride( + origin: this, + override: SyncStatusesProvider._internal( + () => create()..arg = arg, + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + arg: arg, + ), + ); + } + + @override + AutoDisposeAsyncNotifierProviderElement + createElement() { + return _SyncStatusesProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is SyncStatusesProvider && other.arg == arg; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, arg.hashCode); + + return _SystemHash.finish(hash); + } +} + +mixin SyncStatusesRef on AutoDisposeAsyncNotifierProviderRef { + /// The parameter `arg` of this provider. + SyncedItem get arg; +} + +class _SyncStatusesProviderElement + extends AutoDisposeAsyncNotifierProviderElement + with SyncStatusesRef { + _SyncStatusesProviderElement(super.provider); + + @override + SyncedItem get arg => (origin as SyncStatusesProvider).arg; +} + +String _$syncSizeHash() => r'138702f2dd69ab28d142bab67ab4a497bb24f252'; + +abstract class _$SyncSize extends BuildlessAutoDisposeNotifier { + late final SyncedItem arg; + + int? build( + SyncedItem arg, + ); +} + +/// See also [SyncSize]. +@ProviderFor(SyncSize) +const syncSizeProvider = SyncSizeFamily(); + +/// See also [SyncSize]. +class SyncSizeFamily extends Family { + /// See also [SyncSize]. + const SyncSizeFamily(); + + /// See also [SyncSize]. + SyncSizeProvider call( + SyncedItem arg, + ) { + return SyncSizeProvider( + arg, + ); + } + + @override + SyncSizeProvider getProviderOverride( + covariant SyncSizeProvider provider, + ) { + return call( + provider.arg, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'syncSizeProvider'; +} + +/// See also [SyncSize]. +class SyncSizeProvider extends AutoDisposeNotifierProviderImpl { + /// See also [SyncSize]. + SyncSizeProvider( + SyncedItem arg, + ) : this._internal( + () => SyncSize()..arg = arg, + from: syncSizeProvider, + name: r'syncSizeProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$syncSizeHash, + dependencies: SyncSizeFamily._dependencies, + allTransitiveDependencies: SyncSizeFamily._allTransitiveDependencies, + arg: arg, + ); + + SyncSizeProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.arg, + }) : super.internal(); + + final SyncedItem arg; + + @override + int? runNotifierBuild( + covariant SyncSize notifier, + ) { + return notifier.build( + arg, + ); + } + + @override + Override overrideWith(SyncSize Function() create) { + return ProviderOverride( + origin: this, + override: SyncSizeProvider._internal( + () => create()..arg = arg, + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + arg: arg, + ), + ); + } + + @override + AutoDisposeNotifierProviderElement createElement() { + return _SyncSizeProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is SyncSizeProvider && other.arg == arg; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, arg.hashCode); + + return _SystemHash.finish(hash); + } +} + +mixin SyncSizeRef on AutoDisposeNotifierProviderRef { + /// The parameter `arg` of this provider. + SyncedItem get arg; +} + +class _SyncSizeProviderElement + extends AutoDisposeNotifierProviderElement + with SyncSizeRef { + _SyncSizeProviderElement(super.provider); + + @override + SyncedItem get arg => (origin as SyncSizeProvider).arg; +} +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member diff --git a/lib/providers/sync_provider.dart b/lib/providers/sync_provider.dart new file mode 100644 index 0000000..9b1c369 --- /dev/null +++ b/lib/providers/sync_provider.dart @@ -0,0 +1,627 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:developer'; +import 'dart:io'; + +import 'package:background_downloader/background_downloader.dart'; +import 'package:collection/collection.dart'; +import 'package:file_picker/file_picker.dart'; +import 'package:fladder/models/items/chapters_model.dart'; +import 'package:fladder/models/items/movie_model.dart'; +import 'package:fladder/models/items/trick_play_model.dart'; +import 'package:fladder/models/syncing/download_stream.dart'; +import 'package:fladder/models/syncing/i_synced_item.dart'; +import 'package:fladder/models/syncing/sync_item.dart'; +import 'package:fladder/models/syncing/sync_settings_model.dart'; +import 'package:fladder/providers/service_provider.dart'; +import 'package:fladder/providers/settings/client_settings_provider.dart'; +import 'package:fladder/providers/sync/background_download_provider.dart'; +import 'package:fladder/screens/shared/fladder_snackbar.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:http/http.dart' as http; +import 'package:isar/isar.dart'; +import 'package:path/path.dart' as path; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/episode_model.dart'; +import 'package:fladder/models/items/images_models.dart'; +import 'package:fladder/models/items/media_streams_model.dart'; +import 'package:fladder/models/items/series_model.dart'; +import 'package:fladder/models/video_stream_model.dart'; +import 'package:fladder/profiles/default_profile.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; + +final syncProvider = StateNotifierProvider((ref) => throw UnimplementedError()); + +final downloadTasksProvider = StateProvider.family((ref, id) => DownloadStream.empty()); + +class SyncNotifier extends StateNotifier { + SyncNotifier(this.ref, this.isar, this.mobileDirectory) : super(SyncSettingsModel()) { + _init(); + } + + void _init() { + ref.listen( + userProvider, + (previous, next) { + if (previous?.id != next?.id) { + if (next?.id != null) { + _initializeQueryStream(next?.id ?? ""); + } + } + }, + ); + + final userId = ref.read(userProvider)?.id; + if (userId != null) { + _initializeQueryStream(userId); + } + } + + void _initializeQueryStream(String userId) { + _subscription?.cancel(); + + final queryStream = getParentSyncItems + ?.userIdEqualTo(userId) + .watch() + .asyncMap((event) => event.map((e) => SyncedItem.fromIsar(e, syncPath ?? "")).toList()); + + final initItems = getParentSyncItems + ?.userIdEqualTo(userId) + .findAll() + .mapIndexed((index, element) => SyncedItem.fromIsar(element, syncPath ?? "")) + .toList(); + + state = state.copyWith(items: initItems ?? []); + + _subscription = queryStream?.listen((items) { + state = state.copyWith(items: items); + }); + } + + final Ref ref; + final Isar? isar; + final Directory mobileDirectory; + final String subPath = "Synced"; + + StreamSubscription>? _subscription; + + IsarCollection? get syncedItems => isar?.iSyncedItems; + + late final JellyService api = ref.read(jellyApiProvider); + + String? get _savePath => !kIsWeb && (Platform.isWindows || Platform.isLinux || Platform.isMacOS) + ? ref.read(clientSettingsProvider.select((value) => value.syncPath)) + : mobileDirectory.path; + + String? get savePath => _savePath; + + Directory get mainDirectory => Directory(path.joinAll([_savePath ?? "", subPath])); + + Directory? get saveDirectory { + if (kIsWeb) return null; + final directory = _savePath != null + ? Directory(path.joinAll([_savePath ?? "", subPath, ref.read(userProvider)?.id ?? "UnknownUser"])) + : null; + directory?.createSync(recursive: true); + if (directory?.existsSync() == true) { + final noMedia = File(path.joinAll([directory?.path ?? "", ".nomedia"])); + noMedia.writeAsString(''); + } + return directory; + } + + String? get syncPath => saveDirectory?.path; + + QueryBuilder? get getParentSyncItems => + syncedItems?.where().parentIdIsNull(); + + Future get directorySize async { + if (saveDirectory == null) return 0; + var files = await saveDirectory!.list(recursive: true).toList(); + var dirSize = files.fold(0, (int sum, file) => sum + file.statSync().size); + return dirSize; + } + + @override + void dispose() { + _subscription?.cancel(); + super.dispose(); + } + + Future refresh() async { + state = state.copyWith( + items: (await getParentSyncItems?.userIdEqualTo(ref.read(userProvider)?.id).findAllAsync()) + ?.map((e) => SyncedItem.fromIsar(e, syncPath ?? "")) + .toList() ?? + []); + } + + List getNestedChildren(SyncedItem item) { + final allChildren = []; + List toProcess = [item]; + while (toProcess.isNotEmpty) { + final currentLevel = toProcess.map( + (parent) { + final children = syncedItems?.where().parentIdEqualTo(parent.id).sortBySortKey().findAll(); + return children?.map((e) => SyncedItem.fromIsar(e, ref.read(syncProvider.notifier).syncPath ?? "")) ?? + []; + }, + ); + allChildren.addAll(currentLevel.expand((list) => list)); + toProcess = currentLevel.expand((list) => list).toList(); + } + return allChildren; + } + + List getChildren(SyncedItem item) { + return (syncedItems?.where().parentIdEqualTo(item.id).sortBySortKey().findAll()) + ?.map( + (e) => SyncedItem.fromIsar(e, syncPath ?? ""), + ) + .toList() ?? + []; + } + + SyncedItem? getSyncedItem(ItemBaseModel? item) { + final id = item?.id; + if (id == null) return null; + final newItem = syncedItems?.get(id); + if (newItem == null) return null; + return SyncedItem.fromIsar(newItem, syncPath ?? ""); + } + + SyncedItem? getParentItem(String id) { + ISyncedItem? newItem = syncedItems?.get(id); + while (newItem?.parentId != null) { + newItem = syncedItems?.get(newItem!.parentId!); + } + if (newItem == null) return null; + return SyncedItem.fromIsar(newItem, syncPath ?? ""); + } + + ItemBaseModel? getItem(SyncedItem? syncedItem) { + if (syncedItem == null) return null; + return syncedItem.createItemModel(ref); + } + + Future addSyncItem(BuildContext? context, ItemBaseModel item) async { + if (context == null) return null; + + if (saveDirectory == null) { + String? selectedDirectory = await FilePicker.platform.getDirectoryPath(dialogTitle: 'Select downloads folder'); + if (selectedDirectory?.isEmpty == true) { + fladderSnackbar(context, title: "No sync folder setup"); + return null; + } + ref.read(clientSettingsProvider.notifier).setSyncPath(selectedDirectory); + } + + fladderSnackbar(context, title: "Added ${item.detailedName(context)} for syncing"); + final newSync = switch (item) { + EpisodeModel episode => await syncSeries(item.parentBaseModel, episode: episode), + SeriesModel series => await syncSeries(series), + MovieModel movie => await syncMovie(movie), + _ => null + }; + fladderSnackbar(context, + title: newSync != null + ? "Started syncing ${item.detailedName(context)}" + : "Unable to sync ${item.detailedName(context)}, type not supported?"); + return newSync; + } + + Future removeSync(SyncedItem? item) async { + try { + if (item == null) return false; + + final nestedChildren = getNestedChildren(item); + + state = state.copyWith( + items: state.items + .map( + (e) => e.copyWith(markedForDelete: e.id == item.id ? true : false), + ) + .toList()); + + if (item.taskId != null) { + await ref.read(backgroundDownloaderProvider).cancelTaskWithId(item.taskId!); + } + + final deleteFromDatabase = isar?.write((isar) => syncedItems?.deleteAll([...nestedChildren, item] + .map( + (e) => e.id, + ) + .toList())); + + if (deleteFromDatabase == 0) return false; + + for (var i = 0; i < nestedChildren.length; i++) { + final element = nestedChildren[i]; + if (element.taskId != null) { + await ref.read(backgroundDownloaderProvider).cancelTaskWithId(element.taskId!); + } + if (await element.directory.exists()) { + await element.directory.delete(recursive: true); + } + } + + if (await item.directory.exists()) { + await item.directory.delete(recursive: true); + } + + return true; + } catch (e) { + log('Error deleting synced item'); + log(e.toString()); + return false; + } + } + + //Utility functions + Future> saveExternalSubtitles(List? subtitles, SyncedItem item) async { + if (subtitles == null) return []; + + final directory = item.directory; + + await directory.create(recursive: true); + + return Stream.fromIterable(subtitles).asyncMap((element) async { + if (element.isExternal) { + final response = await http.get(Uri.parse(element.url!)); + + final file = File(path.joinAll([directory.path, "${element.displayTitle}.${element.language}.srt"])); + file.writeAsBytesSync(response.bodyBytes); + return element.copyWith( + url: () => file.path, + ); + } + return element; + }).toList(); + } + + Future saveTrickPlayData(ItemBaseModel? item, Directory saveDirectory) async { + if (item == null) return null; + final trickPlayDirectory = Directory(path.joinAll([saveDirectory.path, SyncedItem.trickPlayPath])) + ..createSync(recursive: true); + final trickPlayData = await api.getTrickPlay(item: item, ref: ref); + final List newStringList = []; + + for (var index = 0; index < (trickPlayData?.body?.images.length ?? 0); index++) { + final image = trickPlayData?.body?.images[index]; + if (image != null) { + final http.Response response = await http.get(Uri.parse(image)); + File? newFile; + final fileName = "tile_$index.jpg"; + if (response.statusCode == 200) { + final Uint8List bytes = response.bodyBytes; + newFile = File(path.joinAll([trickPlayDirectory.path, fileName])); + await newFile.writeAsBytes(bytes); + } + if (newFile != null && await newFile.exists()) { + newStringList.add(path.joinAll(['TrickPlay', fileName])); + } + } + } + return trickPlayData?.body?.copyWith(images: newStringList.toList()); + } + + Future saveImageData(ImagesData? data, Directory saveDirectory) async { + if (data == null) return data; + if (!saveDirectory.existsSync()) return data; + + final primary = await urlDataToFileData(data.primary, saveDirectory, "primary.jpg"); + final logo = await urlDataToFileData(data.logo, saveDirectory, "logo.jpg"); + final backdrops = await Stream.fromIterable(data.backDrop ?? []) + .asyncMap((element) async => await urlDataToFileData(element, saveDirectory, "backdrop-${element.key}.jpg")) + .toList(); + + return data.copyWith( + primary: () => primary, + logo: () => logo, + backDrop: () => backdrops.whereNotNull().toList(), + ); + } + + Future?> saveChapterImages(List? data, Directory itemPath) async { + if (data == null) return data; + if (!itemPath.existsSync()) return data; + if (data.isEmpty) return data; + final saveDirectory = Directory(path.joinAll([itemPath.path, "Chapters"])); + + await saveDirectory.create(recursive: true); + + final saveChapters = await Stream.fromIterable(data).asyncMap((event) async { + final fileName = "${event.name}.jpg"; + final response = await http.get(Uri.parse(event.imageUrl)); + final file = File(path.joinAll([saveDirectory.path, fileName])); + if (response.bodyBytes.isEmpty) return null; + file.writeAsBytesSync(response.bodyBytes); + return event.copyWith( + imageUrl: path.joinAll(["Chapters", fileName]), + ); + }).toList(); + return saveChapters.whereNotNull().toList(); + } + + Future urlDataToFileData(ImageData? data, Directory directory, String fileName) async { + if (data?.path == null) return null; + final response = await http.get(Uri.parse(data?.path ?? "")); + + final file = File(path.joinAll([directory.path, fileName])); + file.writeAsBytesSync(response.bodyBytes); + + return data?.copyWith(path: fileName); + } + + void updateItemSync(SyncedItem syncedItem) => + isar?.write((isar) => syncedItems?.put(ISyncedItem.fromSynced(syncedItem, syncPath ?? ""))); + + Future updateItem(SyncedItem syncedItem) async { + isar?.write((isar) => syncedItems?.put(ISyncedItem.fromSynced(syncedItem, syncPath ?? ""))); + } + + Future deleteFullSyncFiles(SyncedItem syncedItem) async { + await syncedItem.deleteDatFiles(ref); + ref.read(downloadTasksProvider(syncedItem.id).notifier).update((state) => DownloadStream.empty()); + refresh(); + return syncedItem; + } + + Future syncVideoFile(SyncedItem syncItem, bool skipDownload) async { + final playbackResponse = await api.itemsItemIdPlaybackInfoPost( + itemId: syncItem.id, + body: PlaybackInfoDto( + enableDirectPlay: true, + enableDirectStream: true, + enableTranscoding: false, + deviceProfile: defaultProfile, + ), + ); + + final item = syncItem.createItemModel(ref); + + final directory = await Directory(syncItem.directory.path).create(recursive: true); + + final newState = VideoStream.fromPlayBackInfo(playbackResponse.bodyOrThrow, ref)?.copyWith(); + final subtitles = await saveExternalSubtitles(newState?.mediaStreamsModel?.subStreams, syncItem); + + final trickPlayFile = await saveTrickPlayData(item, directory); + final introOutroSkip = (await api.introSkipGet(id: syncItem.id))?.body; + + syncItem = syncItem.copyWith( + subtitles: subtitles, + fTrickPlayModel: trickPlayFile, + introOutSkipModel: introOutroSkip, + ); + + await updateItem(syncItem); + + final currentTask = ref.read(downloadTasksProvider(syncItem.id)); + + final downloadString = path.joinAll([ + "${ref.read(userProvider)?.server}", + "Items", + "${syncItem.id}/Download?api_key=${ref.read(userProvider)?.credentials.token}" + ]); + + try { + if (!skipDownload && currentTask.task == null) { + final downloadTask = DownloadTask( + url: downloadString, + directory: syncItem.directory.path, + filename: syncItem.videoFileName, + updates: Updates.statusAndProgress, + baseDirectory: BaseDirectory.root, + requiresWiFi: true, + retries: 5, + allowPause: true, + ); + + final defaultDownloadStream = + DownloadStream(id: syncItem.id, task: downloadTask, progress: 0.0, status: TaskStatus.enqueued); + + ref.read(downloadTasksProvider(syncItem.id).notifier).update((state) => defaultDownloadStream); + + ref.read(backgroundDownloaderProvider).download( + downloadTask, + onProgress: (progress) { + if (progress > 0 && progress < 1) { + ref.read(downloadTasksProvider(syncItem.id).notifier).update( + (state) => state.copyWith(progress: progress), + ); + } else { + ref.read(downloadTasksProvider(syncItem.id).notifier).update( + (state) => state.copyWith(progress: null), + ); + } + }, + onStatus: (status) { + ref.read(downloadTasksProvider(syncItem.id).notifier).update( + (state) => state.copyWith(status: status), + ); + + if (status == TaskStatus.complete) { + ref.read(downloadTasksProvider(syncItem.id).notifier).update((state) => DownloadStream.empty()); + } + }, + ); + + return defaultDownloadStream; + } + } catch (e) { + log(e.toString()); + return null; + } + + return null; + } + + Future clear() async { + await mainDirectory.delete(recursive: true); + isar?.write((isar) => syncedItems?.clear()); + state = state.copyWith(items: []); + } + + Future setup() async { + state = state.copyWith(items: []); + _init(); + } +} + +extension SyncNotifierHelpers on SyncNotifier { + Future createSyncItem(BaseItemDto response, {SyncedItem? parent}) async { + final ItemBaseModel item = ItemBaseModel.fromBaseDto(response, ref); + + final Directory? parentDirectory = parent?.directory; + + SyncedItem syncItem = SyncedItem(id: item.id, userId: ref.read(userProvider)?.id ?? ""); + final directory = Directory(path.joinAll([(parentDirectory ?? saveDirectory)?.path ?? "", item.id])); + + await directory.create(recursive: true); + + File dataFile = File(path.joinAll([directory.path, 'data.json'])); + await dataFile.writeAsString(jsonEncode(response.toJson())); + + final imageData = await saveImageData(item.images, directory); + final origChapters = Chapter.chaptersFromInfo(item.id, response.chapters ?? [], ref); + + return syncItem.copyWith( + id: item.id, + parentId: parent?.id, + sortKey: (response.parentIndexNumber ?? 0) * (response.indexNumber ?? 0), + path: directory.path, + fChapters: await saveChapterImages(origChapters, directory) ?? [], + fileSize: response.mediaSources?.firstOrNull?.size ?? 0, + fImages: imageData, + videoFileName: response.path?.split('/').lastOrNull ?? "", + userData: item.userData, + ); + } + + // Need to move the file after downloading on Android + Future moveFile(DownloadTask downloadTask, SyncedItem syncItem) async { + final currentLocation = File(await downloadTask.filePath()); + final wantedLocation = syncItem.videoFile; + if (currentLocation.path != wantedLocation.path) { + await currentLocation.copy(wantedLocation.path); + await currentLocation.delete(); + } + } + + Future syncMovie(ItemBaseModel item, {bool skipDownload = false}) async { + final response = await api.usersUserIdItemsItemIdGetBaseItem( + itemId: item.id, + ); + + final itemBaseModel = response.body; + if (itemBaseModel == null) return null; + + SyncedItem syncItem = await createSyncItem(itemBaseModel); + + if (!syncItem.directory.existsSync()) return null; + + await syncVideoFile(syncItem, skipDownload); + + await isar?.writeAsync((isar) => syncedItems?.put(ISyncedItem.fromSynced(syncItem, syncPath))); + + return syncItem; + } + + Future syncSeries(SeriesModel item, {EpisodeModel? episode}) async { + final response = await api.usersUserIdItemsItemIdGetBaseItem( + itemId: item.id, + ); + + List newItems = []; + + SyncedItem? itemToDownload; + + SyncedItem seriesItem = await createSyncItem(response.bodyOrThrow); + newItems.add(seriesItem); + if (!seriesItem.directory.existsSync()) return null; + + final seasonsResponse = await api.showsSeriesIdSeasonsGet( + isMissing: false, + enableUserData: true, + fields: [ + ItemFields.mediastreams, + ItemFields.mediasources, + ItemFields.overview, + ItemFields.mediasourcecount, + ItemFields.airtime, + ItemFields.datecreated, + ItemFields.datelastmediaadded, + ItemFields.datelastrefreshed, + ItemFields.sortname, + ItemFields.seasonuserdata, + ItemFields.externalurls, + ItemFields.genres, + ItemFields.parentid, + ItemFields.path, + ItemFields.chapters, + ItemFields.trickplay, + ], + seriesId: item.id, + ); + + final seasons = seasonsResponse.body?.items ?? []; + + for (var i = 0; i < seasons.length; i++) { + final season = seasons[i]; + final syncedSeason = await createSyncItem(season, parent: seriesItem); + newItems.add(syncedSeason); + final episodesResponse = await api.showsSeriesIdEpisodesGet( + isMissing: false, + enableUserData: true, + fields: [ + ItemFields.mediastreams, + ItemFields.mediasources, + ItemFields.overview, + ItemFields.mediasourcecount, + ItemFields.airtime, + ItemFields.datecreated, + ItemFields.datelastmediaadded, + ItemFields.datelastrefreshed, + ItemFields.sortname, + ItemFields.seasonuserdata, + ItemFields.externalurls, + ItemFields.genres, + ItemFields.parentid, + ItemFields.path, + ItemFields.chapters, + ItemFields.trickplay, + ], + seasonId: season.id, + seriesId: seriesItem.id, + ); + final episodes = episodesResponse.body?.items ?? []; + for (var i = 0; i < episodes.length; i++) { + final item = episodes[i]; + final newEpisode = await createSyncItem(item, parent: syncedSeason); + newItems.add(newEpisode); + if (episode?.id == item.id) { + itemToDownload = newEpisode; + } + } + } + + isar?.write( + (isar) => syncedItems?.putAll(newItems + .map( + (e) => ISyncedItem.fromSynced(e, syncPath ?? ""), + ) + .toList()), + ); + + if (itemToDownload != null) { + await syncVideoFile(itemToDownload, false); + } + + return seriesItem; + } +} diff --git a/lib/providers/sync_provider_web.dart b/lib/providers/sync_provider_web.dart new file mode 100644 index 0000000..78789de --- /dev/null +++ b/lib/providers/sync_provider_web.dart @@ -0,0 +1,13 @@ +import 'dart:io'; + +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:isar/isar.dart'; + +class AbstractSyncNotifier { + final Ref ref; + final Isar? isar; + final Directory mobileDirectory; + final String subPath = "Synced"; + + AbstractSyncNotifier(this.ref, this.isar, this.mobileDirectory); +} diff --git a/lib/providers/user_provider.dart b/lib/providers/user_provider.dart new file mode 100644 index 0000000..734dc2a --- /dev/null +++ b/lib/providers/user_provider.dart @@ -0,0 +1,145 @@ +import 'package:chopper/chopper.dart'; +import 'package:fladder/jellyfin/enum_models.dart'; +import 'package:fladder/models/account_model.dart'; +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:fladder/providers/service_provider.dart'; +import 'package:fladder/providers/shared_provider.dart'; +import 'package:fladder/providers/sync_provider.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +part 'user_provider.g.dart'; + +@riverpod +bool showSyncButtonProvider(ShowSyncButtonProviderRef ref) { + final userCanSync = ref.watch(userProvider.select((value) => value?.canDownload ?? false)); + final hasSyncedItems = ref.watch(syncProvider.select((value) => value.items.isNotEmpty)); + return userCanSync || hasSyncedItems; +} + +@Riverpod(keepAlive: true) +class User extends _$User { + late final JellyService api = ref.read(jellyApiProvider); + + set userState(AccountModel? account) { + state = account?.copyWith(lastUsed: DateTime.now()); + if (account != null) { + ref.read(sharedUtilityProvider).updateAccountInfo(account); + } + } + + Future> quickConnect(String pin) async => api.quickConnect(pin); + + Future?> updateInformation() async { + if (state == null) return null; + var response = await api.usersMeGet(); + var quickConnectStatus = await api.quickConnectEnabled(); + var systemConfiguration = await api.systemConfigurationGet(); + if (response.isSuccessful && response.body != null) { + userState = state?.copyWith( + name: response.body?.name ?? state?.name ?? "", + policy: response.body?.policy, + serverConfiguration: systemConfiguration.body, + quickConnectState: quickConnectStatus.body ?? false, + latestItemsExcludes: response.body?.configuration?.latestItemsExcludes ?? [], + ); + return response.copyWith(body: state); + } + return null; + } + + Future refreshMetaData( + String itemId, { + MetadataRefresh? metadataRefreshMode, + bool? replaceAllMetadata, + }) async { + return api.itemsItemIdRefreshPost( + itemId: itemId, + metadataRefreshMode: metadataRefreshMode, + imageRefreshMode: metadataRefreshMode, + replaceAllMetadata: switch (metadataRefreshMode) { + MetadataRefresh.fullRefresh => false, + MetadataRefresh.validation => true, + _ => false, + }, + replaceAllImages: switch (metadataRefreshMode) { + MetadataRefresh.fullRefresh => true, + MetadataRefresh.validation => true, + _ => false, + }, + ); + } + + Future?> setAsFavorite(bool favorite, String itemId) async { + final response = await (favorite + ? api.usersUserIdFavoriteItemsItemIdPost(itemId: itemId) + : api.usersUserIdFavoriteItemsItemIdDelete(itemId: itemId)); + return Response(response.base, UserData.fromDto(response.body)); + } + + Future?> markAsPlayed(bool enable, String itemId) async { + final response = await (enable + ? api.usersUserIdPlayedItemsItemIdPost( + itemId: itemId, + datePlayed: DateTime.now(), + ) + : api.usersUserIdPlayedItemsItemIdDelete( + itemId: itemId, + )); + return Response(response.base, UserData.fromDto(response.body)); + } + + void clear() { + userState = null; + } + + void updateUser(AccountModel? user) { + userState = user; + } + + void loginUser(AccountModel? user) { + state = user; + } + + void setAuthMethod(Authentication method) { + userState = state?.copyWith(authMethod: method); + } + + void addSearchQuery(String value) { + if (value.isEmpty) return; + final newList = state?.searchQueryHistory.toList() ?? []; + if (newList.contains(value)) { + newList.remove(value); + } + newList.add(value); + userState = state?.copyWith(searchQueryHistory: newList); + } + + void removeSearchQuery(String value) { + userState = state?.copyWith( + searchQueryHistory: state?.searchQueryHistory ?? [] + ..remove(value) + ..take(50), + ); + } + + void clearSearchQuery() { + userState = state?.copyWith(searchQueryHistory: []); + } + + Future logoutUser() async { + if (state == null) return; + userState = null; + } + + Future forceLogoutUser(AccountModel account) async { + userState = account; + await api.sessionsLogoutPost(); + userState = null; + } + + @override + AccountModel? build() { + return null; + } +} diff --git a/lib/providers/user_provider.g.dart b/lib/providers/user_provider.g.dart new file mode 100644 index 0000000..21778b7 --- /dev/null +++ b/lib/providers/user_provider.g.dart @@ -0,0 +1,40 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'user_provider.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$showSyncButtonProviderHash() => + r'3468d7309f3859f7b60b1bd317e306e1f5f00555'; + +/// See also [showSyncButtonProvider]. +@ProviderFor(showSyncButtonProvider) +final showSyncButtonProviderProvider = AutoDisposeProvider.internal( + showSyncButtonProvider, + name: r'showSyncButtonProviderProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$showSyncButtonProviderHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef ShowSyncButtonProviderRef = AutoDisposeProviderRef; +String _$userHash() => r'4a4302c819d26fc7c28d04b9274d0dfd0dc8e201'; + +/// See also [User]. +@ProviderFor(User) +final userProvider = NotifierProvider.internal( + User.new, + name: r'userProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$userHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$User = Notifier; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member diff --git a/lib/providers/video_player_provider.dart b/lib/providers/video_player_provider.dart new file mode 100644 index 0000000..6473bc7 --- /dev/null +++ b/lib/providers/video_player_provider.dart @@ -0,0 +1,125 @@ +import 'dart:async'; + +import 'package:collection/collection.dart'; + +import 'package:fladder/models/media_playback_model.dart'; +import 'package:fladder/models/playback/playback_model.dart'; +import 'package:fladder/providers/settings/video_player_settings_provider.dart'; +import 'package:fladder/wrappers/media_control_wrapper.dart' + if (dart.library.html) 'package:fladder/wrappers/media_control_wrapper_web.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:media_kit/media_kit.dart'; + +final mediaPlaybackProvider = StateProvider((ref) => MediaPlaybackModel()); + +final playBackModel = StateProvider((ref) => null); + +final videoPlayerProvider = StateNotifierProvider((ref) { + final videoPlayer = VideoPlayerNotifier(ref); + videoPlayer.init(); + return videoPlayer; +}); + +class VideoPlayerNotifier extends StateNotifier { + VideoPlayerNotifier(this.ref) : super(MediaControlsWrapper(ref: ref)); + + final Ref ref; + + List subscriptions = []; + + late final mediaState = ref.read(mediaPlaybackProvider.notifier); + + bool initMediaControls = false; + + void init() async { + state.player?.dispose(); + if (!initMediaControls && !kDebugMode) { + state.init(); + initMediaControls = true; + } + for (final s in subscriptions) { + s.cancel(); + } + final player = state.setup(); + if (player.platform is NativePlayer) { + await (player.platform as dynamic).setProperty( + 'force-seekable', + 'yes', + ); + } + subscriptions.addAll( + [ + player.stream.buffering.listen((event) => mediaState.update((state) => state.copyWith(buffering: event))), + player.stream.buffer.listen((event) => mediaState.update((state) => state.copyWith(buffer: event))), + player.stream.playing.listen((event) => updatePlaying(event)), + player.stream.position.listen((event) => updatePosition(event)), + player.stream.duration.listen((event) => mediaState.update((state) => state.copyWith(duration: event))), + ].whereNotNull(), + ); + } + + Future updatePlaying(bool event) async { + final player = state.player; + if (player == null) return; + mediaState.update((state) => state.copyWith(playing: event)); + } + + Future updatePosition(Duration event) async { + final player = state.player; + if (player == null) return; + if (!player.state.playing) return; + + final position = event; + final lastPosition = ref.read(mediaPlaybackProvider.select((value) => value.lastPosition)); + final diff = (position.inMilliseconds - lastPosition.inMilliseconds).abs(); + + if (diff > Duration(seconds: 1, milliseconds: 500).inMilliseconds) { + mediaState.update((value) => value.copyWith( + position: event, + playing: player.state.playing, + duration: player.state.duration, + lastPosition: position, + )); + ref.read(playBackModel)?.updatePlaybackPosition(position, player.state.playing, ref); + } else { + mediaState.update((value) => value.copyWith( + position: event, + playing: player.state.playing, + duration: player.state.duration, + )); + } + } + + Future loadPlaybackItem(PlaybackModel model, {Duration? startPosition}) async { + await state.stop(); + mediaState + .update((state) => state.copyWith(state: VideoPlayerState.fullScreen, buffering: true, errorPlaying: false)); + + final media = model.media; + PlaybackModel? newPlaybackModel = model; + + if (media != null) { + await state.setVolume(ref.read(videoPlayerSettingsProvider).volume); + await state.open(media, play: false); + state.player?.stream.buffering.takeWhile((event) => event == true).listen( + null, + onDone: () async { + final start = startPosition ?? await model.startDuration(); + if (start != null) { + await state.seek(start); + } + newPlaybackModel = await newPlaybackModel?.setAudio(null, state); + newPlaybackModel = await newPlaybackModel?.setSubtitle(null, state); + ref.read(playBackModel.notifier).update((state) => newPlaybackModel); + state.play(); + }, + ); + ref.read(playBackModel.notifier).update((state) => model); + return true; + } + + mediaState.update((state) => state.copyWith(errorPlaying: true)); + return false; + } +} diff --git a/lib/providers/views_provider.dart b/lib/providers/views_provider.dart new file mode 100644 index 0000000..841f345 --- /dev/null +++ b/lib/providers/views_provider.dart @@ -0,0 +1,64 @@ +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/view_model.dart'; +import 'package:fladder/models/views_model.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:fladder/providers/service_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +final viewsProvider = StateNotifierProvider((ref) { + return ViewsNotifier(ref); +}); + +class ViewsNotifier extends StateNotifier { + ViewsNotifier(this.ref) : super(ViewsModel()); + + final Ref ref; + + late final JellyService api = ref.read(jellyApiProvider); + + Future fetchViews() async { + if (state.loading) return; + final response = await api.usersUserIdViewsGet(); + final createdViews = response.body?.items?.map((e) => ViewModel.fromBodyDto(e, ref)); + List newList = []; + + if (createdViews != null) { + newList = await Future.wait(createdViews.map((e) async { + if (ref.read(userProvider)?.latestItemsExcludes.contains(e.id) == true) return e; + if ([CollectionType.boxsets, CollectionType.folders].contains(e.collectionType)) return e; + final recents = await api.usersUserIdItemsLatestGet( + parentId: e.id, + imageTypeLimit: 1, + limit: 16, + enableImageTypes: [ + ImageType.primary, + ImageType.backdrop, + ImageType.thumb, + ], + fields: [ + ItemFields.parentid, + ItemFields.mediastreams, + ItemFields.mediasources, + ItemFields.candelete, + ItemFields.candownload, + ], + ); + return e.copyWith(recentlyAdded: recents.body?.map((e) => ItemBaseModel.fromBaseDto(e, ref)).toList()); + })); + } + + state = state.copyWith( + views: newList, + dashboardViews: newList + .where((element) => !(ref.read(userProvider)?.latestItemsExcludes.contains(element.id) ?? true)) + .where((element) => ![CollectionType.boxsets, CollectionType.folders].contains(element.collectionType)) + .toList(), + loading: false); + } + + void clear() { + state = ViewsModel(); + } +} diff --git a/lib/routes/app_routes.dart b/lib/routes/app_routes.dart new file mode 100644 index 0000000..10824d9 --- /dev/null +++ b/lib/routes/app_routes.dart @@ -0,0 +1,121 @@ +import 'package:fladder/providers/shared_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/routes/build_routes/home_routes.dart'; +import 'package:fladder/routes/build_routes/route_builder.dart'; +import 'package:fladder/routes/build_routes/settings_routes.dart'; +import 'package:fladder/screens/home.dart'; +import 'package:fladder/screens/settings/settings_screen.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; + +class AppRoutes { + static final parentKey = GlobalKey(); + static final homeShellKey = GlobalKey(); + static final settingsKey = GlobalKey(); + static final loginRoute = LoginRoute(); + static final splashRoute = SplashRoute(); + + static final scrollController = ScrollController(); + + static GoRouter routes({required WidgetRef ref, required ScreenLayout screenLayout}) { + return GoRouter( + navigatorKey: parentKey, + initialLocation: splashRoute.route, + //Only useful for web if the user is not in an active session yet + redirect: kIsWeb + ? (context, state) async { + if (state.uri.toString() == loginRoute.route || state.uri.toString() == splashRoute.route) return null; + await Future.microtask(() { + final lastUsedAccount = ref.read(sharedUtilityProvider).getActiveAccount(); + if (lastUsedAccount == null) return loginRoute.route; + if (ref.read(userProvider) == null) ref.read(userProvider.notifier).loginUser(lastUsedAccount); + }); + if (ref.read(userProvider) == null) { + return loginRoute.route; + } else { + return state.uri.toString(); + } + } + : null, + routes: AppRoutes().getRoutes(screenLayout), + ); + } + + List getRoutes(ScreenLayout screenLayout) { + switch (screenLayout) { + case ScreenLayout.single: + return linearRoutes; + case ScreenLayout.dual: + return nestedRoutes; + } + } + + static List linearRoutes = [ + loginRoute.go, + splashRoute.go, + LockScreenRoute().go, + ShellRoute( + navigatorKey: homeShellKey, + pageBuilder: (context, state, child) { + return NoTransitionPage( + child: Home( + key: state.pageKey, + location: state.uri.toString(), + nestedChild: child, + ), + ); + }, + routes: [ + DashboardRoute().go, + FavouritesRoute().go, + SyncRoute().go, + ], + ), + DetailsRoute(navKey: parentKey).go, + LibrarySearchRoute(navKey: parentKey).go, + + // Settings routes + SettingsRoute(navKey: parentKey).go, + ClientSettingsRoute(navKey: parentKey).go, + SecuritySettingsRoute(navKey: parentKey).go, + PlayerSettingsRoute(navKey: parentKey).go, + ]; + + static List nestedRoutes = [ + loginRoute.go, + splashRoute.go, + LockScreenRoute().go, + ShellRoute( + navigatorKey: homeShellKey, + pageBuilder: (context, state, child) => NoTransitionPage( + child: Home( + key: state.pageKey, + location: state.uri.toString(), + nestedChild: child, + ), + ), + routes: [ + ShellRoute( + navigatorKey: settingsKey, + pageBuilder: (context, state, child) => NoTransitionPage( + key: state.pageKey, + child: SettingsScreen(location: state.uri.toString(), child: child), + ), + routes: [ + ClientSettingsRoute(navKey: settingsKey).go, + SecuritySettingsRoute(navKey: settingsKey).go, + PlayerSettingsRoute(navKey: settingsKey).go, + ], + ), + DashboardRoute().go, + FavouritesRoute().go, + SyncRoute().go, + DetailsRoute(navKey: homeShellKey).go, + LibrarySearchRoute(navKey: homeShellKey).go, + ], + ), + ]; +} diff --git a/lib/routes/build_routes/home_routes.dart b/lib/routes/build_routes/home_routes.dart new file mode 100644 index 0000000..88b7daf --- /dev/null +++ b/lib/routes/build_routes/home_routes.dart @@ -0,0 +1,182 @@ +import 'package:animations/animations.dart'; +import 'package:collection/collection.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/library_search/library_search_options.dart'; +import 'package:fladder/routes/app_routes.dart'; +import 'package:fladder/routes/build_routes/route_builder.dart'; +import 'package:fladder/screens/dashboard/dashboard_screen.dart'; +import 'package:fladder/screens/syncing/synced_screen.dart'; +import 'package:fladder/screens/favourites/favourites_screen.dart'; +import 'package:fladder/screens/library_search/library_search_screen.dart'; +import 'package:fladder/screens/shared/detail_scaffold.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; + +class DashboardRoute extends CustomRoute { + DashboardRoute() : super(name: 'Dashboard', basePath: '/dashboard'); + + @override + GoRoute get go => GoRoute( + path: basePath, + parentNavigatorKey: AppRoutes.homeShellKey, + pageBuilder: (context, state) { + return CustomTransitionPage( + key: state.pageKey, + child: DashboardScreen( + key: Key(basePath), + navigationScrollController: AppRoutes.scrollController, + ), + transitionsBuilder: (context, animation, secondaryAnimation, child) { + return FadeTransition( + opacity: CurveTween(curve: Curves.easeInOutCirc).animate(animation), + child: child, + ); + }); + }, + ); +} + +class FavouritesRoute extends CustomRoute { + FavouritesRoute() : super(name: 'Favorites', basePath: '/favorites'); + + @override + GoRoute get go => GoRoute( + path: basePath, + parentNavigatorKey: AppRoutes.homeShellKey, + pageBuilder: (context, state) { + return CustomTransitionPage( + key: state.pageKey, + child: FavouritesScreen( + key: Key(basePath), + navigationScrollController: AppRoutes.scrollController, + ), + transitionsBuilder: (context, animation, secondaryAnimation, child) { + return FadeTransition( + opacity: CurveTween(curve: Curves.easeInOutCirc).animate(animation), + child: child, + ); + }); + }, + ); +} + +class SyncRoute extends CustomRoute { + SyncRoute() : super(name: 'Sync', basePath: '/sync'); + + @override + GoRoute get go => GoRoute( + path: basePath, + parentNavigatorKey: AppRoutes.homeShellKey, + pageBuilder: (context, state) { + return CustomTransitionPage( + key: state.pageKey, + child: SyncedScreen( + key: Key(basePath), + navigationScrollController: AppRoutes.scrollController, + ), + transitionsBuilder: (context, animation, secondaryAnimation, child) { + return FadeTransition( + opacity: CurveTween(curve: Curves.easeInOutCirc).animate(animation), + child: child, + ); + }); + }, + ); +} + +class DetailsRoute extends CustomRoute { + final String? id; + final GlobalKey? navKey; + DetailsRoute({this.id, this.navKey}) : super(name: 'Details', basePath: '/details', arguments: ':itemId'); + + @override + String get route => "$basePath/$id"; + + @override + GoRoute get go => GoRoute( + path: path, + parentNavigatorKey: navKey, + pageBuilder: (context, state) { + final String id = state.pathParameters['itemId'] ?? "nothing"; + ItemBaseModel? item = state.extra as ItemBaseModel?; + return CustomTransitionPage( + key: state.pageKey, + child: DetailScreen( + key: Key(id), + id: id, + item: item, + ), + transitionsBuilder: (context, animation, secondaryAnimation, child) { + return FadeThroughTransition( + animation: animation, + secondaryAnimation: secondaryAnimation, + child: child, + ); + }, + ); + }, + ); +} + +const _libraryKey = "libraryId"; +const _sortOptionsKey = "sortOptions"; +const _sortOrderKey = "sortOrder"; +const _favoriteKey = "favorite"; +const _folderKey = "folder"; + +class LibrarySearchRoute extends CustomRoute { + final String? id; + final bool? favorites; + final SortingOptions? sortOptions; + final SortOrder? sortOrder; + final String? folderId; + final GlobalKey? navKey; + LibrarySearchRoute({this.id, this.favorites, this.sortOptions, this.sortOrder, this.folderId, this.navKey}) + : super( + name: 'LibrarySearch', + basePath: '/library', + queryParameters: { + _libraryKey: id, + _sortOptionsKey: sortOptions?.name, + _sortOrderKey: sortOrder?.name, + _favoriteKey: favorites, + _folderKey: folderId, + }, + ); + + @override + String get route => "$basePath${parseUrlParameters(queryParameters)}"; + + @override + GoRoute get go => GoRoute( + path: basePath, + parentNavigatorKey: navKey, + pageBuilder: (context, state) { + final String? id = state.uri.queryParameters[_libraryKey]; + final bool? favourites = bool.tryParse(state.uri.queryParameters[_favoriteKey] ?? ""); + final String? folderId = state.uri.queryParameters[_folderKey]; + final SortingOptions? sortingOptions = SortingOptions.values + .firstWhereOrNull((element) => element.name == state.uri.queryParameters[_sortOptionsKey]); + final SortingOrder? sortOrder = SortingOrder.values + .firstWhereOrNull((element) => element.name == state.uri.queryParameters[_sortOrderKey]); + return CustomTransitionPage( + key: state.pageKey, + child: LibrarySearchScreen( + key: Key(id ?? "librarySearch"), + viewModelId: id, + folderId: folderId?.split(','), + sortingOptions: sortingOptions, + sortOrder: sortOrder, + favourites: favourites, + ), + transitionsBuilder: (context, animation, secondaryAnimation, child) { + return FadeTransition( + opacity: CurveTween(curve: Curves.easeInOutCirc).animate(animation), + child: child, + ); + }, + ); + }, + ); +} diff --git a/lib/routes/build_routes/route_builder.dart b/lib/routes/build_routes/route_builder.dart new file mode 100644 index 0000000..5e82a3b --- /dev/null +++ b/lib/routes/build_routes/route_builder.dart @@ -0,0 +1,124 @@ +import 'package:fladder/screens/login/login_screen.dart'; +import 'package:flutter/material.dart'; + +import 'package:go_router/go_router.dart'; + +import 'package:fladder/routes/app_routes.dart'; +import 'package:fladder/screens/login/lock_screen.dart'; +import 'package:fladder/screens/splash_screen.dart'; +import 'package:fladder/util/adaptive_layout.dart'; + +extension RouteContextBuilder on BuildContext { + /// Push a location onto the page stack. + Future routePush(CustomRoute route, {Object? extra}) async { + return push(route.route, extra: extra); + } + + /// Replaces the top-most page of the page stack with the given URL location + void routeReplace(CustomRoute route, {Object? extra}) { + replace(route.route, extra: extra); + } + + /// Navigate to a location. + void routeGo(CustomRoute route, {Object? extra}) { + go(route.route, extra: extra); + } + + /// [Pushed] if nested(single) else [Go] + void routePushOrGo(CustomRoute route, {Object? extra}) { + switch (AdaptiveLayout.of(this).size) { + case ScreenLayout.single: + routePush(route, extra: extra); + break; + case ScreenLayout.dual: + routeGo(route, extra: extra); + break; + } + } + + /// [Push] if nested(single) else [Replace] + void routeReplaceOrPush(CustomRoute route, {Object? extra}) { + switch (AdaptiveLayout.of(this).size) { + case ScreenLayout.single: + routePush(route, extra: extra); + break; + case ScreenLayout.dual: + routeReplace(route, extra: extra); + break; + } + } +} + +abstract class CustomRoute { + final String name; + final String basePath; + final String? arguments; + final Map? queryParameters; + + CustomRoute({required this.name, required this.basePath, this.arguments, this.queryParameters}) + : assert(basePath.isNotEmpty, 'GoRoute path cannot be empty'); + + String get route => basePath; + + String get path => "$basePath/${arguments ?? queryParameters}"; + + void navigate() { + AppRoutes.parentKey.currentContext?.routeGo(this); + } + + void replaceRoot() { + AppRoutes.parentKey.currentContext?.routeReplace(this); + } + + RouteBase get go; +} + +class LoginRoute extends CustomRoute { + LoginRoute() : super(name: 'Login', basePath: '/login'); + + @override + GoRoute get go => GoRoute( + path: basePath, + builder: (context, state) { + return const LoginScreen(); + }, + ); +} + +class SplashRoute extends CustomRoute { + SplashRoute() : super(name: 'Splash', basePath: '/splash'); + + @override + GoRoute get go => GoRoute( + path: basePath, + builder: (context, state) { + return const SplashScreen(); + }, + ); +} + +class LockScreenRoute extends CustomRoute { + final bool selfLock; + LockScreenRoute({this.selfLock = false}) : super(name: 'Lock', basePath: '/lock'); + + @override + GoRoute get go => GoRoute( + parentNavigatorKey: AppRoutes.parentKey, + path: basePath, + builder: (context, state) { + return LockScreen( + selfLock: selfLock, + ); + }, + ); +} + +String parseUrlParameters(Map? parameters) { + if (parameters == null) return ''; + String parameterString = '?'; + for (String key in parameters.keys) { + if (parameters[key] != null) parameterString += '$key=${parameters[key]}&'; + } + + return parameterString.substring(0, parameterString.length - 1); +} diff --git a/lib/routes/build_routes/settings_routes.dart b/lib/routes/build_routes/settings_routes.dart new file mode 100644 index 0000000..7bda1b9 --- /dev/null +++ b/lib/routes/build_routes/settings_routes.dart @@ -0,0 +1,103 @@ +import 'package:fladder/routes/build_routes/route_builder.dart'; +import 'package:fladder/screens/settings/client_settings_page.dart'; +import 'package:fladder/screens/settings/player_settings_page.dart'; +import 'package:fladder/screens/settings/settings_screen.dart'; +import 'package:fladder/screens/settings/security_settings_page.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; + +class SettingsRoute extends CustomRoute { + final String? id; + final GlobalKey? navKey; + SettingsRoute({this.id, this.navKey}) : super(name: 'Settings', basePath: '/settings'); + + @override + GoRoute get go => GoRoute( + path: basePath, + parentNavigatorKey: navKey, + pageBuilder: (context, state) { + return CustomTransitionPage( + key: state.pageKey, + child: const SettingsScreen(), + transitionsBuilder: (context, animation, secondaryAnimation, child) { + return FadeTransition( + opacity: CurveTween(curve: Curves.easeInOutCirc).animate(animation), + child: child, + ); + }, + ); + }, + ); +} + +class ClientSettingsRoute extends CustomRoute { + final String? id; + final GlobalKey? navKey; + ClientSettingsRoute({this.id, this.navKey}) : super(name: 'ClientSettings', basePath: '/settings/client'); + + @override + GoRoute get go => GoRoute( + path: basePath, + parentNavigatorKey: navKey, + pageBuilder: (context, state) { + return CustomTransitionPage( + key: state.pageKey, + child: const ClientSettingsPage(), + transitionsBuilder: (context, animation, secondaryAnimation, child) { + return FadeTransition( + opacity: CurveTween(curve: Curves.easeInOutCirc).animate(animation), + child: child, + ); + }, + ); + }, + ); +} + +class SecuritySettingsRoute extends CustomRoute { + final String? id; + final GlobalKey? navKey; + SecuritySettingsRoute({this.id, this.navKey}) : super(name: 'SecuritySettings', basePath: '/settings/security'); + + @override + GoRoute get go => GoRoute( + path: basePath, + parentNavigatorKey: navKey, + pageBuilder: (context, state) { + return CustomTransitionPage( + key: state.pageKey, + child: const SecuritySettingsPage(), + transitionsBuilder: (context, animation, secondaryAnimation, child) { + return FadeTransition( + opacity: CurveTween(curve: Curves.easeInOutCirc).animate(animation), + child: child, + ); + }, + ); + }, + ); +} + +class PlayerSettingsRoute extends CustomRoute { + final String? id; + final GlobalKey? navKey; + PlayerSettingsRoute({this.id, this.navKey}) : super(name: 'PlayerSettings', basePath: '/settings/player'); + + @override + GoRoute get go => GoRoute( + path: basePath, + parentNavigatorKey: navKey, + pageBuilder: (context, state) { + return CustomTransitionPage( + key: state.pageKey, + child: const PlayerSettingsPage(), + transitionsBuilder: (context, animation, secondaryAnimation, child) { + return FadeTransition( + opacity: CurveTween(curve: Curves.easeInOutCirc).animate(animation), + child: child, + ); + }, + ); + }, + ); +} diff --git a/lib/screens/book_viewer/book_viewer_chapters.dart b/lib/screens/book_viewer/book_viewer_chapters.dart new file mode 100644 index 0000000..57c7a83 --- /dev/null +++ b/lib/screens/book_viewer/book_viewer_chapters.dart @@ -0,0 +1,118 @@ +import 'package:fladder/models/book_model.dart'; +import 'package:fladder/providers/book_viewer_provider.dart'; +import 'package:fladder/providers/items/book_details_provider.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/fladder_image.dart'; +import 'package:fladder/widgets/shared/modal_side_sheet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +Future showBookViewerChapters( + BuildContext context, AutoDisposeStateNotifierProvider provider, + {Function(BookModel book)? onPressed}) async { + if (AdaptiveLayout.of(context).isDesktop) { + return showModalSideSheet(context, + content: BookViewerChapters( + provider: provider, + onPressed: onPressed, + )); + } else { + return showModalBottomSheet( + context: context, + isScrollControlled: true, + showDragHandle: true, + useSafeArea: true, + builder: (context) => BookViewerChapters( + provider: provider, + onPressed: onPressed, + ), + ); + } +} + +class BookViewerChapters extends ConsumerWidget { + final AutoDisposeStateNotifierProvider provider; + final Function(BookModel book)? onPressed; + const BookViewerChapters({required this.provider, this.onPressed, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final currentBook = ref.watch(bookViewerProvider.select((value) => value.book)); + final chapters = ref.watch(provider.select((value) => value.chapters)); + + return Column( + mainAxisSize: MainAxisSize.max, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Align( + alignment: Alignment.centerLeft, + child: Text( + "Chapters", + style: Theme.of(context).textTheme.titleLarge, + ), + ), + ), + const Divider(), + Flexible( + child: ListView( + shrinkWrap: true, + children: [ + ...chapters.map( + (book) { + final bool current = currentBook == book; + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 6), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 2), + child: Card( + elevation: current ? 10 : 3, + child: Container( + constraints: const BoxConstraints(minHeight: 80), + alignment: Alignment.center, + child: ListTile( + contentPadding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + leading: AspectRatio( + aspectRatio: 1, + child: Card( + child: FladderImage( + image: book.getPosters?.primary, + ), + ), + ), + title: Text(book.name), + trailing: current + ? Padding( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8), + child: Icon( + Icons.visibility_rounded, + color: Theme.of(context).colorScheme.primary, + ), + ) + : FilledButton( + onPressed: () => onPressed?.call(book), + style: ElevatedButton.styleFrom( + padding: EdgeInsets.zero, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6), + ), + ), + child: const Icon(Icons.read_more_rounded), + ), + ), + ), + ), + ), + ); + }, + ), + SizedBox( + height: MediaQuery.of(context).padding.bottom, + ), + ], + ), + ), + ], + ); + } +} diff --git a/lib/screens/book_viewer/book_viewer_controls.dart b/lib/screens/book_viewer/book_viewer_controls.dart new file mode 100644 index 0000000..9d6bac3 --- /dev/null +++ b/lib/screens/book_viewer/book_viewer_controls.dart @@ -0,0 +1,398 @@ +import 'package:extended_image/extended_image.dart'; +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/book_model.dart'; +import 'package:fladder/providers/book_viewer_provider.dart'; +import 'package:fladder/providers/items/book_details_provider.dart'; +import 'package:fladder/providers/settings/book_viewer_settings_provider.dart'; +import 'package:fladder/screens/book_viewer/book_viewer_chapters.dart'; +import 'package:fladder/screens/book_viewer/book_viewer_settings.dart'; +import 'package:fladder/screens/shared/default_titlebar.dart'; +import 'package:fladder/screens/shared/fladder_snackbar.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/throttler.dart'; +import 'package:fladder/widgets/shared/fladder_slider.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:screen_brightness/screen_brightness.dart'; +import 'package:wakelock_plus/wakelock_plus.dart'; + +class BookViewController { + bool controlsVisible = true; + + late ValueNotifier visibilityChanged = ValueNotifier(controlsVisible); + + void toggleControls({bool? value}) { + controlsVisible = value ?? !controlsVisible; + visibilityChanged.value = controlsVisible; + } +} + +class BookViewerControls extends ConsumerStatefulWidget { + final AutoDisposeStateNotifierProvider provider; + final BookViewController viewController; + + final ExtendedPageController controller; + const BookViewerControls({ + required this.provider, + required this.controller, + required this.viewController, + super.key, + }); + + @override + ConsumerState createState() => _BookViewerControlsState(); +} + +class _BookViewerControlsState extends ConsumerState { + final FocusNode focusNode = FocusNode(); + final Throttler throttler = Throttler(duration: const Duration(milliseconds: 130)); + final Duration pageAnimDuration = const Duration(milliseconds: 125); + final Curve pageAnimCurve = Curves.easeInCubic; + late final BookViewController viewController = widget.viewController; + + late final double topPadding = MediaQuery.of(context).viewPadding.top; + late final double bottomPadding = MediaQuery.of(context).viewPadding.bottom; + + bool showControls = true; + void toggleControls({bool? value}) { + setState(() { + showControls = value ?? !showControls; + }); + SystemChrome.setEnabledSystemUIMode(!showControls ? SystemUiMode.leanBack : SystemUiMode.edgeToEdge, overlays: []); + SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( + statusBarColor: Colors.transparent, + systemNavigationBarColor: Colors.transparent, + systemNavigationBarDividerColor: Colors.transparent, + )); + } + + @override + void initState() { + super.initState(); + WakelockPlus.enable(); + viewController.visibilityChanged.addListener(() { + toggleControls(value: viewController.controlsVisible); + }); + } + + @override + void dispose() { + super.dispose(); + WakelockPlus.disable(); + ScreenBrightness().resetScreenBrightness(); + SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge, overlays: []); + SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( + statusBarColor: Colors.transparent, + systemNavigationBarColor: Colors.transparent, + systemNavigationBarDividerColor: Colors.transparent, + )); + } + + @override + Widget build(BuildContext context) { + final details = ref.watch(widget.provider); + final bookViewerSettings = ref.watch(bookViewerSettingsProvider); + final chapters = details.chapters; + final bookViewerDetails = ref.watch(bookViewerProvider); + final currentPage = bookViewerDetails.currentPage; + const overlayColor = Colors.black; + final previousChapter = details.previousChapter(bookViewerDetails.book); + final nextChapter = details.nextChapter(bookViewerDetails.book); + + if (AdaptiveLayout.of(context).isDesktop) { + FocusScope.of(context).requestFocus(focusNode); + } + return MediaQuery.removePadding( + context: context, + child: KeyboardListener( + focusNode: focusNode, + autofocus: AdaptiveLayout.of(context).isDesktop, + onKeyEvent: (value) { + if (value is KeyDownEvent) { + if (value.logicalKey == LogicalKeyboardKey.arrowLeft || value.logicalKey == LogicalKeyboardKey.keyA) { + bookViewerSettings.readDirection == ReadDirection.leftToRight ? previousPage() : nextPage(); + } + if (value.logicalKey == LogicalKeyboardKey.arrowRight || value.logicalKey == LogicalKeyboardKey.keyD) { + bookViewerSettings.readDirection == ReadDirection.leftToRight ? nextPage() : previousPage(); + } + if (value.logicalKey == LogicalKeyboardKey.space) { + toggleControls(); + } + } + }, + child: Stack( + children: [ + IgnorePointer( + ignoring: !showControls, + child: AnimatedOpacity( + duration: const Duration(milliseconds: 500), + opacity: showControls ? 1 : 0, + child: Stack( + children: [ + Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + overlayColor.withOpacity(1), + overlayColor.withOpacity(0.65), + overlayColor.withOpacity(0), + ], + ), + ), + child: Padding( + padding: EdgeInsets.only(top: topPadding).copyWith(bottom: 8), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + if (AdaptiveLayout.of(context).isDesktop) + const Flexible( + child: DefaultTitleBar( + height: 50, + brightness: Brightness.dark, + ), + ), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const BackButton(), + const SizedBox( + width: 16, + ), + Flexible( + child: Text( + bookViewerDetails.book?.name ?? "None", + style: Theme.of(context).textTheme.titleLarge, + ), + ) + ], + ), + const SizedBox(height: 16), + ], + ), + ), + ), + if (!bookViewerDetails.loading) ...{ + if (bookViewerDetails.book != null && bookViewerDetails.pages.isNotEmpty) ...{ + Align( + alignment: Alignment.bottomCenter, + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + overlayColor.withOpacity(0), + overlayColor.withOpacity(0.65), + overlayColor.withOpacity(1), + ], + ), + ), + child: Padding( + padding: EdgeInsets.only(bottom: bottomPadding).copyWith(top: 16, bottom: 16), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const SizedBox(height: 30), + Row( + children: [ + const SizedBox(width: 8), + Tooltip( + message: bookViewerSettings.readDirection == ReadDirection.leftToRight + ? previousChapter?.name != null + ? "Load ${previousChapter?.name}" + : "" + : nextChapter?.name != null + ? "Load ${nextChapter?.name}" + : "", + child: IconButton.filled( + onPressed: bookViewerSettings.readDirection == ReadDirection.leftToRight + ? previousChapter != null + ? () async => await loadNextBook(previousChapter) + : null + : nextChapter != null + ? () async => await loadNextBook(nextChapter) + : null, + icon: const Icon(IconsaxOutline.backward), + ), + ), + const SizedBox(width: 8), + Flexible( + child: Container( + decoration: BoxDecoration( + color: Colors.black.withOpacity(0.7), + borderRadius: BorderRadius.circular(60), + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 24), + child: Row( + children: [ + if (bookViewerSettings.readDirection == ReadDirection.leftToRight) + ...controls(currentPage, bookViewerSettings, bookViewerDetails) + else + ...controls(currentPage, bookViewerSettings, bookViewerDetails) + .reversed, + ], + ), + ), + ), + ), + const SizedBox(width: 8), + Tooltip( + message: bookViewerSettings.readDirection == ReadDirection.leftToRight + ? nextChapter?.name != null + ? "Load ${nextChapter?.name}" + : "" + : previousChapter?.name != null + ? "Load ${previousChapter?.name}" + : "", + child: IconButton.filled( + onPressed: bookViewerSettings.readDirection == ReadDirection.leftToRight + ? nextChapter != null + ? () async => await loadNextBook(nextChapter) + : null + : previousChapter != null + ? () async => await loadNextBook(previousChapter) + : null, + icon: const Icon(IconsaxOutline.forward), + ), + ), + const SizedBox(width: 8), + ], + ), + const SizedBox(height: 16), + Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Transform.flip( + flipX: bookViewerSettings.readDirection == ReadDirection.rightToLeft, + child: IconButton( + onPressed: () => widget.controller + .animateToPage(1, duration: pageAnimDuration, curve: pageAnimCurve), + icon: const Icon(IconsaxOutline.backward)), + ), + IconButton( + onPressed: () { + showBookViewerSettings(context); + }, + icon: const Icon(IconsaxOutline.setting_2), + ), + IconButton( + onPressed: chapters.length > 1 + ? () { + showBookViewerChapters( + context, + widget.provider, + onPressed: (book) async { + Navigator.of(context).pop(); + loadNextBook(book); + }, + ); + } + : () => fladderSnackbar(context, title: "No other chapters"), + icon: const Icon(IconsaxOutline.bookmark_2), + ) + ], + ), + ], + ), + ), + ), + ), + } else + const Center( + child: Card( + child: Padding( + padding: EdgeInsets.all(8.0), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.menu_book_rounded), + SizedBox(width: 8), + Text("Unable to load book"), + ], + ), + ), + ), + ) + }, + ], + ), + ), + ), + if (bookViewerDetails.loading) + Center( + child: Card( + child: Padding( + padding: const EdgeInsets.all(16), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (bookViewerDetails.book != null) ...{ + Flexible( + child: Text("Loading ${bookViewerDetails.book?.name}", + style: Theme.of(context).textTheme.titleMedium), + ), + const SizedBox(width: 16), + }, + const CircularProgressIndicator.adaptive(strokeCap: StrokeCap.round), + ], + ), + ), + ), + ) + ], + ), + ), + ); + } + + List controls(int currentPage, BookViewerSettingsModel bookViewerSettings, BookViewerModel details) { + final clampedCurrentPage = currentPage.clamp(1, details.pages.length); + return [ + const SizedBox(width: 6), + Text( + (currentPage.clamp(1, details.pages.length)).toInt().toString().padLeft(1).padRight(1), + style: Theme.of(context).textTheme.titleMedium, + ), + Flexible( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Transform.flip( + flipX: bookViewerSettings.readDirection == ReadDirection.rightToLeft, + child: SizedBox( + height: 40, + child: FladderSlider( + value: clampedCurrentPage.toDouble(), + divisions: details.pages.length - 1, + min: 1, + max: details.pages.length.toDouble(), + onChangeEnd: (value) => widget.controller.jumpToPage(value.toInt()), + onChanged: (value) => ref.read(bookViewerProvider.notifier).setPage(value), + ), + ), + ), + ), + ), + Text( + details.pages.length.toString().padLeft(1).padRight(1), + style: Theme.of(context).textTheme.titleMedium, + ), + ]; + } + + Future loadNextBook(BookModel? book) async { + await ref.read(bookViewerProvider.notifier).fetchBook(book); + widget.controller.jumpToPage(0); + return; + } + + Future nextPage() async => + throttler.run(() async => await widget.controller.nextPage(duration: pageAnimDuration, curve: pageAnimCurve)); + + Future previousPage() async => + throttler.run(() async => await widget.controller.previousPage(duration: pageAnimDuration, curve: pageAnimCurve)); +} diff --git a/lib/screens/book_viewer/book_viewer_reader.dart b/lib/screens/book_viewer/book_viewer_reader.dart new file mode 100644 index 0000000..a59a879 --- /dev/null +++ b/lib/screens/book_viewer/book_viewer_reader.dart @@ -0,0 +1,119 @@ +import 'dart:io'; +import 'dart:math' as math; + +import 'package:extended_image/extended_image.dart'; +import 'package:fladder/providers/settings/book_viewer_settings_provider.dart'; +import 'package:fladder/screens/book_viewer/book_viewer_controls.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class BookViewerReader extends ConsumerWidget { + final int index; + final List pages; + final BookViewerSettingsModel bookViewSettings; + final Function() previousPage; + final Function() nextPage; + final BookViewController viewController; + final double lastScale; + final Function(double value) newScale; + const BookViewerReader({ + required this.index, + required this.pages, + required this.bookViewSettings, + required this.previousPage, + required this.nextPage, + required this.viewController, + required this.lastScale, + required this.newScale, + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + double? initScale({ + required Size imageSize, + required Size size, + double? initialScale, + }) { + final double n1 = imageSize.height / imageSize.width; + final double n2 = size.height / size.width; + if (n1 > n2) { + final FittedSizes fittedSizes = applyBoxFit(BoxFit.cover, imageSize, size); + //final Size sourceSize = fittedSizes.source; + final Size destinationSize = fittedSizes.destination; + return size.width / destinationSize.width; + } else if (n1 / n2 < 1 / 4) { + final FittedSizes fittedSizes = applyBoxFit(BoxFit.cover, imageSize, size); + //final Size sourceSize = fittedSizes.source; + final Size destinationSize = fittedSizes.destination; + return size.height / destinationSize.height; + } + + return initialScale; + } + + return GestureDetector( + behavior: HitTestBehavior.translucent, + onTapUp: (tapDetails) { + double screenWidth = MediaQuery.of(context).size.width; + double tapPosition = tapDetails.globalPosition.dx; + double tapPercentage = tapPosition / screenWidth; + if (tapPercentage < 0.22) { + bookViewSettings.readDirection == ReadDirection.leftToRight ? previousPage() : nextPage(); + } else if (tapPercentage < 0.88) { + viewController.toggleControls(); + } else { + bookViewSettings.readDirection == ReadDirection.leftToRight ? nextPage() : previousPage(); + } + }, + child: ExtendedImage.file( + fit: BoxFit.contain, + imageCacheName: pages[index - 1], + mode: ExtendedImageMode.gesture, + initGestureConfigHandler: (state) { + double? initialScale = !bookViewSettings.keepPageZoom + ? switch (bookViewSettings.initZoomState) { + InitZoomState.contained => 1.0, + InitZoomState.covered => 1.75, + } + : lastScale; + + if (state.extendedImageInfo != null) { + initialScale = initScale( + size: MediaQuery.sizeOf(context), + initialScale: initialScale, + imageSize: Size( + state.extendedImageInfo!.image.width.toDouble(), state.extendedImageInfo!.image.height.toDouble())); + } + + return GestureConfig( + inertialSpeed: 300, + inPageView: true, + initialScale: initialScale!, + initialAlignment: bookViewSettings.initZoomState == InitZoomState.contained && initialScale == 1.0 + ? InitialAlignment.center + : switch (bookViewSettings.readDirection) { + ReadDirection.rightToLeft => InitialAlignment.topRight, + ReadDirection.leftToRight => InitialAlignment.topLeft, + }, + reverseMousePointerScrollDirection: true, + maxScale: math.max(initialScale, 5.0), + minScale: math.min(initialScale, 1), + animationMaxScale: math.max(initialScale, 5.0), + gestureDetailsIsChanged: (details) { + if (bookViewSettings.keepPageZoom) { + if (lastScale != (details?.totalScale ?? initialScale)) { + newScale(details?.totalScale ?? 1.0); + } + } + }, + cacheGesture: bookViewSettings.cachePageZoom, + hitTestBehavior: HitTestBehavior.translucent, + ); + }, + File(pages[index - 1]), + enableMemoryCache: true, + ), + ); + } +} diff --git a/lib/screens/book_viewer/book_viewer_reader_web.dart b/lib/screens/book_viewer/book_viewer_reader_web.dart new file mode 100644 index 0000000..2c2c20d --- /dev/null +++ b/lib/screens/book_viewer/book_viewer_reader_web.dart @@ -0,0 +1,33 @@ +import 'package:fladder/providers/settings/book_viewer_settings_provider.dart'; +import 'package:fladder/screens/book_viewer/book_viewer_controls.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class BookViewerReader extends ConsumerWidget { + final int index; + final List pages; + final BookViewerSettingsModel bookViewSettings; + final Function() previousPage; + final Function() nextPage; + final BookViewController viewController; + final double lastScale; + final Function(double value) newScale; + const BookViewerReader({ + required this.index, + required this.pages, + required this.bookViewSettings, + required this.previousPage, + required this.nextPage, + required this.viewController, + required this.lastScale, + required this.newScale, + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Container( + child: Text("Web not supported."), + ); + } +} diff --git a/lib/screens/book_viewer/book_viewer_screen.dart b/lib/screens/book_viewer/book_viewer_screen.dart new file mode 100644 index 0000000..f9ee091 --- /dev/null +++ b/lib/screens/book_viewer/book_viewer_screen.dart @@ -0,0 +1,270 @@ +import 'package:extended_image/extended_image.dart'; +import 'package:fladder/models/book_model.dart'; +import 'package:fladder/providers/book_viewer_provider.dart'; +import 'package:fladder/providers/items/book_details_provider.dart'; +import 'package:fladder/providers/settings/book_viewer_settings_provider.dart'; +import 'package:fladder/screens/book_viewer/book_viewer_controls.dart'; +import 'package:fladder/screens/book_viewer/book_viewer_reader.dart' + if (dart.library.html) 'package:fladder/screens/book_viewer/book_viewer_reader_web.dart'; +import 'package:fladder/util/themes_data.dart'; +import 'package:fladder/util/throttler.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +Future openBookViewer( + BuildContext context, + AutoDisposeStateNotifierProvider provider, { + int? initialPage, +}) async { + return showDialog( + context: context, + useRootNavigator: true, + useSafeArea: false, + builder: (context) => Dialog.fullscreen( + child: BookViewerScreen( + initialPage: initialPage ?? 0, + provider: provider, + ), + ), + ); +} + +class BookViewerScreen extends ConsumerStatefulWidget { + final int initialPage; + final AutoDisposeStateNotifierProvider provider; + const BookViewerScreen({required this.provider, this.initialPage = 0, super.key}); + + @override + ConsumerState createState() => _BookViewerScreenState(); +} + +class _BookViewerScreenState extends ConsumerState { + final Throttler throttler = Throttler(duration: const Duration(milliseconds: 130)); + final Duration pageAnimDuration = const Duration(milliseconds: 125); + final Curve pageAnimCurve = Curves.easeInCubic; + late final ExtendedPageController extendedController = ExtendedPageController(initialPage: widget.initialPage); + late final BookViewController viewController = BookViewController(); + bool outOfRange = false; + + @override + void initState() { + super.initState(); + Future.microtask(() => ref.read(bookViewerSettingsProvider.notifier).setSavedBrightness()); + } + + late double lastScale = switch (ref.read(bookViewerSettingsProvider).initZoomState) { + InitZoomState.contained => 1.0, + InitZoomState.covered => 1.75, + }; + + late double lastPosition = 0.0; + + @override + Widget build(BuildContext context) { + final bookViewerDetails = ref.watch(bookViewerProvider); + final loading = bookViewerDetails.loading; + final pages = bookViewerDetails.pages; + final book = bookViewerDetails.book; + final bookViewSettings = ref.watch(bookViewerSettingsProvider); + ref.listen( + bookViewerProvider.select((value) => value.loading), + (previous, next) { + if (previous == true && next == false) { + ref.read(bookViewerProvider.notifier).updatePlayback((widget.initialPage.toDouble()).toInt()); + } + }, + ); + return Theme( + data: ThemesData.of(context).dark, + child: PopScope( + canPop: true, + onPopInvoked: (didPop) async { + await ref.read(bookViewerProvider.notifier).stopPlayback(); + }, + child: Scaffold( + backgroundColor: Colors.black, + body: Stack( + fit: StackFit.expand, + children: [ + if (!loading) + ExtendedImageGesturePageView.builder( + itemCount: pages.length + 2, + controller: extendedController, + canScrollPage: (gestureDetails) { + return bookViewSettings.disableScrollOnZoom + ? gestureDetails != null + ? !(gestureDetails.totalScale! > 1.0) + : true + : true; + }, + onPageChanged: (value) { + final newRange = pages.length + 1 == value || value == 0; + if (outOfRange != newRange) { + viewController.toggleControls(value: newRange); + outOfRange = newRange; + } + ref.read(bookViewerProvider.notifier).updatePlayback(value); + }, + reverse: bookViewSettings.readDirection == ReadDirection.rightToLeft, + itemBuilder: (context, index) { + if (pages.length + 1 == index || index == 0) { + final atEnd = index >= pages.length; + final details = ref.read(widget.provider); + return Padding( + padding: const EdgeInsets.all(16.0), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: bookViewSettings.readDirection != ReadDirection.leftToRight + ? CrossAxisAlignment.start + : CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + if (atEnd) ...{ + Flexible( + child: Text( + "End: \n${book?.name}", + textAlign: TextAlign.start, + style: Theme.of(context).textTheme.titleLarge, + ), + ), + if (details.nextChapter(bookViewerDetails.book) != null) ...{ + const SizedBox(height: 32), + Flexible( + child: Text( + "Next: ", + textAlign: TextAlign.start, + style: Theme.of(context).textTheme.titleLarge, + ), + ), + Flexible( + child: FilledButton( + style: FilledButton.styleFrom(padding: const EdgeInsets.symmetric(horizontal: 8)), + onPressed: () async => + await loadNextBook(details.nextChapter(bookViewerDetails.book)), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.keyboard_arrow_left_rounded), + Text( + details.nextChapter(bookViewerDetails.book)!.name, + style: Theme.of(context).textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.bold, + color: Theme.of(context).colorScheme.onPrimary), + ), + ], + ), + ), + ), + } else ...{ + const SizedBox(height: 32), + Card( + child: Padding( + padding: const EdgeInsets.all(16), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.info_rounded), + const SizedBox(width: 16), + Text("No next chapter"), + ], + ), + ), + ) + } + } else ...{ + Flexible( + child: Text( + "Start: \n${book?.name}", + textAlign: TextAlign.start, + style: Theme.of(context).textTheme.titleLarge, + ), + ), + if (details.previousChapter(bookViewerDetails.book) != null) ...{ + const SizedBox(height: 32), + Flexible( + child: Text( + "Previous:", + textAlign: TextAlign.start, + style: Theme.of(context).textTheme.titleLarge, + ), + ), + Flexible( + child: FilledButton( + style: FilledButton.styleFrom(padding: const EdgeInsets.symmetric(horizontal: 8)), + onPressed: () async => + await loadNextBook(details.previousChapter(bookViewerDetails.book)), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + details.previousChapter(bookViewerDetails.book)!.name, + style: Theme.of(context).textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.bold, + color: Theme.of(context).colorScheme.onPrimary), + ), + const Icon(Icons.keyboard_arrow_right_rounded), + ], + ), + ), + ), + } else ...{ + const SizedBox(height: 32), + Card( + child: Padding( + padding: const EdgeInsets.all(16), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.info_rounded), + const SizedBox(width: 16), + Text("First chapter"), + ], + ), + ), + ) + } + }, + ], + ), + ), + ); + } else { + return BookViewerReader( + index: index, + pages: pages, + bookViewSettings: bookViewSettings, + previousPage: previousPage, + nextPage: nextPage, + viewController: viewController, + lastScale: lastScale, + newScale: (value) => lastScale = value, + ); + } + }, + ), + BookViewerControls( + provider: widget.provider, + viewController: viewController, + controller: extendedController, + ) + ], + ), + ), + ), + ); + } + + Future nextPage() async => + throttler.run(() async => await extendedController.nextPage(duration: pageAnimDuration, curve: pageAnimCurve)); + + Future previousPage() async => throttler + .run(() async => await extendedController.previousPage(duration: pageAnimDuration, curve: pageAnimCurve)); + + Future loadNextBook(BookModel? book) async { + await ref.read(bookViewerProvider.notifier).fetchBook(book); + extendedController.jumpToPage(0); + return; + } +} diff --git a/lib/screens/book_viewer/book_viewer_settings.dart b/lib/screens/book_viewer/book_viewer_settings.dart new file mode 100644 index 0000000..738b4ec --- /dev/null +++ b/lib/screens/book_viewer/book_viewer_settings.dart @@ -0,0 +1,187 @@ +import 'package:fladder/providers/settings/book_viewer_settings_provider.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/string_extensions.dart'; +import 'package:fladder/widgets/shared/enum_selection.dart'; +import 'package:fladder/widgets/shared/fladder_slider.dart'; +import 'package:fladder/widgets/shared/modal_side_sheet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +Future showBookViewerSettings( + BuildContext context, +) async { + if (AdaptiveLayout.of(context).isDesktop) { + return showModalSideSheet(context, content: const BookViewerSettingsScreen()); + } else { + return showModalBottomSheet( + context: context, + showDragHandle: true, + builder: (context) => const BookViewerSettingsScreen(), + ); + } +} + +class BookViewerSettingsScreen extends ConsumerWidget { + const BookViewerSettingsScreen({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final settings = ref.watch(bookViewerSettingsProvider); + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Align( + alignment: Alignment.centerLeft, + child: Text( + "Reader settings", + style: Theme.of(context).textTheme.titleLarge, + ), + ), + ), + const Divider(), + if (!AdaptiveLayout.of(context).isDesktop) ...{ + ListTile( + title: Row( + children: [ + const Text("Screen Brightness"), + Flexible( + child: Opacity( + opacity: settings.screenBrightness == null ? 0.5 : 1, + child: FladderSlider( + value: settings.screenBrightness ?? 1.0, + min: 0, + max: 1, + onChanged: (value) => ref.read(bookViewerSettingsProvider.notifier).setScreenBrightness(value), + ), + ), + ), + IconButton( + onPressed: () => ref.read(bookViewerSettingsProvider.notifier).setScreenBrightness(null), + icon: Opacity( + opacity: settings.screenBrightness != null ? 0.5 : 1, + child: Icon( + Icons.brightness_auto_rounded, + color: Theme.of(context).colorScheme.primary, + ), + ), + ) + ], + ), + ), + }, + ListTile( + title: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Flexible( + child: EnumSelection( + label: const Text("Read direction"), + current: settings.readDirection.name.toUpperCaseSplit(), + itemBuilder: (context) => ReadDirection.values + .map((value) => PopupMenuItem( + value: value, + child: Text(value.name.toUpperCaseSplit()), + onTap: () => ref + .read(bookViewerSettingsProvider.notifier) + .update((state) => state.copyWith(readDirection: value)), + )) + .toList(), + ), + ), + ], + ), + ), + ListTile( + title: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Flexible( + child: EnumSelection( + label: const Text("Init zoom"), + current: settings.initZoomState.name.toUpperCaseSplit(), + itemBuilder: (context) => InitZoomState.values + .map((value) => PopupMenuItem( + value: value, + child: Text(value.name.toUpperCaseSplit()), + onTap: () => ref + .read(bookViewerSettingsProvider.notifier) + .update((state) => state.copyWith(initZoomState: value)), + )) + .toList(), + ), + ), + ], + ), + ), + ListTile( + onTap: () => ref + .read(bookViewerSettingsProvider.notifier) + .update((state) => state.copyWith(disableScrollOnZoom: !settings.disableScrollOnZoom)), + title: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Expanded( + flex: 3, + child: Text("Disable slide page gestures when zoomed"), + ), + const Spacer(), + Switch.adaptive( + value: settings.disableScrollOnZoom, + onChanged: (value) => ref + .read(bookViewerSettingsProvider.notifier) + .update((state) => state.copyWith(disableScrollOnZoom: value)), + ) + ], + ), + ), + ListTile( + onTap: () => ref + .read(bookViewerSettingsProvider.notifier) + .update((state) => state.copyWith(cachePageZoom: !settings.cachePageZoom)), + title: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Expanded( + flex: 3, + child: Text("Cache page zoom state"), + ), + const Spacer(), + Switch.adaptive( + value: settings.cachePageZoom, + onChanged: (value) => ref + .read(bookViewerSettingsProvider.notifier) + .update((incoming) => incoming.copyWith(cachePageZoom: value)), + ) + ], + ), + ), + ListTile( + onTap: () => ref + .read(bookViewerSettingsProvider.notifier) + .update((state) => state.copyWith(keepPageZoom: !settings.keepPageZoom)), + title: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Expanded( + flex: 3, + child: Text("Keep page zoom"), + ), + const Spacer(), + Switch.adaptive( + value: settings.keepPageZoom, + onChanged: (value) => ref + .read(bookViewerSettingsProvider.notifier) + .update((incoming) => incoming.copyWith(keepPageZoom: value)), + ) + ], + ), + ), + SizedBox( + height: MediaQuery.of(context).padding.bottom, + ) + ], + ); + } +} diff --git a/lib/screens/collections/add_to_collection.dart b/lib/screens/collections/add_to_collection.dart new file mode 100644 index 0000000..e64f64a --- /dev/null +++ b/lib/screens/collections/add_to_collection.dart @@ -0,0 +1,174 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/providers/collections_provider.dart'; +import 'package:fladder/screens/shared/adaptive_dialog.dart'; +import 'package:fladder/screens/shared/fladder_snackbar.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/widgets/shared/modal_bottom_sheet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/screens/shared/outlined_text_field.dart'; + +Future addItemToCollection(BuildContext context, List item) { + return showDialogAdaptive( + context: context, + builder: (context) => AddToCollection( + items: item, + ), + ); +} + +class AddToCollection extends ConsumerStatefulWidget { + final List items; + const AddToCollection({required this.items, super.key}); + + @override + ConsumerState createState() => _AddToCollectionState(); +} + +class _AddToCollectionState extends ConsumerState { + final TextEditingController controller = TextEditingController(); + late final provider = collectionsProvider; + + @override + void initState() { + super.initState(); + Future.microtask(() => ref.read(provider.notifier).setItems(widget.items)); + } + + @override + Widget build(BuildContext context) { + final collectonOptions = ref.watch(provider); + return Card( + color: Theme.of(context).colorScheme.surface, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox(height: MediaQuery.paddingOf(context).top), + Container( + color: Theme.of(context).colorScheme.surface, + child: Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + if (widget.items.length == 1) + Text( + 'Add to collection', + style: Theme.of(context).textTheme.titleLarge, + ) + else + Text( + 'Add ${widget.items.length} item(s) to collection', + style: Theme.of(context).textTheme.titleLarge, + ), + IconButton( + onPressed: () => ref.read(provider.notifier).setItems(widget.items), + icon: const Icon(IconsaxOutline.refresh), + ) + ], + ), + ), + if (widget.items.length == 1) ItemBottomSheetPreview(item: widget.items.first), + ], + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: Row( + children: [ + Flexible( + child: OutlinedTextField( + label: 'New collection', + controller: controller, + onChanged: (value) => setState(() {}), + ), + ), + const SizedBox(width: 32), + IconButton( + onPressed: controller.text.isNotEmpty + ? () async { + await ref.read(provider.notifier).addToNewCollection( + name: controller.text, + ); + setState(() => controller.text = ''); + } + : null, + icon: const Icon(Icons.add_rounded)), + const SizedBox(width: 4), + ], + ), + ), + Flexible( + child: ListView( + shrinkWrap: true, + children: [ + ...collectonOptions.collections.entries.map( + (e) { + if (e.value != null) { + return CheckboxListTile.adaptive( + title: Text(e.key.name), + value: e.value, + onChanged: (value) async { + final response = await ref + .read(provider.notifier) + .toggleCollection(boxSet: e.key, value: value == true, item: widget.items.first); + if (context.mounted) { + fladderSnackbar(context, + title: response.isSuccessful + ? "${value == true ? "Added to" : "Removed from"} ${e.key.name} collection" + : 'Unable to ${value == true ? "add to" : "remove from"} ${e.key.name} collection - (${response.statusCode}) - ${response.base.reasonPhrase}'); + } + }, + ); + } else { + return ListTile( + title: Text(e.key.name), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + ElevatedButton( + onPressed: () async { + final response = + await ref.read(provider.notifier).addToCollection(boxSet: e.key, add: true); + if (context.mounted) { + fladderSnackbar(context, + title: response.isSuccessful + ? "Added to ${e.key.name} collection" + : 'Unable to add to ${e.key.name} collection - (${response.statusCode}) - ${response.base.reasonPhrase}'); + } + }, + child: Icon(Icons.add_rounded, color: Theme.of(context).colorScheme.primary), + ), + ], + ), + ); + } + }, + ), + ], + ), + ), + Container( + color: Theme.of(context).colorScheme.surface, + child: Padding( + padding: const EdgeInsets.all(16), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + FilledButton( + onPressed: () => Navigator.of(context).pop(), + child: Text(context.localized.close), + ) + ], + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/screens/dashboard/dashboard_screen.dart b/lib/screens/dashboard/dashboard_screen.dart new file mode 100644 index 0000000..8caf0b7 --- /dev/null +++ b/lib/screens/dashboard/dashboard_screen.dart @@ -0,0 +1,203 @@ +import 'dart:async'; + +import 'package:collection/collection.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/library_search/library_search_options.dart'; +import 'package:fladder/models/settings/home_settings_model.dart'; +import 'package:fladder/providers/dashboard_provider.dart'; +import 'package:fladder/providers/settings/client_settings_provider.dart'; +import 'package:fladder/providers/settings/home_settings_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/providers/views_provider.dart'; +import 'package:fladder/routes/build_routes/home_routes.dart'; +import 'package:fladder/routes/build_routes/route_builder.dart'; +import 'package:fladder/screens/shared/media/carousel_banner.dart'; +import 'package:fladder/screens/shared/media/poster_row.dart'; +import 'package:fladder/screens/shared/nested_scaffold.dart'; +import 'package:fladder/screens/shared/nested_sliver_appbar.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/sliver_list_padding.dart'; +import 'package:fladder/widgets/shared/pinch_poster_zoom.dart'; +import 'package:fladder/widgets/shared/poster_size_slider.dart'; +import 'package:fladder/widgets/shared/pull_to_refresh.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class DashboardScreen extends ConsumerStatefulWidget { + final ScrollController navigationScrollController; + const DashboardScreen({ + required this.navigationScrollController, + super.key, + }); + + @override + ConsumerState createState() => _DashboardScreenState(); +} + +class _DashboardScreenState extends ConsumerState { + late final Timer _timer; + final GlobalKey _refreshIndicatorKey = GlobalKey(); + + @override + void initState() { + super.initState(); + _timer = Timer.periodic(const Duration(seconds: 120), (timer) { + _refreshIndicatorKey.currentState?.show(); + }); + } + + @override + void dispose() { + _timer.cancel(); + super.dispose(); + } + + Future _refreshHome() async { + if (mounted) { + await ref.read(userProvider.notifier).updateInformation(); + await ref.read(viewsProvider.notifier).fetchViews(); + await ref.read(dashboardProvider.notifier).fetchNextUpAndResume(); + } + } + + @override + Widget build(BuildContext context) { + final dashboardData = ref.watch(dashboardProvider); + final views = ref.watch(viewsProvider); + final homeSettings = ref.watch(homeSettingsProvider); + final resumeVideo = dashboardData.resumeVideo; + final resumeAudio = dashboardData.resumeAudio; + final resumeBooks = dashboardData.resumeBooks; + + final allResume = [...resumeVideo, ...resumeAudio, ...resumeBooks].toList(); + + final homeCarouselItems = switch (homeSettings.carouselSettings) { + HomeCarouselSettings.nextUp => dashboardData.nextUp, + HomeCarouselSettings.combined => [...allResume, ...dashboardData.nextUp], + HomeCarouselSettings.cont => allResume, + _ => [...allResume, ...dashboardData.nextUp], + }; + + return MediaQuery.removeViewInsets( + context: context, + child: NestedScaffold( + body: PullToRefresh( + refreshKey: _refreshIndicatorKey, + displacement: 80 + MediaQuery.of(context).viewPadding.top, + onRefresh: () async => await _refreshHome(), + child: PinchPosterZoom( + scaleDifference: (difference) => ref.read(clientSettingsProvider.notifier).addPosterSize(difference), + child: CustomScrollView( + physics: const AlwaysScrollableScrollPhysics(), + controller: widget.navigationScrollController, + slivers: [ + if (AdaptiveLayout.of(context).layout == LayoutState.phone) + NestedSliverAppBar( + route: LibrarySearchRoute(), + parent: context, + ), + if (homeSettings.carouselSettings != HomeCarouselSettings.off && homeCarouselItems.isNotEmpty) ...{ + SliverToBoxAdapter( + child: Transform.translate( + offset: Offset(0, AdaptiveLayout.layoutOf(context) == LayoutState.phone ? -14 : 0), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: AdaptiveLayout.of(context).isDesktop ? 350 : 275, + maxHeight: (MediaQuery.sizeOf(context).height * 0.25).clamp(400, double.infinity)), + child: AspectRatio( + aspectRatio: 1.6, + child: SizedBox( + width: MediaQuery.of(context).size.width, + child: CarouselBanner( + items: homeCarouselItems, + ), + ), + ), + ), + ), + ), + } else if (AdaptiveLayout.of(context).isDesktop) + DefaultSliverTopBadding(), + if (AdaptiveLayout.of(context).isDesktop) + SliverToBoxAdapter( + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + PosterSizeWidget(), + ], + ), + ), + ...[ + if (resumeVideo.isNotEmpty && + (homeSettings.nextUp == HomeNextUp.cont || homeSettings.nextUp == HomeNextUp.separate)) + SliverToBoxAdapter( + child: PosterRow( + label: context.localized.dashboardContinueWatching, + posters: resumeVideo, + ), + ), + if (resumeAudio.isNotEmpty && + (homeSettings.nextUp == HomeNextUp.cont || homeSettings.nextUp == HomeNextUp.separate)) + SliverToBoxAdapter( + child: PosterRow( + label: context.localized.dashboardContinueListening, + posters: resumeAudio, + ), + ), + if (resumeBooks.isNotEmpty && + (homeSettings.nextUp == HomeNextUp.cont || homeSettings.nextUp == HomeNextUp.separate)) + SliverToBoxAdapter( + child: PosterRow( + label: context.localized.dashboardContinueReading, + posters: resumeBooks, + ), + ), + if (dashboardData.nextUp.isNotEmpty && + (homeSettings.nextUp == HomeNextUp.nextUp || homeSettings.nextUp == HomeNextUp.separate)) + SliverToBoxAdapter( + child: PosterRow( + label: context.localized.dashboardNextUp, + posters: dashboardData.nextUp, + ), + ), + if ([...allResume, ...dashboardData.nextUp].isNotEmpty && homeSettings.nextUp == HomeNextUp.combined) + SliverToBoxAdapter( + child: PosterRow( + label: context.localized.dashboardContinue, + posters: [...allResume, ...dashboardData.nextUp], + ), + ), + ...views.dashboardViews + .where((element) => element.recentlyAdded.isNotEmpty) + .map((view) => SliverToBoxAdapter( + child: PosterRow( + label: context.localized.dashboardRecentlyAdded(view.name), + onLabelClick: () => context.routePushOrGo(LibrarySearchRoute( + id: view.id, + sortOptions: switch (view.collectionType) { + CollectionType.tvshows || + CollectionType.books || + CollectionType.boxsets || + CollectionType.folders || + CollectionType.music => + SortingOptions.dateLastContentAdded, + _ => SortingOptions.dateAdded, + }, + sortOrder: SortOrder.descending, + )), + posters: view.recentlyAdded, + ), + )), + ].whereNotNull().toList().addInBetween(SliverToBoxAdapter(child: SizedBox(height: 16))), + const DefautlSliverBottomPadding(), + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/screens/details_screens/book_detail_screen.dart b/lib/screens/details_screens/book_detail_screen.dart new file mode 100644 index 0000000..1db996c --- /dev/null +++ b/lib/screens/details_screens/book_detail_screen.dart @@ -0,0 +1,228 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/book_model.dart'; +import 'package:fladder/providers/items/book_details_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/screens/details_screens/components/overview_header.dart'; +import 'package:fladder/screens/shared/detail_scaffold.dart'; +import 'package:fladder/screens/shared/media/components/media_play_button.dart'; +import 'package:fladder/screens/shared/media/expanding_overview.dart'; +import 'package:fladder/screens/shared/media/poster_list_item.dart'; +import 'package:fladder/util/fladder_image.dart'; +import 'package:fladder/util/item_base_model/item_base_model_extensions.dart'; +import 'package:fladder/util/item_base_model/play_item_helpers.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/widget_extensions.dart'; +import 'package:fladder/widgets/shared/item_actions.dart'; +import 'package:fladder/widgets/shared/modal_bottom_sheet.dart'; +import 'package:fladder/widgets/shared/selectable_icon_button.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; + +class BookDetailScreen extends ConsumerStatefulWidget { + final BookModel item; + const BookDetailScreen({required this.item, super.key}); + + @override + ConsumerState createState() => _BookDetailScreenState(); +} + +class _BookDetailScreenState extends ConsumerState { + late final provider = bookDetailsProvider(widget.item.id); + + @override + Widget build(BuildContext context) { + final details = ref.watch(provider); + return DetailScaffold( + label: widget.item.name, + item: details.book, + actions: (context) => details.book?.generateActions( + context, + ref, + exclude: { + ItemActions.play, + ItemActions.playFromStart, + ItemActions.details, + }, + onDeleteSuccesFully: (item) { + if (context.mounted) { + context.pop(); + } + }, + ), + backgroundColor: Theme.of(context).colorScheme.surface.withOpacity(0.8), + onRefresh: () async => await ref.read(provider.notifier).fetchDetails(widget.item), + backDrops: details.cover, + content: (padding) => details.book != null + ? Padding( + padding: const EdgeInsets.only(bottom: 64), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + SizedBox(height: MediaQuery.of(context).size.height * 0.2), + if (MediaQuery.sizeOf(context).width < 500) + Center( + child: ConstrainedBox( + constraints: BoxConstraints(maxWidth: MediaQuery.sizeOf(context).width * 0.75), + child: AspectRatio( + aspectRatio: 0.76, + child: Card( + child: FladderImage(image: details.cover?.primary), + ), + ), + ).padding(padding), + ), + Row( + children: [ + if (MediaQuery.sizeOf(context).width > 500) ...{ + ConstrainedBox( + constraints: BoxConstraints( + maxWidth: MediaQuery.sizeOf(context).width * 0.3, + maxHeight: MediaQuery.sizeOf(context).height * 0.75), + child: AspectRatio( + aspectRatio: 0.76, + child: Card( + child: FladderImage(image: details.cover?.primary), + ), + ), + ), + const SizedBox(width: 32), + }, + Flexible( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (details.nextUp != null) + OverviewHeader( + subTitle: details.book!.parentName ?? details.parentModel?.name, + name: details.nextUp!.name, + productionYear: details.nextUp!.overview.productionYear, + runTime: details.nextUp!.overview.runTime, + genres: details.nextUp!.overview.genreItems, + studios: details.nextUp!.overview.studios, + officialRating: details.nextUp!.overview.parentalRating, + communityRating: details.nextUp!.overview.communityRating, + externalUrls: details.nextUp!.overview.externalUrls, + ), + const SizedBox(height: 16), + Wrap( + spacing: 8, + runSpacing: 8, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + //Wrapped so the correct context is used for refreshing the pages + Builder( + builder: (context) { + return MediaPlayButton( + item: details.nextUp!, + onPressed: () async => details.nextUp.play(context, ref, provider: provider)); + }, + ), + if (details.parentModel != null) + SelectableIconButton( + onPressed: () async => await details.parentModel?.navigateTo(context), + selected: false, + selectedIcon: IconsaxBold.book, + icon: IconsaxOutline.book, + ), + if (details.parentModel != null) + SelectableIconButton( + onPressed: () async => await ref.read(userProvider.notifier).setAsFavorite( + !details.parentModel!.userData.isFavourite, details.parentModel!.id), + selected: details.parentModel!.userData.isFavourite, + selectedIcon: IconsaxBold.heart, + icon: IconsaxOutline.heart, + ) + else + SelectableIconButton( + onPressed: () async => await ref + .read(userProvider.notifier) + .setAsFavorite(!details.book!.userData.isFavourite, details.book!.id), + selected: details.book!.userData.isFavourite, + selectedIcon: IconsaxBold.heart, + icon: IconsaxOutline.heart, + ), + + //This one toggles all books in a collection + Builder(builder: (context) { + return Tooltip( + message: "Mark all chapters as read", + child: SelectableIconButton( + onPressed: () async => await Future.forEach( + details.allBooks, + (element) async => await ref + .read(userProvider.notifier) + .markAsPlayed(!details.collectionPlayed, element.id)), + selected: details.collectionPlayed, + selectedIcon: Icons.check_circle_rounded, + icon: Icons.check_circle_outline_rounded, + ), + ); + }), + ], + ) + ], + ), + ), + ], + ).padding(padding), + if (details.nextUp!.overview.summary.isNotEmpty == true) + ExpandingOverview( + text: details.nextUp!.overview.summary, + ).padding(padding), + if (details.chapters.length > 1) + Builder(builder: (context) { + final parentContext = context; + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(context.localized.chapter(details.chapters.length), + style: Theme.of(context).textTheme.titleLarge), + const Padding( + padding: EdgeInsets.symmetric(vertical: 16), + child: Divider(), + ), + ...details.chapters.map( + (e) { + final current = e == details.nextUp; + return Padding( + padding: const EdgeInsets.only(bottom: 2), + child: Opacity( + opacity: e.userData.played ? 0.65 : 1, + child: Card( + color: current ? Theme.of(context).colorScheme.surfaceContainerHighest : null, + child: PosterListItem( + poster: e, + onPressed: (action, item) => showBottomSheetPill( + context: context, + item: item, + content: (context, scrollController) => ListView( + shrinkWrap: true, + controller: scrollController, + children: item + .generateActions( + parentContext, + ref, + ) + .listTileItems(context, useIcons: true), + ), + ), + ), + ), + ), + ); + }, + ) + ], + ).padding(padding); + }) + ].addPadding(const EdgeInsets.symmetric(vertical: 16)), + ), + ) + : Container(), + ); + } +} diff --git a/lib/screens/details_screens/components/label_title_item.dart b/lib/screens/details_screens/components/label_title_item.dart new file mode 100644 index 0000000..69a7ebe --- /dev/null +++ b/lib/screens/details_screens/components/label_title_item.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; + +import 'package:collection/collection.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class LabelTitleItem extends ConsumerWidget { + final Text? title; + final String? label; + final Widget? content; + const LabelTitleItem({ + this.title, + this.label, + this.content, + super.key, + }) : assert(label != null || content != null); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Material( + color: Colors.transparent, + textStyle: Theme.of(context).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.bold), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Opacity( + opacity: 0.6, + child: Material( + color: Colors.transparent, textStyle: Theme.of(context).textTheme.titleMedium, child: title)), + const SizedBox(width: 12), + label != null + ? SelectableText( + label!, + ) + : content!, + ].whereNotNull().toList(), + ), + ); + } +} diff --git a/lib/screens/details_screens/components/media_stream_information.dart b/lib/screens/details_screens/components/media_stream_information.dart new file mode 100644 index 0000000..b659b27 --- /dev/null +++ b/lib/screens/details_screens/components/media_stream_information.dart @@ -0,0 +1,146 @@ +import 'package:fladder/util/localization_helper.dart'; +import 'package:flutter/material.dart'; + +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/models/items/media_streams_model.dart'; +import 'package:fladder/screens/details_screens/components/label_title_item.dart'; + +class MediaStreamInformation extends ConsumerWidget { + final MediaStreamsModel mediaStream; + final Function(int index)? onAudioIndexChanged; + final Function(int index)? onSubIndexChanged; + const MediaStreamInformation( + {required this.mediaStream, this.onAudioIndexChanged, this.onSubIndexChanged, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (mediaStream.videoStreams.isNotEmpty) + _StreamOptionSelect( + label: Text(context.localized.video), + current: (mediaStream.videoStreams.first).prettyName, + itemBuilder: (context) => mediaStream.videoStreams + .map( + (e) => PopupMenuItem( + value: e, + child: Text(e.prettyName), + onTap: () {}, + ), + ) + .toList(), + ), + if (mediaStream.audioStreams.isNotEmpty) + _StreamOptionSelect( + label: Text(context.localized.audio), + current: mediaStream.currentAudioStream?.displayTitle ?? "", + itemBuilder: (context) => mediaStream.audioStreams + .map( + (e) => PopupMenuItem( + value: e, + padding: EdgeInsets.zero, + child: textWidget(context, selected: mediaStream.currentAudioStream == e, label: e.displayTitle), + onTap: () => onAudioIndexChanged?.call(e.index), + ), + ) + .toList(), + ), + if (mediaStream.subStreams.isNotEmpty) + _StreamOptionSelect( + label: Text(context.localized.subtitles), + current: mediaStream.currentSubStream?.displayTitle ?? "", + itemBuilder: (context) => [SubStreamModel.no(), ...mediaStream.subStreams] + .map( + (e) => PopupMenuItem( + value: e, + padding: EdgeInsets.zero, + child: textWidget(context, selected: mediaStream.currentSubStream == e, label: e.displayTitle), + onTap: () => onSubIndexChanged?.call(e.index), + ), + ) + .toList(), + ), + ], + ); + } + + Widget textWidget(BuildContext context, {required bool selected, required String label}) { + return Container( + height: kMinInteractiveDimension, + width: double.maxFinite, + color: selected ? Theme.of(context).colorScheme.primary : null, + alignment: Alignment.centerLeft, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: Text( + label, + style: Theme.of(context).textTheme.labelLarge?.copyWith( + color: selected ? Theme.of(context).colorScheme.onPrimary : null, + fontWeight: FontWeight.bold, + ), + ), + ), + ); + } +} + +class _StreamOptionSelect extends StatelessWidget { + final Text label; + final String current; + final List> Function(BuildContext context) itemBuilder; + const _StreamOptionSelect({ + required this.label, + required this.current, + required this.itemBuilder, + }); + + @override + Widget build(BuildContext context) { + final textStyle = Theme.of(context).textTheme.titleMedium; + const padding = EdgeInsets.all(6.0); + final itemList = itemBuilder(context); + return LabelTitleItem( + title: label, + content: Flexible( + child: PopupMenuButton( + tooltip: '', + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), + enabled: itemList.length > 1, + itemBuilder: itemBuilder, + padding: padding, + child: Padding( + padding: padding, + child: Material( + textStyle: textStyle?.copyWith( + fontWeight: FontWeight.bold, + color: itemList.length > 1 ? Theme.of(context).colorScheme.primary : null), + color: Colors.transparent, + child: Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Flexible( + child: Text( + current, + textAlign: TextAlign.start, + ), + ), + const SizedBox(width: 6), + if (itemList.length > 1) + Icon( + Icons.keyboard_arrow_down, + color: Theme.of(context).colorScheme.primary, + ) + ], + ), + ), + ), + ), + ), + ); + } +} diff --git a/lib/screens/details_screens/components/overview_header.dart b/lib/screens/details_screens/components/overview_header.dart new file mode 100644 index 0000000..3e894a3 --- /dev/null +++ b/lib/screens/details_screens/components/overview_header.dart @@ -0,0 +1,165 @@ +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/screens/shared/media/components/small_detail_widgets.dart'; +import 'package:fladder/screens/shared/media/external_urls.dart'; +import 'package:fladder/util/humanize_duration.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class OverviewHeader extends ConsumerWidget { + final String name; + final EdgeInsets? padding; + final String? subTitle; + final String? originalTitle; + final Function()? onTitleClicked; + final int? productionYear; + final Duration? runTime; + final String? officialRating; + final double? communityRating; + final List studios; + final List genres; + final List? externalUrls; + final List actions; + const OverviewHeader({ + required this.name, + this.padding, + this.subTitle, + this.originalTitle, + this.onTitleClicked, + this.productionYear, + this.runTime, + this.officialRating, + this.communityRating, + this.externalUrls, + this.genres = const [], + this.studios = const [], + this.actions = const [], + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final mainStyle = Theme.of(context).textTheme.headlineMedium?.copyWith( + fontWeight: FontWeight.bold, + ); + final subStyle = Theme.of(context).textTheme.titleMedium?.copyWith( + fontSize: 20, + ); + + return Padding( + padding: padding ?? EdgeInsets.zero, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + const SizedBox(height: 32), + if (subTitle == null) + Flexible( + child: SelectableText( + name, + style: mainStyle, + ), + ) + else ...{ + Flexible( + child: SelectableText( + subTitle ?? "", + style: mainStyle, + ), + ), + Flexible( + child: Opacity( + opacity: 0.75, + child: Row( + children: [ + Flexible( + child: SelectableText( + name, + style: subStyle, + onTap: onTitleClicked, + ), + ), + if (onTitleClicked != null) + IconButton( + onPressed: onTitleClicked, + icon: Transform.translate(offset: Offset(0, 1.5), child: Icon(Icons.read_more_rounded))) + ], + ), + ), + ), + }, + if (name != originalTitle && originalTitle != null) + SelectableText( + originalTitle.toString(), + style: subStyle, + ), + const SizedBox(height: 6), + Wrap( + spacing: 8, + runSpacing: 8, + alignment: WrapAlignment.start, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + if (productionYear != null) + SelectableText( + productionYear.toString(), + style: subStyle, + ), + if (runTime != null && (runTime?.inSeconds ?? 0) > 1) + SelectableText( + runTime.humanize.toString(), + style: subStyle, + ), + if (officialRating != null) + Card( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 8), + child: SelectableText( + officialRating.toString(), + style: subStyle, + ), + ), + ), + if (communityRating != null) + Row( + children: [ + Icon( + Icons.star_rate_rounded, + color: Theme.of(context).colorScheme.primary, + ), + Text( + communityRating?.toStringAsFixed(1) ?? "", + style: subStyle, + ), + ], + ), + ], + ), + const SizedBox(height: 6), + if (studios.isNotEmpty) + Text( + "${context.localized.watchOn} ${studios.map((e) => e.name).first}", + style: subStyle?.copyWith(fontSize: 16, color: Colors.grey), + ), + const SizedBox(height: 6), + if (externalUrls?.isNotEmpty ?? false) + ExternalUrlsRow( + urls: externalUrls, + ), + const SizedBox(height: 6), + if (genres.isNotEmpty) + Genres( + genres: genres.take(10).toList(), + ), + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: actions.addPadding( + const EdgeInsets.symmetric(horizontal: 6), + ), + ), + ], + ), + ); + } +} diff --git a/lib/screens/details_screens/details_screens.dart b/lib/screens/details_screens/details_screens.dart new file mode 100644 index 0000000..7b99ce7 --- /dev/null +++ b/lib/screens/details_screens/details_screens.dart @@ -0,0 +1,4 @@ +export 'movie_detail_screen.dart'; +export 'series_detail_screen.dart'; +export 'person_detail_screen.dart'; +export 'empty_item.dart'; diff --git a/lib/screens/details_screens/empty_item.dart b/lib/screens/details_screens/empty_item.dart new file mode 100644 index 0000000..e40b065 --- /dev/null +++ b/lib/screens/details_screens/empty_item.dart @@ -0,0 +1,19 @@ +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/screens/shared/detail_scaffold.dart'; +import 'package:fladder/util/string_extensions.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class EmptyItem extends ConsumerWidget { + final ItemBaseModel item; + const EmptyItem({required this.item, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return DetailScaffold( + label: "Empty", + content: (padding) => + Center(child: Text("Type of (Jelly.${item.jellyType?.name.capitalize()}) has not been implemented yet.")), + ); + } +} diff --git a/lib/screens/details_screens/episode_detail_screen.dart b/lib/screens/details_screens/episode_detail_screen.dart new file mode 100644 index 0000000..3326acd --- /dev/null +++ b/lib/screens/details_screens/episode_detail_screen.dart @@ -0,0 +1,176 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/screens/details_screens/components/overview_header.dart'; +import 'package:fladder/screens/shared/media/components/media_play_button.dart'; +import 'package:fladder/util/item_base_model/item_base_model_extensions.dart'; +import 'package:fladder/util/item_base_model/play_item_helpers.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:flutter/material.dart'; + +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/providers/items/episode_details_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/screens/details_screens/components/media_stream_information.dart'; +import 'package:fladder/screens/shared/detail_scaffold.dart'; +import 'package:fladder/screens/shared/fladder_snackbar.dart'; +import 'package:fladder/screens/shared/media/chapter_row.dart'; +import 'package:fladder/screens/shared/media/components/media_header.dart'; +import 'package:fladder/screens/shared/media/episode_posters.dart'; +import 'package:fladder/screens/shared/media/expanding_overview.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/widget_extensions.dart'; +import 'package:fladder/widgets/shared/selectable_icon_button.dart'; +import 'package:go_router/go_router.dart'; + +class EpisodeDetailScreen extends ConsumerStatefulWidget { + final ItemBaseModel item; + const EpisodeDetailScreen({required this.item, super.key}); + + @override + ConsumerState createState() => _ItemDetailScreenState(); +} + +class _ItemDetailScreenState extends ConsumerState { + late final providerInstance = episodeDetailsProvider(widget.item.id); + + @override + Widget build(BuildContext context) { + final details = ref.watch(providerInstance); + final seasonDetails = details.series; + final episodeDetails = details.episode; + + return DetailScaffold( + label: widget.item.name, + item: details.episode, + actions: (context) => details.episode?.generateActions( + context, + ref, + exclude: { + if (details.series == null) ItemActions.openShow, + ItemActions.details, + }, + onDeleteSuccesFully: (item) { + if (context.mounted) { + context.pop(); + } + }, + ), + onRefresh: () async => await ref.read(providerInstance.notifier).fetchDetails(widget.item), + backDrops: details.episode?.images ?? details.series?.images, + content: (padding) => seasonDetails != null && episodeDetails != null + ? Padding( + padding: const EdgeInsets.only(bottom: 64), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + SizedBox(height: MediaQuery.of(context).size.height * 0.35), + MediaHeader( + name: details.series?.name ?? "", + logo: seasonDetails.images?.logo, + ), + OverviewHeader( + name: details.series?.name ?? "", + padding: padding, + subTitle: details.episode?.name, + originalTitle: details.series?.originalTitle, + onTitleClicked: () => details.series?.navigateTo(context), + productionYear: details.series?.overview.productionYear, + runTime: details.episode?.overview.runTime, + studios: details.series?.overview.studios ?? [], + genres: details.series?.overview.genreItems ?? [], + officialRating: details.series?.overview.parentalRating, + communityRating: details.series?.overview.communityRating, + externalUrls: details.series?.overview.externalUrls, + ), + Wrap( + spacing: 8, + runSpacing: 8, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + if (episodeDetails.playAble) + MediaPlayButton( + item: episodeDetails, + onPressed: () async { + await details.episode.play(context, ref); + ref.read(providerInstance.notifier).fetchDetails(widget.item); + }, + onLongPressed: () async { + await details.episode.play(context, ref, showPlaybackOption: true); + ref.read(providerInstance.notifier).fetchDetails(widget.item); + }, + ), + SelectableIconButton( + onPressed: () async { + await ref + .read(userProvider.notifier) + .setAsFavorite(!(episodeDetails.userData.isFavourite), episodeDetails.id); + }, + selected: episodeDetails.userData.isFavourite, + selectedIcon: IconsaxBold.heart, + icon: IconsaxOutline.heart, + ), + SelectableIconButton( + onPressed: () async { + await ref + .read(userProvider.notifier) + .markAsPlayed(!(episodeDetails.userData.played), episodeDetails.id); + }, + selected: episodeDetails.userData.played, + selectedIcon: IconsaxBold.tick_circle, + icon: IconsaxOutline.tick_circle, + ), + ].addPadding(const EdgeInsets.symmetric(horizontal: 6)), + ).padding(padding), + if (details.episode?.mediaStreams != null) + Padding( + padding: padding, + child: MediaStreamInformation( + mediaStream: details.episode!.mediaStreams, + onSubIndexChanged: (index) { + ref.read(providerInstance.notifier).setSubIndex(index); + }, + onAudioIndexChanged: (index) { + ref.read(providerInstance.notifier).setAudioIndex(index); + }, + ), + ), + if (episodeDetails.overview.summary.isNotEmpty == true) + ExpandingOverview( + text: episodeDetails.overview.summary, + ).padding(padding), + if (episodeDetails.chapters.isNotEmpty) + ChapterRow( + chapters: episodeDetails.chapters, + contentPadding: padding, + onPressed: (chapter) async { + await details.episode?.play(context, ref, startPosition: chapter.startPosition); + ref.read(providerInstance.notifier).fetchDetails(widget.item); + }, + ), + if (details.episodes.length > 1) + EpisodePosters( + contentPadding: padding, + label: context.localized + .moreFrom("${context.localized.season(1).toLowerCase()} ${episodeDetails.season}"), + onEpisodeTap: (action, episodeModel) { + if (episodeModel.id == episodeDetails.id) { + fladderSnackbar(context, title: context.localized.selectedWith(context.localized.episode(0))); + } else { + action(); + } + }, + playEpisode: (episode) => episode.play( + context, + ref, + ), + episodes: details.episodes.where((element) => element.season == episodeDetails.season).toList(), + ), + ].addPadding(const EdgeInsets.symmetric(vertical: 16)), + ), + ) + : Container(), + ); + } +} diff --git a/lib/screens/details_screens/folder_detail_screen.dart b/lib/screens/details_screens/folder_detail_screen.dart new file mode 100644 index 0000000..942dee2 --- /dev/null +++ b/lib/screens/details_screens/folder_detail_screen.dart @@ -0,0 +1,59 @@ +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/photos_model.dart'; +import 'package:fladder/providers/items/folder_details_provider.dart'; +import 'package:fladder/screens/photo_viewer/photo_viewer_screen.dart'; +import 'package:fladder/screens/shared/media/poster_grid.dart'; +import 'package:fladder/widgets/shared/pull_to_refresh.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:page_transition/page_transition.dart'; + +class FolderDetailScreen extends ConsumerWidget { + final ItemBaseModel item; + const FolderDetailScreen({required this.item, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final providerInstance = folderDetailsProvider(item.id); + final details = ref.watch(providerInstance); + + return PullToRefresh( + child: Scaffold( + appBar: AppBar( + title: Text( + details?.name ?? "", + )), + body: ListView( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: PosterGrid( + posters: details?.items ?? [], + onPressed: (action, item) async { + switch (item) { + case PhotoModel photoModel: + final photoItems = details?.items.whereType().toList(); + await Navigator.of(context, rootNavigator: true).push(PageTransition( + child: PhotoViewerScreen( + items: photoItems, + indexOfSelected: photoItems?.indexOf(photoModel) ?? 0, + ), + type: PageTransitionType.fade)); + break; + default: + if (context.mounted) { + await item.navigateTo(context); + } + } + }, + ), + ) + ], + ), + ), + onRefresh: () async { + await ref.read(providerInstance.notifier).fetchDetails(item.id); + }, + ); + } +} diff --git a/lib/screens/details_screens/movie_detail_screen.dart b/lib/screens/details_screens/movie_detail_screen.dart new file mode 100644 index 0000000..3f093b8 --- /dev/null +++ b/lib/screens/details_screens/movie_detail_screen.dart @@ -0,0 +1,164 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/providers/items/movies_details_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/screens/details_screens/components/overview_header.dart'; +import 'package:fladder/screens/details_screens/components/media_stream_information.dart'; +import 'package:fladder/screens/shared/media/components/media_header.dart'; +import 'package:fladder/screens/shared/detail_scaffold.dart'; +import 'package:fladder/screens/shared/media/chapter_row.dart'; +import 'package:fladder/screens/shared/media/components/media_play_button.dart'; +import 'package:fladder/screens/shared/media/expanding_overview.dart'; +import 'package:fladder/screens/shared/media/people_row.dart'; +import 'package:fladder/screens/shared/media/poster_row.dart'; +import 'package:fladder/util/item_base_model/item_base_model_extensions.dart'; +import 'package:fladder/util/item_base_model/play_item_helpers.dart'; + +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/widget_extensions.dart'; +import 'package:fladder/widgets/shared/selectable_icon_button.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; + +class MovieDetailScreen extends ConsumerStatefulWidget { + final ItemBaseModel item; + const MovieDetailScreen({required this.item, super.key}); + + @override + ConsumerState createState() => _ItemDetailScreenState(); +} + +class _ItemDetailScreenState extends ConsumerState { + late final providerInstance = movieDetailsProvider(widget.item.id); + + @override + Widget build(BuildContext context) { + final details = ref.watch(providerInstance); + + return DetailScaffold( + label: widget.item.name, + item: details, + actions: (context) => details?.generateActions( + context, + ref, + exclude: { + ItemActions.play, + ItemActions.playFromStart, + ItemActions.details, + }, + onDeleteSuccesFully: (item) { + if (context.mounted) { + context.pop(); + } + }, + ), + onRefresh: () async => await ref.read(providerInstance.notifier).fetchDetails(widget.item), + backDrops: details?.images, + content: (padding) => details != null + ? Padding( + padding: const EdgeInsets.only(bottom: 64), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + SizedBox(height: MediaQuery.of(context).size.height * 0.25), + MediaHeader( + name: details.name, + logo: details.images?.logo, + ), + OverviewHeader( + name: details.name, + padding: padding, + originalTitle: details.originalTitle, + productionYear: details.overview.productionYear, + runTime: details.overview.runTime, + genres: details.overview.genreItems, + studios: details.overview.studios, + officialRating: details.overview.parentalRating, + communityRating: details.overview.communityRating, + externalUrls: details.overview.externalUrls, + ), + Wrap( + spacing: 8, + runSpacing: 8, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + MediaPlayButton( + item: details, + onLongPressed: () async { + await details.play( + context, + ref, + showPlaybackOption: true, + ); + ref.read(providerInstance.notifier).fetchDetails(widget.item); + }, + onPressed: () async { + await details.play( + context, + ref, + ); + ref.read(providerInstance.notifier).fetchDetails(widget.item); + }, + ), + SelectableIconButton( + onPressed: () async { + await ref + .read(userProvider.notifier) + .setAsFavorite(!details.userData.isFavourite, details.id); + }, + selected: details.userData.isFavourite, + selectedIcon: IconsaxBold.heart, + icon: IconsaxOutline.heart, + ), + SelectableIconButton( + onPressed: () async { + await ref.read(userProvider.notifier).markAsPlayed(!details.userData.played, details.id); + }, + selected: details.userData.played, + selectedIcon: IconsaxBold.tick_circle, + icon: IconsaxOutline.tick_circle, + ), + ], + ).padding(padding), + if (details.mediaStreams.isNotEmpty) + MediaStreamInformation( + onSubIndexChanged: (index) { + ref.read(providerInstance.notifier).setSubIndex(index); + }, + onAudioIndexChanged: (index) { + ref.read(providerInstance.notifier).setAudioIndex(index); + }, + mediaStream: details.mediaStreams, + ).padding(padding), + if (details.overview.summary.isNotEmpty == true) + ExpandingOverview( + text: details.overview.summary, + ).padding(padding), + if (details.chapters.isNotEmpty) + ChapterRow( + chapters: details.chapters, + contentPadding: padding, + onPressed: (chapter) { + details.play( + context, + ref, + startPosition: chapter.startPosition, + ); + }, + ), + if (details.overview.people.isNotEmpty) + PeopleRow( + people: details.overview.people, + contentPadding: padding, + ), + if (details.related.isNotEmpty) + PosterRow(posters: details.related, contentPadding: padding, label: "Related"), + ].addPadding(const EdgeInsets.symmetric(vertical: 16)), + ), + ) + : Container(), + ); + } +} diff --git a/lib/screens/details_screens/person_detail_screen.dart b/lib/screens/details_screens/person_detail_screen.dart new file mode 100644 index 0000000..d37c6c7 --- /dev/null +++ b/lib/screens/details_screens/person_detail_screen.dart @@ -0,0 +1,127 @@ +import 'package:collection/collection.dart'; +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/providers/items/person_details_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/screens/shared/detail_scaffold.dart'; +import 'package:fladder/screens/shared/media/external_urls.dart'; +import 'package:fladder/screens/shared/media/poster_row.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/fladder_image.dart'; +import 'package:fladder/util/list_extensions.dart'; +import 'package:fladder/util/string_extensions.dart'; +import 'package:fladder/util/widget_extensions.dart'; +import 'package:fladder/widgets/shared/selectable_icon_button.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:intl/intl.dart'; + +class PersonDetailScreen extends ConsumerStatefulWidget { + final Person person; + const PersonDetailScreen({required this.person, super.key}); + + @override + ConsumerState createState() => _PersonDetailScreenState(); +} + +class _PersonDetailScreenState extends ConsumerState { + late final providerID = personDetailsProvider(widget.person.id); + + @override + Widget build(BuildContext context) { + final details = ref.watch(providerID); + return DetailScaffold( + label: details?.name ?? "", + onRefresh: () async { + await ref.read(providerID.notifier).fetchPerson(widget.person); + }, + backDrops: [...?details?.movies, ...?details?.series].random().firstOrNull?.images, + content: (padding) => Column( + mainAxisSize: MainAxisSize.max, + children: [ + SizedBox(height: MediaQuery.of(context).size.height / 6), + Padding( + padding: padding, + child: Wrap( + alignment: WrapAlignment.center, + runAlignment: WrapAlignment.spaceEvenly, + crossAxisAlignment: WrapCrossAlignment.center, + runSpacing: 32, + spacing: 32, + children: [ + Container( + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15), + ), + width: AdaptiveLayout.of(context).layout == LayoutState.phone + ? MediaQuery.of(context).size.width + : MediaQuery.of(context).size.width / 3.5, + child: AspectRatio( + aspectRatio: 0.70, + child: FladderImage( + fit: BoxFit.cover, + placeHolder: placeHolder(details?.name ?? ""), + image: details?.images?.primary, + ), + ), + ), + Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric(vertical: 32), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Flexible(child: Text(details?.name ?? "", style: Theme.of(context).textTheme.displaySmall)), + const SizedBox(width: 15), + SelectableIconButton( + onPressed: () async => await ref + .read(userProvider.notifier) + .setAsFavorite(!(details?.userData.isFavourite ?? false), details?.id ?? ""), + selected: (details?.userData.isFavourite ?? false), + selectedIcon: Icons.favorite_rounded, + icon: Icons.favorite_border_rounded, + ), + ], + ), + ), + if (details?.dateOfBirth != null) + Text("Birthday: ${DateFormat.yMEd().format(details?.dateOfBirth ?? DateTime.now()).toString()}"), + if (details?.age != null) Text("Age: ${details?.age}"), + if (details?.birthPlace.isEmpty == false) Text("Born in ${details?.birthPlace.join(",")}"), + if (details?.overview.externalUrls?.isNotEmpty ?? false) + ExternalUrlsRow( + urls: details?.overview.externalUrls, + ).padding(padding), + ], + ), + ], + ), + ), + const SizedBox(height: 32), + if (details?.movies.isNotEmpty ?? false) + PosterRow(contentPadding: padding, posters: details?.movies ?? [], label: "Movies"), + if (details?.series.isNotEmpty ?? false) + PosterRow(contentPadding: padding, posters: details?.series ?? [], label: "Series") + ], + ), + ); + } + + Widget placeHolder(String name) { + return Container( + color: Theme.of(context).colorScheme.surfaceContainerHighest, + child: FractionallySizedBox( + widthFactor: 0.4, + child: Card( + shape: const CircleBorder(), + child: Center( + child: Text( + name.getInitials(), + style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold), + )), + ), + ), + ); + } +} diff --git a/lib/screens/details_screens/season_detail_screen.dart b/lib/screens/details_screens/season_detail_screen.dart new file mode 100644 index 0000000..b21b9c6 --- /dev/null +++ b/lib/screens/details_screens/season_detail_screen.dart @@ -0,0 +1,185 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/providers/items/season_details_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/screens/details_screens/components/overview_header.dart'; +import 'package:fladder/screens/shared/detail_scaffold.dart'; +import 'package:fladder/screens/shared/media/components/media_header.dart'; +import 'package:fladder/screens/shared/media/episode_details_list.dart'; +import 'package:fladder/screens/shared/media/expanding_overview.dart'; +import 'package:fladder/screens/shared/media/people_row.dart'; +import 'package:fladder/screens/shared/media/person_list_.dart'; +import 'package:fladder/util/fladder_image.dart'; +import 'package:fladder/util/item_base_model/item_base_model_extensions.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/string_extensions.dart'; +import 'package:fladder/util/widget_extensions.dart'; +import 'package:fladder/widgets/shared/selectable_icon_button.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class SeasonDetailScreen extends ConsumerStatefulWidget { + final ItemBaseModel item; + const SeasonDetailScreen({required this.item, super.key}); + + @override + ConsumerState createState() => _SeasonDetailScreenState(); +} + +class _SeasonDetailScreenState extends ConsumerState { + Set viewOptions = {EpisodeDetailsViewType.grid}; + late final providerId = seasonDetailsProvider(widget.item.id); + + @override + Widget build(BuildContext context) { + final details = ref.watch(providerId); + + return DetailScaffold( + label: details?.localizedName(context) ?? "", + item: details, + actions: (context) => details?.generateActions(context, ref, exclude: { + ItemActions.details, + }), + onRefresh: () async { + await ref.read(providerId.notifier).fetchDetails(widget.item.id); + }, + backDrops: details?.parentImages, + content: (padding) => Padding( + padding: const EdgeInsets.only(bottom: 64), + child: details != null + ? Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + SizedBox(height: MediaQuery.of(context).size.height * 0.35), + Wrap( + alignment: WrapAlignment.spaceAround, + runAlignment: WrapAlignment.center, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + ConstrainedBox( + constraints: BoxConstraints( + maxWidth: 600, + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + MediaHeader( + name: "${details.seriesName} - ${details.name}", + logo: details.parentImages?.logo, + ), + OverviewHeader( + name: details.seriesName, + padding: padding, + subTitle: details.localizedName(context), + onTitleClicked: () => details.parentBaseModel.navigateTo(context), + originalTitle: details.seriesName, + productionYear: details.overview.productionYear, + runTime: details.overview.runTime, + studios: details.overview.studios, + officialRating: details.overview.parentalRating, + genres: details.overview.genreItems, + communityRating: details.overview.communityRating, + externalUrls: details.overview.externalUrls, + ), + ], + ), + ), + ConstrainedBox( + constraints: BoxConstraints(maxWidth: 300), + child: Card(child: FladderImage(image: details.getPosters?.primary))), + ], + ).padding(padding), + Row( + children: [ + Expanded( + child: Wrap( + spacing: 8, + runSpacing: 8, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + SelectableIconButton( + onPressed: () async => await ref + .read(userProvider.notifier) + .setAsFavorite(!details.userData.isFavourite, details.id), + selected: details.userData.isFavourite, + selectedIcon: IconsaxBold.heart, + icon: IconsaxOutline.heart, + ), + SelectableIconButton( + onPressed: () async => await ref + .read(userProvider.notifier) + .markAsPlayed(!details.userData.played, details.id), + selected: details.userData.played, + selectedIcon: IconsaxBold.tick_circle, + icon: IconsaxOutline.tick_circle, + ), + ], + ), + ), + Row( + children: [ + Card( + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(200)), + child: SegmentedButton( + style: ButtonStyle( + elevation: WidgetStatePropertyAll(5), + side: WidgetStatePropertyAll(BorderSide.none), + ), + showSelectedIcon: true, + segments: EpisodeDetailsViewType.values + .map( + (e) => ButtonSegment( + value: e, + icon: Icon(e.icon), + label: SizedBox( + height: 50, + child: Center( + child: Text( + e.name.capitalize(), + ), + )), + ), + ) + .toList(), + selected: viewOptions, + onSelectionChanged: (newOptions) { + setState(() { + viewOptions = newOptions; + }); + }, + ), + ), + ], + ), + ], + ).padding(padding), + if (details.overview.summary.isNotEmpty) + ExpandingOverview( + text: details.overview.summary, + ).padding(padding), + if (details.overview.directors.isNotEmpty) + PersonList( + label: context.localized.director(2), + people: details.overview.directors, + ).padding(padding), + if (details.overview.writers.isNotEmpty) + PersonList(label: context.localized.writer(2), people: details.overview.writers).padding(padding), + if (details.episodes.isNotEmpty) + EpisodeDetailsList( + viewType: viewOptions.first, + episodes: details.episodes, + padding: padding, + ), + if (details.overview.people.isNotEmpty) + PeopleRow( + people: details.overview.people, + contentPadding: padding, + ), + ].addPadding(const EdgeInsets.symmetric(vertical: 16)), + ) + : null, + ), + ); + } +} diff --git a/lib/screens/details_screens/series_detail_screen.dart b/lib/screens/details_screens/series_detail_screen.dart new file mode 100644 index 0000000..135be8b --- /dev/null +++ b/lib/screens/details_screens/series_detail_screen.dart @@ -0,0 +1,165 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/screens/details_screens/components/overview_header.dart'; +import 'package:fladder/screens/shared/media/components/media_play_button.dart'; +import 'package:fladder/screens/shared/media/components/next_up_episode.dart'; +import 'package:fladder/util/item_base_model/item_base_model_extensions.dart'; +import 'package:fladder/util/item_base_model/play_item_helpers.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:flutter/material.dart'; + +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/providers/items/series_details_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/screens/shared/detail_scaffold.dart'; +import 'package:fladder/screens/shared/media/components/media_header.dart'; +import 'package:fladder/screens/shared/media/episode_posters.dart'; +import 'package:fladder/screens/shared/media/expanding_overview.dart'; +import 'package:fladder/screens/shared/media/people_row.dart'; +import 'package:fladder/screens/shared/media/poster_row.dart'; +import 'package:fladder/screens/shared/media/season_row.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/widget_extensions.dart'; +import 'package:fladder/widgets/shared/selectable_icon_button.dart'; +import 'package:go_router/go_router.dart'; + +class SeriesDetailScreen extends ConsumerStatefulWidget { + final ItemBaseModel item; + const SeriesDetailScreen({required this.item, super.key}); + + @override + ConsumerState createState() => _SeriesDetailScreenState(); +} + +class _SeriesDetailScreenState extends ConsumerState { + late final providerId = seriesDetailsProvider(widget.item.id); + + @override + Widget build(BuildContext context) { + final details = ref.watch(providerId); + return DetailScaffold( + label: details?.name ?? "", + item: details, + actions: (context) => details?.generateActions( + context, + ref, + exclude: { + ItemActions.play, + ItemActions.playFromStart, + ItemActions.details, + }, + onDeleteSuccesFully: (item) { + if (context.mounted) { + context.pop(); + } + }, + ), + onRefresh: () => ref.read(providerId.notifier).fetchDetails(widget.item), + backDrops: details?.images, + content: (padding) => details != null + ? Padding( + padding: const EdgeInsets.only(bottom: 64), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + SizedBox(height: MediaQuery.of(context).size.height * 0.35), + MediaHeader( + name: details.name, + logo: details.images?.logo, + ), + OverviewHeader( + name: details.name, + padding: padding, + originalTitle: details.originalTitle, + productionYear: details.overview.productionYear, + runTime: details.overview.runTime, + studios: details.overview.studios, + officialRating: details.overview.parentalRating, + genres: details.overview.genreItems, + communityRating: details.overview.communityRating, + externalUrls: details.overview.externalUrls, + ), + Wrap( + spacing: 8, + runSpacing: 8, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + MediaPlayButton( + item: details.nextUp, + onPressed: details.nextUp != null + ? () async { + await details.nextUp.play(context, ref); + ref.read(providerId.notifier).fetchDetails(widget.item); + } + : null, + onLongPressed: details.nextUp != null + ? () async { + await details.nextUp.play(context, ref, showPlaybackOption: true); + ref.read(providerId.notifier).fetchDetails(widget.item); + } + : null, + ), + SelectableIconButton( + onPressed: () async { + await ref + .read(userProvider.notifier) + .setAsFavorite(!details.userData.isFavourite, details.id); + }, + selected: details.userData.isFavourite, + selectedIcon: IconsaxBold.heart, + icon: IconsaxOutline.heart, + ), + SelectableIconButton( + onPressed: () async { + await ref.read(userProvider.notifier).markAsPlayed(!details.userData.played, details.id); + }, + selected: details.userData.played, + selectedIcon: IconsaxBold.tick_circle, + icon: IconsaxOutline.tick_circle, + ), + ], + ).padding(padding), + if (details.nextUp != null) + NextUpEpisode( + nextEpisode: details.nextUp!, + onChanged: (episode) => ref.read(providerId.notifier).updateEpisodeInfo(episode), + ).padding(padding), + if (details.overview.summary.isNotEmpty) + ExpandingOverview( + text: details.overview.summary, + ).padding(padding), + if (details.availableEpisodes?.isNotEmpty ?? false) + EpisodePosters( + contentPadding: padding, + label: context.localized.episode(details.availableEpisodes?.length ?? 2), + playEpisode: (episode) async { + await episode.play( + context, + ref, + ); + ref.read(providerId.notifier).fetchDetails(widget.item); + }, + episodes: details.availableEpisodes ?? [], + ), + if (details.seasons?.isNotEmpty ?? false) + SeasonsRow( + contentPadding: padding, + seasons: details.seasons, + onSeasonPressed: (season) => season.navigateTo(context), + ), + if (details.overview.people.isNotEmpty) + PeopleRow( + people: details.overview.people, + contentPadding: padding, + ), + if (details.related.isNotEmpty) + PosterRow(posters: details.related, contentPadding: padding, label: context.localized.related), + ].addPadding(const EdgeInsets.symmetric(vertical: 16)), + ), + ) + : Container(), + ); + } +} diff --git a/lib/screens/favourites/favourites_screen.dart b/lib/screens/favourites/favourites_screen.dart new file mode 100644 index 0000000..7a35d04 --- /dev/null +++ b/lib/screens/favourites/favourites_screen.dart @@ -0,0 +1,82 @@ +import 'package:fladder/providers/settings/client_settings_provider.dart'; +import 'package:fladder/routes/build_routes/home_routes.dart'; +import 'package:fladder/screens/shared/nested_scaffold.dart'; +import 'package:fladder/screens/shared/nested_sliver_appbar.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/widgets/shared/pinch_poster_zoom.dart'; +import 'package:fladder/widgets/shared/poster_size_slider.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/providers/favourites_provider.dart'; +import 'package:fladder/screens/shared/media/poster_grid.dart'; +import 'package:fladder/util/sliver_list_padding.dart'; +import 'package:fladder/widgets/shared/pull_to_refresh.dart'; + +class FavouritesScreen extends ConsumerWidget { + final ScrollController navigationScrollController; + + const FavouritesScreen({required this.navigationScrollController, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final favourites = ref.watch(favouritesProvider); + + return PullToRefresh( + onRefresh: () async => await ref.read(favouritesProvider.notifier).fetchFavourites(), + child: NestedScaffold( + body: PinchPosterZoom( + scaleDifference: (difference) => ref.read(clientSettingsProvider.notifier).addPosterSize(difference / 2), + child: CustomScrollView( + physics: const AlwaysScrollableScrollPhysics(), + controller: navigationScrollController, + slivers: [ + if (AdaptiveLayout.of(context).layout == LayoutState.phone) + NestedSliverAppBar( + searchTitle: "${context.localized.search} ${context.localized.favorites.toLowerCase()}...", + parent: context, + route: LibrarySearchRoute(favorites: true), + ) + else + const DefaultSliverTopBadding(), + if (AdaptiveLayout.of(context).isDesktop) + SliverToBoxAdapter( + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + PosterSizeWidget(), + ], + ), + ), + ...favourites.favourites.entries.where((element) => element.value.isNotEmpty).map( + (e) => SliverToBoxAdapter( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: PosterGrid( + stickyHeader: true, + name: e.key.label(context), + posters: e.value, + ), + ), + ), + ), + if (favourites.people.isNotEmpty) + SliverToBoxAdapter( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: PosterGrid( + stickyHeader: true, + name: "People", + posters: favourites.people, + ), + ), + ), + const DefautlSliverBottomPadding(), + ], + ), + ), + ), + ); + } +} diff --git a/lib/screens/home.dart b/lib/screens/home.dart new file mode 100644 index 0000000..e77d481 --- /dev/null +++ b/lib/screens/home.dart @@ -0,0 +1,86 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:flutter/material.dart'; + +import 'package:collection/collection.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/routes/build_routes/home_routes.dart'; +import 'package:fladder/routes/build_routes/route_builder.dart'; +import 'package:fladder/util/string_extensions.dart'; +import 'package:fladder/widgets/navigation_scaffold/components/adaptive_fab.dart'; +import 'package:fladder/widgets/navigation_scaffold/components/destination_model.dart'; +import 'package:fladder/widgets/navigation_scaffold/navigation_scaffold.dart'; + +enum HomeTabs { + dashboard, + favorites, + sync; +} + +class Home extends ConsumerWidget { + final HomeTabs? currentTab; + final Widget? nestedChild; + final String? location; + const Home({this.currentTab, this.nestedChild, this.location, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final canDownload = ref.watch(showSyncButtonProviderProvider); + final destinations = HomeTabs.values.map((e) { + switch (e) { + case HomeTabs.dashboard: + return DestinationModel( + label: context.localized.navigationDashboard, + icon: const Icon(IconsaxOutline.home), + selectedIcon: const Icon(IconsaxBold.home), + route: DashboardRoute(), + action: () => context.routeGo(DashboardRoute()), + floatingActionButton: AdaptiveFab( + context: context, + title: context.localized.search, + key: Key(e.name.capitalize()), + onPressed: () => context.routePushOrGo(LibrarySearchRoute()), + child: const Icon(IconsaxOutline.search_normal_1), + ), + ); + case HomeTabs.favorites: + return DestinationModel( + label: context.localized.navigationFavorites, + icon: const Icon(IconsaxOutline.heart), + selectedIcon: const Icon(IconsaxBold.heart), + route: FavouritesRoute(), + floatingActionButton: AdaptiveFab( + context: context, + title: context.localized.filter(0), + key: Key(e.name.capitalize()), + onPressed: () => context.routePushOrGo(LibrarySearchRoute(favorites: true)), + child: const Icon(IconsaxOutline.heart_search), + ), + action: () => context.routeGo(FavouritesRoute()), + ); + case HomeTabs.sync: + if (canDownload) { + return DestinationModel( + label: context.localized.navigationSync, + icon: const Icon(IconsaxOutline.cloud), + selectedIcon: const Icon(IconsaxBold.cloud), + route: SyncRoute(), + action: () => context.routeGo(SyncRoute()), + ); + } + return null; + default: + return null; + } + }); + + return NavigationScaffold( + currentIndex: currentTab?.index ?? 0, + location: location, + nestedChild: nestedChild, + destinations: destinations.whereNotNull().toList(), + ); + } +} diff --git a/lib/screens/library/components/library_tabs.dart b/lib/screens/library/components/library_tabs.dart new file mode 100644 index 0000000..e27c1f8 --- /dev/null +++ b/lib/screens/library/components/library_tabs.dart @@ -0,0 +1,83 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first + +import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.dart'; +import 'package:fladder/screens/library/tabs/favourites_tab.dart'; +import 'package:fladder/screens/library/tabs/library_tab.dart'; +import 'package:fladder/screens/library/tabs/timeline_tab.dart'; +import 'package:flutter/material.dart'; + +import 'package:fladder/models/view_model.dart'; +import 'package:fladder/screens/library/tabs/recommendations_tab.dart'; + +class LibraryTabs { + final String name; + final Icon icon; + final Widget page; + final FloatingActionButton? floatingActionButton; + LibraryTabs({ + required this.name, + required this.icon, + required this.page, + this.floatingActionButton, + }); + + static List getLibraryForType(ViewModel viewModel, CollectionType type) { + LibraryTabs recommendTab() { + return LibraryTabs( + name: "Recommended", + icon: const Icon(Icons.recommend_rounded), + page: RecommendationsTab(viewModel: viewModel), + ); + } + + LibraryTabs timelineTab() { + return LibraryTabs( + name: "Timeline", + icon: const Icon(Icons.timeline), + page: TimelineTab(viewModel: viewModel), + ); + } + + LibraryTabs favouritesTab() { + return LibraryTabs( + name: "Favourites", + icon: const Icon(Icons.favorite_rounded), + page: FavouritesTab(viewModel: viewModel), + ); + } + + LibraryTabs libraryTab() { + return LibraryTabs( + name: "Library", + icon: const Icon(Icons.book_rounded), + page: LibraryTab(viewModel: viewModel), + ); + } + + switch (type) { + case CollectionType.tvshows: + case CollectionType.movies: + return [ + libraryTab(), + recommendTab(), + favouritesTab(), + ]; + case CollectionType.books: + case CollectionType.homevideos: + return [ + libraryTab(), + timelineTab(), + recommendTab(), + favouritesTab(), + ]; + case CollectionType.boxsets: + case CollectionType.playlists: + case CollectionType.folders: + return [ + libraryTab(), + ]; + default: + return []; + } + } +} diff --git a/lib/screens/library/library_screen.dart b/lib/screens/library/library_screen.dart new file mode 100644 index 0000000..896c9f6 --- /dev/null +++ b/lib/screens/library/library_screen.dart @@ -0,0 +1,92 @@ +import 'package:fladder/models/view_model.dart'; +import 'package:fladder/providers/library_provider.dart'; +import 'package:fladder/screens/library/components/library_tabs.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class LibraryScreen extends ConsumerStatefulWidget { + final ViewModel viewModel; + const LibraryScreen({ + required this.viewModel, + super.key, + }); + + @override + ConsumerState createState() => _LibraryScreenState(); +} + +class _LibraryScreenState extends ConsumerState with SingleTickerProviderStateMixin { + late final List tabs = LibraryTabs.getLibraryForType(widget.viewModel, widget.viewModel.collectionType); + late final TabController tabController = TabController(length: tabs.length, vsync: this); + + @override + void initState() { + super.initState(); + Future.microtask(() { + ref.read(libraryProvider(widget.viewModel.id).notifier).setupLibrary(widget.viewModel); + }); + + tabController.addListener(() { + if (tabController.previousIndex != tabController.index) { + setState(() {}); + } + }); + } + + @override + Widget build(BuildContext context) { + final PreferredSizeWidget tabBar = TabBar( + isScrollable: AdaptiveLayout.of(context).isDesktop ? true : false, + indicatorWeight: 3, + controller: tabController, + tabs: tabs + .map((e) => Tab( + text: e.name, + icon: e.icon, + )) + .toList(), + ); + + return Padding( + padding: AdaptiveLayout.of(context).isDesktop + ? EdgeInsets.only(top: MediaQuery.of(context).padding.top) + : EdgeInsets.zero, + child: ClipRRect( + borderRadius: BorderRadius.circular(AdaptiveLayout.of(context).isDesktop ? 15 : 0), + child: Card( + margin: AdaptiveLayout.of(context).isDesktop ? null : EdgeInsets.zero, + elevation: 2, + child: Scaffold( + backgroundColor: AdaptiveLayout.of(context).isDesktop ? Colors.transparent : null, + floatingActionButton: tabs[tabController.index].floatingActionButton, + floatingActionButtonLocation: FloatingActionButtonLocation.endContained, + appBar: AppBar( + centerTitle: true, + backgroundColor: AdaptiveLayout.of(context).isDesktop ? Colors.transparent : null, + title: tabs.length > 1 ? (!AdaptiveLayout.of(context).isDesktop ? null : tabBar) : null, + toolbarHeight: AdaptiveLayout.of(context).isDesktop ? 75 : 40, + bottom: tabs.length > 1 ? (AdaptiveLayout.of(context).isDesktop ? null : tabBar) : null, + ), + extendBody: true, + body: Padding( + padding: !AdaptiveLayout.of(context).isDesktop + ? EdgeInsets.only( + left: MediaQuery.of(context).padding.left, right: MediaQuery.of(context).padding.right) + : EdgeInsets.zero, + child: TabBarView( + controller: tabController, + children: tabs + .map((e) => Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: e.page, + )) + .toList(), + ), + ), + ), + ), + ), + ); + } +} diff --git a/lib/screens/library/tabs/favourites_tab.dart b/lib/screens/library/tabs/favourites_tab.dart new file mode 100644 index 0000000..ff633b7 --- /dev/null +++ b/lib/screens/library/tabs/favourites_tab.dart @@ -0,0 +1,37 @@ +import 'package:fladder/models/view_model.dart'; +import 'package:fladder/providers/library_provider.dart'; +import 'package:fladder/screens/shared/media/poster_grid.dart'; +import 'package:fladder/widgets/shared/pull_to_refresh.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class FavouritesTab extends ConsumerStatefulWidget { + final ViewModel viewModel; + const FavouritesTab({required this.viewModel, super.key}); + + @override + ConsumerState createState() => _FavouritesTabState(); +} + +class _FavouritesTabState extends ConsumerState with AutomaticKeepAliveClientMixin { + @override + Widget build(BuildContext context) { + final favourites = ref.watch(libraryProvider(widget.viewModel.id))?.favourites ?? []; + super.build(context); + return PullToRefresh( + onRefresh: () async { + await ref.read(libraryProvider(widget.viewModel.id).notifier).loadFavourites(widget.viewModel); + }, + child: favourites.isNotEmpty + ? ListView( + children: [ + PosterGrid(posters: favourites), + ], + ) + : const Center(child: Text("No favourites, add some using the heart icon.")), + ); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/screens/library/tabs/library_tab.dart b/lib/screens/library/tabs/library_tab.dart new file mode 100644 index 0000000..8ec1163 --- /dev/null +++ b/lib/screens/library/tabs/library_tab.dart @@ -0,0 +1,40 @@ +import 'package:fladder/models/view_model.dart'; +import 'package:fladder/providers/library_provider.dart'; +import 'package:fladder/screens/shared/media/poster_grid.dart'; +import 'package:fladder/util/grouping.dart'; +import 'package:fladder/util/keyed_list_view.dart'; +import 'package:fladder/widgets/shared/pull_to_refresh.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class LibraryTab extends ConsumerStatefulWidget { + final ViewModel viewModel; + const LibraryTab({required this.viewModel, super.key}); + + @override + ConsumerState createState() => _LibraryTabState(); +} + +class _LibraryTabState extends ConsumerState with AutomaticKeepAliveClientMixin { + @override + Widget build(BuildContext context) { + super.build(context); + final library = ref.watch(libraryProvider(widget.viewModel.id).select((value) => value?.posters)) ?? []; + final items = groupByName(library); + return PullToRefresh( + onRefresh: () async { + await ref.read(libraryProvider(widget.viewModel.id).notifier).loadLibrary(widget.viewModel); + }, + child: KeyedListView( + map: items, + itemBuilder: (context, index) { + final currentIndex = items.entries.elementAt(index); + return PosterGrid(name: currentIndex.key, posters: currentIndex.value); + }, + ), + ); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/screens/library/tabs/recommendations_tab.dart b/lib/screens/library/tabs/recommendations_tab.dart new file mode 100644 index 0000000..2de9ca7 --- /dev/null +++ b/lib/screens/library/tabs/recommendations_tab.dart @@ -0,0 +1,49 @@ +import 'package:fladder/models/view_model.dart'; +import 'package:fladder/providers/library_provider.dart'; +import 'package:fladder/screens/shared/media/poster_grid.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/widgets/shared/pull_to_refresh.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class RecommendationsTab extends ConsumerStatefulWidget { + final ViewModel viewModel; + + const RecommendationsTab({required this.viewModel, super.key}); + + @override + ConsumerState createState() => _RecommendationsTabState(); +} + +class _RecommendationsTabState extends ConsumerState with AutomaticKeepAliveClientMixin { + @override + Widget build(BuildContext context) { + super.build(context); + final recommendations = ref.watch(libraryProvider(widget.viewModel.id) + .select((value) => value?.recommendations.where((element) => element.posters.isNotEmpty))) ?? + []; + return PullToRefresh( + onRefresh: () async { + await ref.read(libraryProvider(widget.viewModel.id).notifier).loadRecommendations(widget.viewModel); + }, + child: recommendations.isNotEmpty + ? ListView( + children: recommendations + .map( + (e) => PosterGrid(name: e.name, posters: e.posters), + ) + .toList() + .addPadding( + const EdgeInsets.only( + bottom: 32, + ), + ), + ) + : const Center( + child: Text("No recommendations, add more movies and or shows to receive more recomendations")), + ); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/screens/library/tabs/timeline_tab.dart b/lib/screens/library/tabs/timeline_tab.dart new file mode 100644 index 0000000..653c6c7 --- /dev/null +++ b/lib/screens/library/tabs/timeline_tab.dart @@ -0,0 +1,132 @@ +import 'package:fladder/models/items/photos_model.dart'; +import 'package:fladder/models/view_model.dart'; +import 'package:fladder/providers/library_provider.dart'; +import 'package:fladder/screens/photo_viewer/photo_viewer_screen.dart'; +import 'package:fladder/screens/shared/flat_button.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/fladder_image.dart'; +import 'package:fladder/util/sticky_header_text.dart'; +import 'package:fladder/widgets/shared/pull_to_refresh.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; +import 'package:intl/intl.dart'; +import 'package:page_transition/page_transition.dart'; +import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; +import 'package:sticky_headers/sticky_headers.dart'; + +class TimelineTab extends ConsumerStatefulWidget { + final ViewModel viewModel; + + const TimelineTab({required this.viewModel, super.key}); + + @override + ConsumerState createState() => _TimelineTabState(); +} + +class _TimelineTabState extends ConsumerState with AutomaticKeepAliveClientMixin { + final itemScrollController = ItemScrollController(); + double get posterCount { + if (AdaptiveLayout.of(context).layout == LayoutState.desktop) { + return 200; + } + return 125; + } + + @override + Widget build(BuildContext context) { + super.build(context); + final timeLine = ref.watch(libraryProvider(widget.viewModel.id))?.timelinePhotos ?? []; + final items = groupedItems(timeLine); + + return PullToRefresh( + onRefresh: () async { + await ref.read(libraryProvider(widget.viewModel.id).notifier).loadTimeline(widget.viewModel); + }, + child: ScrollablePositionedList.builder( + itemScrollController: itemScrollController, + itemCount: items.length, + itemBuilder: (context, index) { + final item = items.entries.elementAt(index); + return Padding( + padding: const EdgeInsets.only(bottom: 64.0), + child: StickyHeader( + header: StickyHeaderText( + label: item.key.year != DateTime.now().year + ? DateFormat('E dd MMM. y').format(item.key) + : DateFormat('E dd MMM.').format(item.key)), + content: StaggeredGrid.count( + crossAxisCount: MediaQuery.of(context).size.width ~/ posterCount, + mainAxisSpacing: 0, + crossAxisSpacing: 0, + axisDirection: AxisDirection.down, + children: item.value + .map( + (e) => Hero( + tag: e.id, + child: AspectRatio( + aspectRatio: e.primaryRatio ?? 0.0, + child: Card( + margin: const EdgeInsets.all(4), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)), + clipBehavior: Clip.antiAlias, + child: Stack( + children: [ + FladderImage(image: e.thumbnail?.primary), + FlatButton( + onLongPress: () {}, + onTap: () async { + final position = await Navigator.of(context, rootNavigator: true).push( + PageTransition( + child: PhotoViewerScreen( + items: timeLine, + indexOfSelected: timeLine.indexOf(e), + ), + type: PageTransitionType.fade), + ); + getParentPosition(items, timeLine, position); + }, + ) + ], + ), + ), + ), + ), + ) + .toList(), + ), + ), + ); + }, + ), + ); + } + + void getParentPosition(Map> items, List timeLine, int position) { + items.forEach( + (key, value) { + if (value.contains(timeLine[position])) { + itemScrollController.scrollTo( + index: items.keys.toList().indexOf(key), duration: const Duration(milliseconds: 250)); + } + }, + ); + } + + Map> groupedItems(List items) { + Map> groupedItems = {}; + for (int i = 0; i < items.length; i++) { + DateTime curretDate = items[i].dateTaken ?? DateTime.now(); + DateTime key = DateTime(curretDate.year, curretDate.month, curretDate.day); + if (!groupedItems.containsKey(key)) { + groupedItems[key] = [items[i]]; + } else { + groupedItems[key]?.add(items[i]); + } + } + return groupedItems; + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/screens/library_search/library_search_screen.dart b/lib/screens/library_search/library_search_screen.dart new file mode 100644 index 0000000..ede46bc --- /dev/null +++ b/lib/screens/library_search/library_search_screen.dart @@ -0,0 +1,790 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/boxset_model.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/photos_model.dart'; +import 'package:fladder/models/library_search/library_search_options.dart'; +import 'package:fladder/models/media_playback_model.dart'; +import 'package:fladder/models/playlist_model.dart'; +import 'package:fladder/providers/settings/client_settings_provider.dart'; +import 'package:fladder/providers/video_player_provider.dart'; +import 'package:fladder/screens/collections/add_to_collection.dart'; +import 'package:fladder/screens/library_search/widgets/library_sort_dialogue.dart'; +import 'package:fladder/screens/playlists/add_to_playlists.dart'; +import 'package:fladder/screens/shared/animated_fade_size.dart'; +import 'package:fladder/screens/shared/flat_button.dart'; +import 'package:fladder/screens/shared/nested_bottom_appbar.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/fab_extended_anim.dart'; +import 'package:fladder/util/item_base_model/item_base_model_extensions.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/refresh_state.dart'; +import 'package:fladder/widgets/navigation_scaffold/components/floating_player_bar.dart'; +import 'package:fladder/widgets/navigation_scaffold/components/settings_user_icon.dart'; +import 'package:fladder/widgets/shared/fladder_scrollbar.dart'; +import 'package:fladder/widgets/shared/hide_on_scroll.dart'; +import 'package:fladder/widgets/shared/item_actions.dart'; +import 'package:fladder/widgets/shared/modal_bottom_sheet.dart'; +import 'package:fladder/widgets/shared/pinch_poster_zoom.dart'; +import 'package:fladder/widgets/shared/poster_size_slider.dart'; +import 'package:fladder/widgets/shared/scroll_position.dart'; +import 'package:fladder/widgets/shared/shapes.dart'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/models/library_search/library_search_model.dart'; +import 'package:fladder/providers/library_search_provider.dart'; +import 'package:fladder/screens/library_search/widgets/library_filter_chips.dart'; +import 'package:fladder/screens/library_search/widgets/library_views.dart'; +import 'package:fladder/screens/library_search/widgets/suggestion_search_bar.dart'; +import 'package:fladder/util/debouncer.dart'; +import 'package:fladder/util/sliver_list_padding.dart'; +import 'package:fladder/widgets/shared/pull_to_refresh.dart'; + +class LibrarySearchScreen extends ConsumerStatefulWidget { + final String? viewModelId; + final bool? favourites; + final List? folderId; + final SortingOrder? sortOrder; + final SortingOptions? sortingOptions; + final PhotoModel? photoToView; + const LibrarySearchScreen({ + this.viewModelId, + this.folderId, + this.favourites, + this.sortOrder, + this.sortingOptions, + this.photoToView, + super.key, + }); + + @override + ConsumerState createState() => _LibrarySearchScreenState(); +} + +class _LibrarySearchScreenState extends ConsumerState { + late final Key uniqueKey = Key(widget.folderId?.join(',').toString() ?? widget.viewModelId ?? UniqueKey().toString()); + late final providerKey = librarySearchProvider(uniqueKey); + late final libraryProvider = ref.read(providerKey.notifier); + final SearchController searchController = SearchController(); + final Debouncer debouncer = Debouncer(const Duration(seconds: 1)); + final GlobalKey refreshKey = GlobalKey(); + final ScrollController scrollController = ScrollController(); + late double lastScale = 0; + + bool loadOnStart = false; + + @override + void initState() { + super.initState(); + searchController.addListener(() { + debouncer.run(() { + ref.read(providerKey.notifier).setSearch(searchController.text); + }); + }); + + Future.microtask( + () async { + libraryProvider.setDefaultOptions(widget.sortOrder, widget.sortingOptions); + await refreshKey.currentState?.show(); + SystemChrome.setEnabledSystemUIMode( + SystemUiMode.edgeToEdge, + overlays: [], + ); + if (context.mounted && widget.photoToView != null) { + libraryProvider.viewGallery(context, selected: widget.photoToView); + } + scrollController.addListener(() { + scrollPosition(); + }); + }, + ); + } + + void scrollPosition() { + if (scrollController.position.pixels > scrollController.position.maxScrollExtent * 0.65) { + libraryProvider.loadMore(); + } + } + + @override + Widget build(BuildContext context) { + final isEmptySearchScreen = widget.viewModelId == null && widget.favourites == null && widget.folderId == null; + final librarySearchResults = ref.watch(providerKey); + final libraryProvider = ref.read(providerKey.notifier); + final postersList = librarySearchResults.posters.hideEmptyChildren(librarySearchResults.hideEmtpyShows); + final playerState = ref.watch(mediaPlaybackProvider.select((value) => value.state)); + + final libraryViewType = ref.watch(libraryViewTypeProvider); + + ref.listen( + providerKey, + (previous, next) { + if (previous != next) { + refreshKey.currentState?.show(); + scrollController.jumpTo(0); + } + }, + ); + + return PopScope( + canPop: !librarySearchResults.selecteMode, + onPopInvoked: (popped) async { + if (librarySearchResults.selecteMode) { + libraryProvider.toggleSelectMode(); + } + }, + child: Scaffold( + extendBody: true, + extendBodyBehindAppBar: true, + floatingActionButtonLocation: + playerState == VideoPlayerState.minimized ? FloatingActionButtonLocation.centerFloat : null, + floatingActionButton: switch (playerState) { + VideoPlayerState.minimized => Padding( + padding: EdgeInsets.symmetric(horizontal: 8), + child: FloatingPlayerBar(), + ), + _ => HideOnScroll( + controller: scrollController, + visibleBuilder: (visible) => Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + if (librarySearchResults.showPlayButtons) + FloatingActionButtonAnimated( + key: Key(context.localized.playLabel), + isExtended: visible, + tooltip: context.localized.playVideos, + onPressed: () async => await libraryProvider.playLibraryItems(context, ref), + label: Text(context.localized.playLabel), + icon: const Icon(IconsaxBold.play), + ), + if (librarySearchResults.showGalleryButtons) + FloatingActionButtonAnimated( + key: Key(context.localized.viewPhotos), + isExtended: visible, + alternate: true, + tooltip: context.localized.viewPhotos, + onPressed: () async => await libraryProvider.viewGallery(context), + label: Text(context.localized.viewPhotos), + icon: const Icon(IconsaxBold.gallery), + ) + ].addInBetween(SizedBox(height: 10)), + ), + ), + }, + bottomNavigationBar: HideOnScroll( + controller: AdaptiveLayout.of(context).isDesktop ? null : scrollController, + child: IgnorePointer( + ignoring: librarySearchResults.fetchingItems, + child: _LibrarySearchBottomBar( + uniqueKey: uniqueKey, + refreshKey: refreshKey, + scrollController: scrollController, + libraryProvider: libraryProvider, + postersList: postersList, + ), + ), + ), + body: Stack( + children: [ + Positioned.fill( + child: Card( + elevation: 1, + child: PinchPosterZoom( + scaleDifference: (difference) => ref.read(clientSettingsProvider.notifier).addPosterSize(difference), + child: MediaQuery.removeViewInsets( + context: context, + child: ClipRRect( + borderRadius: AdaptiveLayout.of(context).layout == LayoutState.desktop + ? BorderRadius.circular(15) + : BorderRadius.circular(0), + child: FladderScrollbar( + visible: AdaptiveLayout.of(context).inputDevice != InputDevice.pointer, + controller: scrollController, + child: PullToRefresh( + refreshKey: refreshKey, + autoFocus: false, + contextRefresh: false, + onRefresh: () async => + libraryProvider.initRefresh(widget.folderId, widget.viewModelId, widget.favourites), + refreshOnStart: false, + child: CustomScrollView( + physics: const AlwaysScrollableNoImplicitScrollPhysics(), + controller: scrollController, + slivers: [ + SliverAppBar( + floating: !AdaptiveLayout.of(context).isDesktop, + collapsedHeight: 80, + automaticallyImplyLeading: true, + pinned: AdaptiveLayout.of(context).isDesktop, + primary: true, + elevation: 5, + surfaceTintColor: Colors.transparent, + shadowColor: Colors.transparent, + backgroundColor: Theme.of(context).colorScheme.surface, + shape: AppBarShape(), + titleSpacing: 4, + leadingWidth: 48, + actions: [ + const SizedBox(width: 4), + Builder(builder: (context) { + final isFavorite = + librarySearchResults.nestedCurrentItem?.userData.isFavourite == true; + final itemActions = librarySearchResults.nestedCurrentItem?.generateActions( + context, + ref, + exclude: { + ItemActions.details, + ItemActions.markPlayed, + ItemActions.markUnplayed, + }, + onItemUpdated: (item) { + libraryProvider.updateParentItem(item); + }, + onUserDataChanged: (userData) { + libraryProvider.updateUserDataMain(userData); + }, + ) ?? + []; + final itemCountWidget = ItemActionButton( + label: Text(context.localized.itemCount(librarySearchResults.totalItemCount)), + icon: Icon(IconsaxBold.document_1), + ); + final refreshAction = ItemActionButton( + label: Text(context.localized.forceRefresh), + action: () => refreshKey.currentState?.show(), + icon: Icon(IconsaxOutline.refresh), + ); + final itemViewAction = ItemActionButton( + label: Text(context.localized.selectViewType), + icon: Icon(libraryViewType.icon), + action: () { + showAdaptiveDialog( + context: context, + builder: (context) => AlertDialog.adaptive( + content: Consumer( + builder: (context, ref, child) { + final currentType = ref.watch(libraryViewTypeProvider); + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Text(context.localized.selectViewType, + style: Theme.of(context).textTheme.titleMedium), + const SizedBox(height: 12), + ...LibraryViewTypes.values + .map( + (e) => FilledButton.tonal( + style: FilledButtonTheme.of(context).style?.copyWith( + padding: WidgetStatePropertyAll( + EdgeInsets.symmetric( + horizontal: 12, vertical: 24)), + backgroundColor: WidgetStateProperty.resolveWith( + (states) { + if (e != currentType) { + return Colors.transparent; + } + return null; + }, + ), + ), + onPressed: () { + ref.read(libraryViewTypeProvider.notifier).state = e; + }, + child: Row( + children: [ + Icon(e.icon), + const SizedBox(width: 12), + Text( + e.label(context), + ) + ], + ), + ), + ) + .toList() + .addInBetween(const SizedBox(height: 12)), + ], + ); + }, + ), + ), + ); + }); + return Card( + elevation: 0, + child: Tooltip( + message: librarySearchResults.nestedCurrentItem?.type.label(context) ?? + context.localized.library(1), + child: InkWell( + onTapUp: (details) async { + if (AdaptiveLayout.of(context).inputDevice == InputDevice.pointer) { + double left = details.globalPosition.dx; + double top = details.globalPosition.dy + 20; + await showMenu( + context: context, + position: RelativeRect.fromLTRB(left, top, 40, 100), + items: [ + PopupMenuItem( + child: Text( + librarySearchResults.nestedCurrentItem?.type.label(context) ?? + context.localized.library(0))), + itemCountWidget.toPopupMenuItem(useIcons: true), + refreshAction.toPopupMenuItem(useIcons: true), + itemViewAction.toPopupMenuItem(useIcons: true), + if (itemActions.isNotEmpty) ItemActionDivider().toPopupMenuItem(), + ...itemActions.popupMenuItems(useIcons: true), + ], + elevation: 8.0, + ); + } else { + await showBottomSheetPill( + context: context, + content: (context, scrollController) => ListView( + shrinkWrap: true, + controller: scrollController, + children: [ + itemCountWidget.toListItem(context, useIcons: true), + refreshAction.toListItem(context, useIcons: true), + itemViewAction.toListItem(context, useIcons: true), + if (itemActions.isNotEmpty) ItemActionDivider().toListItem(context), + ...itemActions.listTileItems(context, useIcons: true), + ], + ), + ); + } + }, + child: Padding( + padding: const EdgeInsets.all(12), + child: Icon( + isFavorite + ? librarySearchResults.nestedCurrentItem?.type.selectedicon + : librarySearchResults.nestedCurrentItem?.type.icon ?? + IconsaxOutline.document, + color: isFavorite ? Theme.of(context).colorScheme.primary : null, + ), + ), + ), + ), + ); + }), + if (AdaptiveLayout.of(context).layout == LayoutState.phone) ...[ + const SizedBox(width: 6), + SizedBox.square(dimension: 46, child: SettingsUserIcon()), + ], + const SizedBox(width: 12) + ], + title: Hero( + tag: "PrimarySearch", + child: SuggestionSearchBar( + autoFocus: isEmptySearchScreen, + key: uniqueKey, + title: librarySearchResults.searchBarTitle(context), + debounceDuration: const Duration(seconds: 1), + onItem: (value) async { + await value.navigateTo(context); + refreshKey.currentState?.show(); + }, + onSubmited: (value) async { + if (librarySearchResults.searchQuery != value) { + libraryProvider.setSearch(value); + refreshKey.currentState?.show(); + } + }, + ), + ), + bottom: PreferredSize( + preferredSize: const Size(0, 50), + child: Transform.translate( + offset: Offset(0, AdaptiveLayout.of(context).isDesktop ? -20 : -15), + child: IgnorePointer( + ignoring: librarySearchResults.loading, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Opacity( + opacity: librarySearchResults.loading ? 0.5 : 1, + child: SingleChildScrollView( + padding: const EdgeInsets.all(8), + scrollDirection: Axis.horizontal, + child: LibraryFilterChips( + controller: scrollController, + libraryProvider: libraryProvider, + librarySearchResults: librarySearchResults, + uniqueKey: uniqueKey, + postersList: postersList, + libraryViewType: libraryViewType, + ), + ), + ), + Row(), + ], + ), + ), + ), + ), + ), + if (AdaptiveLayout.of(context).isDesktop) + SliverToBoxAdapter( + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + PosterSizeWidget(), + ], + ), + ), + if (postersList.isNotEmpty) + SliverPadding( + padding: EdgeInsets.only( + left: MediaQuery.of(context).padding.left, + right: MediaQuery.of(context).padding.right), + sliver: LibraryViews( + key: uniqueKey, + items: postersList, + groupByType: librarySearchResults.groupBy, + ), + ) + else + SliverToBoxAdapter( + child: Center( + child: Text(context.localized.noItemsToShow), + ), + ), + const DefautlSliverBottomPadding(), + const SliverPadding(padding: EdgeInsets.only(bottom: 80)) + ], + ), + ), + ), + ), + ), + ), + ), + ), + if (librarySearchResults.fetchingItems) ...[ + Container( + color: Colors.black.withOpacity(0.1), + ), + Center( + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.primaryContainer, + borderRadius: BorderRadius.circular(16), + ), + child: Padding( + padding: EdgeInsets.all(16), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + CircularProgressIndicator.adaptive(), + Text(context.localized.fetchingLibrary, style: Theme.of(context).textTheme.titleMedium), + IconButton( + onPressed: () => libraryProvider.cancelFetch(), + icon: Icon(IconsaxOutline.close_square), + ) + ].addInBetween(const SizedBox(width: 16)), + ), + ), + ), + ) + ], + ], + ), + ), + ); + } +} + +class AlwaysScrollableNoImplicitScrollPhysics extends ScrollPhysics { + /// Creates scroll physics that always lets the user scroll. + const AlwaysScrollableNoImplicitScrollPhysics({super.parent}); + + @override + AlwaysScrollableNoImplicitScrollPhysics applyTo(ScrollPhysics? ancestor) { + return AlwaysScrollableNoImplicitScrollPhysics(parent: buildParent(ancestor)); + } + + @override + bool get allowImplicitScrolling => false; + + @override + bool shouldAcceptUserOffset(ScrollMetrics position) => true; + + @override + bool recommendDeferredLoading(double velocity, ScrollMetrics metrics, BuildContext context) => false; +} + +class _LibrarySearchBottomBar extends ConsumerWidget { + final Key uniqueKey; + final ScrollController scrollController; + final LibrarySearchNotifier libraryProvider; + final List postersList; + final GlobalKey refreshKey; + const _LibrarySearchBottomBar({ + required this.uniqueKey, + required this.scrollController, + required this.libraryProvider, + required this.postersList, + required this.refreshKey, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final librarySearchResults = ref.watch(librarySearchProvider(uniqueKey)); + final actions = [ + ItemActionButton( + action: () async { + await libraryProvider.setSelectedAsFavorite(true); + if (context.mounted) context.refreshData(); + }, + label: Text(context.localized.addAsFavorite), + icon: const Icon(IconsaxOutline.heart_add), + ), + ItemActionButton( + action: () async { + await libraryProvider.setSelectedAsFavorite(false); + if (context.mounted) context.refreshData(); + }, + label: Text(context.localized.removeAsFavorite), + icon: const Icon(IconsaxOutline.heart_remove), + ), + ItemActionButton( + action: () async { + await libraryProvider.setSelectedAsWatched(true); + if (context.mounted) context.refreshData(); + }, + label: Text(context.localized.markAsWatched), + icon: const Icon(IconsaxOutline.eye), + ), + ItemActionButton( + action: () async { + await libraryProvider.setSelectedAsWatched(false); + if (context.mounted) context.refreshData(); + }, + label: Text(context.localized.markAsUnwatched), + icon: const Icon(IconsaxOutline.eye_slash), + ), + if (librarySearchResults.nestedCurrentItem is BoxSetModel) + ItemActionButton( + action: () async { + await libraryProvider.removeSelectedFromCollection(); + if (context.mounted) context.refreshData(); + }, + label: Text(context.localized.removeFromCollection), + icon: Container( + decoration: + BoxDecoration(color: Theme.of(context).colorScheme.onPrimary, borderRadius: BorderRadius.circular(6)), + child: const Padding( + padding: EdgeInsets.all(3.0), + child: Icon(IconsaxOutline.save_remove, size: 20), + ), + )), + if (librarySearchResults.nestedCurrentItem is PlaylistModel) + ItemActionButton( + action: () async { + await libraryProvider.removeSelectedFromPlaylist(); + if (context.mounted) context.refreshData(); + }, + label: Text(context.localized.removeFromPlaylist), + icon: const Icon(IconsaxOutline.save_remove), + ), + ItemActionButton( + action: () async { + await addItemToCollection(context, librarySearchResults.selectedPosters); + if (context.mounted) context.refreshData(); + }, + label: Text(context.localized.addToCollection), + icon: Icon( + IconsaxOutline.save_add, + size: 20, + ), + ), + ItemActionButton( + action: () async { + await addItemToPlaylist(context, librarySearchResults.selectedPosters); + if (context.mounted) context.refreshData(); + }, + label: Text(context.localized.addToPlaylist), + icon: const Icon(IconsaxOutline.save_add), + ), + ]; + return NestedBottomAppBar( + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + Row( + children: [ + ScrollStatePosition( + controller: scrollController, + positionBuilder: (state) => AnimatedFadeSize( + child: state != ScrollState.top + ? Tooltip( + message: context.localized.scrollToTop, + child: FlatButton( + clipBehavior: Clip.antiAlias, + elevation: 0, + borderRadiusGeometry: BorderRadius.circular(6), + onTap: () => scrollController.animateTo(0, + duration: const Duration(milliseconds: 500), curve: Curves.easeInOutCubic), + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.primaryContainer, + ), + padding: const EdgeInsets.all(6), + child: Icon( + IconsaxOutline.arrow_up_3, + color: Theme.of(context).colorScheme.onPrimaryContainer, + ), + ), + ), + ) + : const SizedBox(), + ), + ), + const SizedBox(width: 6), + if (!librarySearchResults.selecteMode) ...{ + const SizedBox(width: 6), + IconButton( + tooltip: context.localized.sortBy, + onPressed: () async { + final newOptions = await openSortByDialogue( + context, + libraryProvider: libraryProvider, + uniqueKey: uniqueKey, + options: (librarySearchResults.sortingOption, librarySearchResults.sortOrder), + ); + if (newOptions != null) { + if (newOptions.$1 != null) { + libraryProvider.setSortBy(newOptions.$1!); + } + if (newOptions.$2 != null) { + libraryProvider.setSortOrder(newOptions.$2!); + } + } + }, + icon: const Icon(IconsaxOutline.sort), + ), + if (librarySearchResults.hasActiveFilters) ...{ + const SizedBox(width: 6), + IconButton( + tooltip: context.localized.disableFilters, + onPressed: disableFilters(librarySearchResults, libraryProvider), + icon: const Icon(IconsaxOutline.filter_remove), + ), + }, + }, + const SizedBox(width: 6), + IconButton( + onPressed: () => libraryProvider.toggleSelectMode(), + color: librarySearchResults.selecteMode ? Theme.of(context).colorScheme.primary : null, + icon: const Icon(IconsaxOutline.category_2), + ), + const SizedBox(width: 6), + AnimatedFadeSize( + child: librarySearchResults.selecteMode + ? Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.primaryContainer, + borderRadius: BorderRadius.circular(16)), + child: Row( + children: [ + Tooltip( + message: context.localized.selectAll, + child: IconButton( + onPressed: () => libraryProvider.selectAll(true), + icon: const Icon(IconsaxOutline.box_add), + ), + ), + const SizedBox(width: 6), + Tooltip( + message: context.localized.clearSelection, + child: IconButton( + onPressed: () => libraryProvider.selectAll(false), + icon: const Icon(IconsaxOutline.box_remove), + ), + ), + const SizedBox(width: 6), + if (librarySearchResults.selectedPosters.isNotEmpty) ...{ + if (AdaptiveLayout.of(context).isDesktop) + PopupMenuButton( + itemBuilder: (context) => actions.popupMenuItems(useIcons: true), + ) + else + IconButton( + onPressed: () { + showBottomSheetPill( + context: context, + content: (context, scrollController) => ListView( + shrinkWrap: true, + controller: scrollController, + children: actions.listTileItems(context, useIcons: true), + ), + ); + }, + icon: Icon(IconsaxOutline.more)) + }, + ], + ), + ) + : const SizedBox(), + ), + const Spacer(), + IconButton( + tooltip: context.localized.random, + onPressed: () => libraryProvider.openRandom(context), + icon: Card( + color: Theme.of(context).colorScheme.secondary, + child: Padding( + padding: const EdgeInsets.all(2.0), + child: Icon( + IconsaxBold.arrow_up_1, + color: Theme.of(context).colorScheme.onSecondary, + ), + ), + ), + ), + if (librarySearchResults.showGalleryButtons) + IconButton( + tooltip: context.localized.shuffleGallery, + onPressed: () => libraryProvider.viewGallery(context, shuffle: true), + icon: Card( + color: Theme.of(context).colorScheme.primary, + child: Padding( + padding: const EdgeInsets.all(2.0), + child: Icon( + IconsaxBold.shuffle, + color: Theme.of(context).colorScheme.onPrimary, + ), + ), + ), + ), + if (librarySearchResults.showPlayButtons) + IconButton( + tooltip: context.localized.shuffleVideos, + onPressed: librarySearchResults.activePosters.isNotEmpty + ? () async { + await libraryProvider.playLibraryItems(context, ref, shuffle: true); + } + : null, + icon: const Icon(IconsaxOutline.shuffle), + ), + ], + ), + if (AdaptiveLayout.of(context).isDesktop) SizedBox(height: 8), + ], + ), + ); + } + + void Function()? disableFilters(LibrarySearchModel librarySearchResults, LibrarySearchNotifier libraryProvider) { + return () { + libraryProvider.clearAllFilters(); + refreshKey.currentState?.show(); + }; + } +} diff --git a/lib/screens/library_search/widgets/library_filter_chips.dart b/lib/screens/library_search/widgets/library_filter_chips.dart new file mode 100644 index 0000000..86c6b41 --- /dev/null +++ b/lib/screens/library_search/widgets/library_filter_chips.dart @@ -0,0 +1,219 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/models/library_search/library_search_model.dart'; +import 'package:fladder/models/library_search/library_search_options.dart'; +import 'package:fladder/providers/library_search_provider.dart'; +import 'package:fladder/screens/library_search/widgets/library_views.dart'; +import 'package:fladder/screens/shared/chips/category_chip.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/map_bool_helper.dart'; +import 'package:fladder/util/refresh_state.dart'; +import 'package:fladder/widgets/shared/scroll_position.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class LibraryFilterChips extends ConsumerWidget { + final Key uniqueKey; + final ScrollController controller; + final LibrarySearchModel librarySearchResults; + final LibrarySearchNotifier libraryProvider; + final List postersList; + final LibraryViewTypes libraryViewType; + const LibraryFilterChips({ + required this.uniqueKey, + required this.controller, + required this.librarySearchResults, + required this.libraryProvider, + required this.postersList, + required this.libraryViewType, + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return ScrollStatePosition( + controller: controller, + positionBuilder: (state) { + return Row( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.center, + children: libraryFilterChips( + context, + ref, + uniqueKey, + librarySearchResults: librarySearchResults, + libraryProvider: libraryProvider, + postersList: postersList, + libraryViewType: libraryViewType, + ).addPadding(const EdgeInsets.symmetric(horizontal: 8)), + ); + }, + ); + } +} + +List libraryFilterChips( + BuildContext context, + WidgetRef ref, + Key uniqueKey, { + required LibrarySearchModel librarySearchResults, + required LibrarySearchNotifier libraryProvider, + required List postersList, + required LibraryViewTypes libraryViewType, +}) { + Future openGroupDialogue() { + return showDialog( + context: context, + builder: (context) { + return Consumer( + builder: (context, ref, child) { + return AlertDialog.adaptive( + content: SizedBox( + width: MediaQuery.of(context).size.width * 0.65, + child: ListView( + shrinkWrap: true, + children: [ + Text(context.localized.groupBy), + ...GroupBy.values.map((groupBy) => RadioListTile.adaptive( + value: groupBy, + title: Text(groupBy.value(context)), + groupValue: ref.watch(librarySearchProvider(uniqueKey).select((value) => value.groupBy)), + onChanged: (value) { + libraryProvider.setGroupBy(groupBy); + Navigator.pop(context); + }, + )), + ], + ), + ), + ); + }, + ); + }, + ); + } + + return [ + if (librarySearchResults.folderOverwrite.isEmpty) + CategoryChip( + label: Text(context.localized.library(2)), + items: librarySearchResults.views, + labelBuilder: (item) => Text(item.name), + onSave: (value) => libraryProvider.setViews(value), + onCancel: () => libraryProvider.setViews(librarySearchResults.views), + onClear: () => libraryProvider.setViews(librarySearchResults.views.setAll(false)), + ), + CategoryChip( + label: Text(context.localized.type(librarySearchResults.types.length)), + items: librarySearchResults.types, + labelBuilder: (item) => Row( + children: [ + Icon(item.icon), + const SizedBox(width: 12), + Text(item.label(context)), + ], + ), + onSave: (value) => libraryProvider.setTypes(value), + onClear: () => libraryProvider.setTypes(librarySearchResults.types.setAll(false)), + ), + FilterChip( + label: Text(context.localized.favorites), + avatar: Icon( + librarySearchResults.favourites ? IconsaxBold.heart : IconsaxOutline.heart, + color: Theme.of(context).colorScheme.onSurface, + ), + selected: librarySearchResults.favourites, + showCheckmark: false, + onSelected: (value) { + libraryProvider.toggleFavourite(); + context.refreshData(); + }, + ), + FilterChip( + label: Text(context.localized.recursive), + selected: librarySearchResults.recursive, + onSelected: (value) { + libraryProvider.toggleRecursive(); + context.refreshData(); + }, + ), + if (librarySearchResults.genres.isNotEmpty) + CategoryChip( + label: Text(context.localized.genre(librarySearchResults.genres.length)), + activeIcon: IconsaxBold.hierarchy_2, + items: librarySearchResults.genres, + labelBuilder: (item) => Text(item), + onSave: (value) => libraryProvider.setGenres(value), + onCancel: () => libraryProvider.setGenres(librarySearchResults.genres), + onClear: () => libraryProvider.setGenres(librarySearchResults.genres.setAll(false)), + ), + if (librarySearchResults.studios.isNotEmpty) + CategoryChip( + label: Text(context.localized.studio(librarySearchResults.studios.length)), + activeIcon: IconsaxBold.airdrop, + items: librarySearchResults.studios, + labelBuilder: (item) => Text(item.name), + onSave: (value) => libraryProvider.setStudios(value), + onCancel: () => libraryProvider.setStudios(librarySearchResults.studios), + onClear: () => libraryProvider.setStudios(librarySearchResults.studios.setAll(false)), + ), + if (librarySearchResults.tags.isNotEmpty) + CategoryChip( + label: Text(context.localized.label(librarySearchResults.tags.length)), + activeIcon: Icons.label_rounded, + items: librarySearchResults.tags, + labelBuilder: (item) => Text(item), + onSave: (value) => libraryProvider.setTags(value), + onCancel: () => libraryProvider.setTags(librarySearchResults.tags), + onClear: () => libraryProvider.setTags(librarySearchResults.tags.setAll(false)), + ), + FilterChip( + label: Text(context.localized.group), + selected: librarySearchResults.groupBy != GroupBy.none, + onSelected: (value) { + openGroupDialogue(); + }, + ), + CategoryChip( + label: Text(context.localized.filter(librarySearchResults.filters.length)), + items: librarySearchResults.filters, + labelBuilder: (item) => Text(item.label(context)), + onSave: (value) => libraryProvider.setFilters(value), + onClear: () => libraryProvider.setFilters(librarySearchResults.filters.setAll(false)), + ), + if (librarySearchResults.types[FladderItemType.series] == true) + FilterChip( + avatar: Icon( + librarySearchResults.hideEmtpyShows ? Icons.visibility_rounded : Icons.visibility_off_rounded, + color: Theme.of(context).colorScheme.onSurface, + ), + selected: librarySearchResults.hideEmtpyShows, + showCheckmark: false, + label: Text(librarySearchResults.hideEmtpyShows ? context.localized.showEmpty : context.localized.hideEmpty), + onSelected: libraryProvider.setHideEmpty, + ), + if (librarySearchResults.officialRatings.isNotEmpty) + CategoryChip( + label: Text(context.localized.rating(librarySearchResults.officialRatings.length)), + activeIcon: Icons.star_rate_rounded, + items: librarySearchResults.officialRatings, + labelBuilder: (item) => Text(item), + onSave: (value) => libraryProvider.setRatings(value), + onCancel: () => libraryProvider.setRatings(librarySearchResults.officialRatings), + onClear: () => libraryProvider.setRatings(librarySearchResults.officialRatings.setAll(false)), + ), + if (librarySearchResults.years.isNotEmpty) + CategoryChip( + label: Text(context.localized.year(librarySearchResults.years.length)), + items: librarySearchResults.years, + labelBuilder: (item) => Text(item.toString()), + onSave: (value) => libraryProvider.setYears(value), + onCancel: () => libraryProvider.setYears(librarySearchResults.years), + onClear: () => libraryProvider.setYears(librarySearchResults.years.setAll(false)), + ), + ]; +} diff --git a/lib/screens/library_search/widgets/library_sort_dialogue.dart b/lib/screens/library_search/widgets/library_sort_dialogue.dart new file mode 100644 index 0000000..cf2f6b1 --- /dev/null +++ b/lib/screens/library_search/widgets/library_sort_dialogue.dart @@ -0,0 +1,78 @@ +import 'package:fladder/models/library_search/library_search_options.dart'; +import 'package:fladder/providers/library_search_provider.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:flutter/material.dart'; + +Future<(SortingOptions? sortOptions, SortingOrder? sortingOrder)?> openSortByDialogue( + BuildContext context, { + required (SortingOptions sortOptions, SortingOrder sortingOrder) options, + required LibrarySearchNotifier libraryProvider, + required Key uniqueKey, +}) async { + SortingOptions? newSortingOptions = options.$1; + SortingOrder? newSortOrder = options.$2; + await showDialog( + context: context, + builder: (context) { + return StatefulBuilder( + builder: (context, state) { + return AlertDialog.adaptive( + content: SizedBox( + width: MediaQuery.of(context).size.width * 0.65, + child: ListView( + shrinkWrap: true, + children: [ + Padding( + padding: const EdgeInsets.only(left: 8), + child: Text(context.localized.sortBy, style: Theme.of(context).textTheme.titleLarge), + ), + const SizedBox(height: 8), + ...SortingOptions.values.map((e) => RadioListTile.adaptive( + value: e, + title: Text(e.label(context)), + groupValue: newSortingOptions, + onChanged: (value) { + state( + () { + newSortingOptions = value; + }, + ); + }, + )), + const Padding( + padding: EdgeInsets.symmetric(vertical: 8), + child: Divider(), + ), + Padding( + padding: const EdgeInsets.only(left: 8), + child: Text(context.localized.sortOrder, style: Theme.of(context).textTheme.titleLarge), + ), + const SizedBox(height: 8), + ...SortingOrder.values.map( + (e) => RadioListTile.adaptive( + value: e, + title: Text(e.label(context)), + groupValue: newSortOrder, + onChanged: (value) { + state( + () { + newSortOrder = value; + }, + ); + }, + ), + ), + ], + ), + ), + ); + }, + ); + }, + ); + if (newSortingOptions == null && newSortOrder == null) { + return null; + } else { + return (newSortingOptions, newSortOrder); + } +} diff --git a/lib/screens/library_search/widgets/library_views.dart b/lib/screens/library_search/widgets/library_views.dart new file mode 100644 index 0000000..b043b68 --- /dev/null +++ b/lib/screens/library_search/widgets/library_views.dart @@ -0,0 +1,387 @@ +import 'dart:ui'; + +import 'package:collection/collection.dart'; +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/boxset_model.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/photos_model.dart'; +import 'package:fladder/models/library_search/library_search_options.dart'; +import 'package:fladder/models/playlist_model.dart'; +import 'package:fladder/providers/library_search_provider.dart'; +import 'package:fladder/providers/settings/client_settings_provider.dart'; +import 'package:fladder/screens/photo_viewer/photo_viewer_screen.dart'; +import 'package:fladder/screens/shared/media/poster_grid.dart'; +import 'package:fladder/screens/shared/media/poster_list_item.dart'; +import 'package:fladder/screens/shared/media/poster_widget.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/item_base_model/item_base_model_extensions.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/refresh_state.dart'; +import 'package:fladder/util/string_extensions.dart'; +import 'package:fladder/widgets/shared/item_actions.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; +import 'package:intl/intl.dart'; +import 'package:page_transition/page_transition.dart'; +import 'package:sliver_tools/sliver_tools.dart'; +import 'package:sticky_headers/sticky_headers/widget.dart'; + +final libraryViewTypeProvider = StateProvider((ref) { + return LibraryViewTypes.grid; +}); + +enum LibraryViewTypes { + grid(icon: IconsaxOutline.grid_2), + list(icon: IconsaxOutline.grid_6), + masonry(icon: IconsaxOutline.grid_3); + + const LibraryViewTypes({required this.icon}); + + String label(BuildContext context) => switch (this) { + LibraryViewTypes.grid => context.localized.grid, + LibraryViewTypes.list => context.localized.list, + LibraryViewTypes.masonry => context.localized.masonry, + }; + + final IconData icon; +} + +class LibraryViews extends ConsumerWidget { + final List items; + final GroupBy groupByType; + final Function(ItemBaseModel)? onPressed; + final Set excludeActions = const {ItemActions.openParent}; + const LibraryViews({required this.items, required this.groupByType, this.onPressed, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return SliverPadding( + padding: const EdgeInsets.symmetric(horizontal: 4), + sliver: SliverAnimatedSwitcher( + duration: const Duration(milliseconds: 250), + child: _getWidget(ref, context), + ), + ); + } + + Widget _getWidget(WidgetRef ref, BuildContext context) { + final selected = ref.watch(librarySearchProvider(key!).select((value) => value.selectedPosters)); + final posterSizeMultiplier = ref.watch(clientSettingsProvider.select((value) => value.posterSize)); + final libraryProvider = ref.read(librarySearchProvider(key!).notifier); + final posterSize = MediaQuery.sizeOf(context).width / + (AdaptiveLayout.poster(context).gridRatio * + ref.watch(clientSettingsProvider.select((value) => value.posterSize))); + final decimal = posterSize - posterSize.toInt(); + + final sortingOptions = ref.watch(librarySearchProvider(key!).select((value) => value.sortingOption)); + + List otherActions(ItemBaseModel item) { + return [ + if (ref.watch(librarySearchProvider(key!).select((value) => value.nestedCurrentItem is BoxSetModel))) ...{ + ItemActionButton( + label: Text(context.localized.removeFromCollection), + icon: Icon(IconsaxOutline.archive_slash), + action: () async { + await libraryProvider.removeFromCollection(items: [item]); + if (context.mounted) { + context.refreshData(); + } + }, + ) + }, + if (ref.watch(librarySearchProvider(key!).select((value) => value.nestedCurrentItem is PlaylistModel))) ...{ + ItemActionButton( + label: Text(context.localized.removeFromPlaylist), + icon: Icon(IconsaxOutline.archive_minus), + action: () async { + await libraryProvider.removeFromPlaylist(items: [item]); + if (context.mounted) { + context.refreshData(); + } + }, + ) + } + ]; + } + + switch (ref.watch(libraryViewTypeProvider)) { + case LibraryViewTypes.grid: + if (groupByType != GroupBy.none) { + final groupedItems = groupItemsBy(context, items, groupByType); + return SliverList.builder( + itemCount: groupedItems.length, + itemBuilder: (context, index) { + final name = groupedItems.keys.elementAt(index); + final group = groupedItems[name]; + if (group?.isEmpty ?? false || group == null) { + return Text(context.localized.empty); + } + return PosterGrid( + posters: group!, + name: name, + itemBuilder: (context, index) { + final item = group[index]; + return PosterWidget( + key: Key(item.id), + poster: group[index], + maxLines: 2, + heroTag: true, + subTitle: item.subTitle(sortingOptions), + excludeActions: excludeActions, + otherActions: otherActions(item), + selected: selected.contains(item), + onUserDataChanged: (id, newData) => libraryProvider.updateUserData(id, newData), + onItemRemoved: (oldItem) => libraryProvider.removeFromPosters([oldItem.id]), + onItemUpdated: (newItem) => libraryProvider.updateItem(newItem), + onPressed: (action, item) async => onItemPressed(action, key, item, ref, context), + ); + }, + onPressed: (action, item) async => onItemPressed(action, key, item, ref, context), + ); + }, + ); + } else { + return SliverPadding( + padding: const EdgeInsets.symmetric(horizontal: 8), + sliver: SliverGrid.builder( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: posterSize.toInt(), + mainAxisSpacing: (8 * decimal) + 8, + crossAxisSpacing: (8 * decimal) + 8, + childAspectRatio: AdaptiveLayout.poster(context).ratio, + ), + itemCount: items.length, + itemBuilder: (context, index) { + final item = items[index]; + return PosterWidget( + key: Key(item.id), + poster: item, + maxLines: 2, + heroTag: true, + subTitle: item.subTitle(sortingOptions), + excludeActions: excludeActions, + otherActions: otherActions(item), + selected: selected.contains(item), + onUserDataChanged: (id, newData) => libraryProvider.updateUserData(id, newData), + onItemRemoved: (oldItem) => libraryProvider.removeFromPosters([oldItem.id]), + onItemUpdated: (newItem) => libraryProvider.updateItem(newItem), + onPressed: (action, item) async => onItemPressed(action, key, item, ref, context), + ); + }, + ), + ); + } + case LibraryViewTypes.list: + if (groupByType != GroupBy.none) { + final groupedItems = groupItemsBy(context, items, groupByType); + return SliverList.builder( + itemCount: groupedItems.length, + itemBuilder: (context, index) { + final name = groupedItems.keys.elementAt(index); + final group = groupedItems[name]; + if (group?.isEmpty ?? false) { + return Text(context.localized.empty); + } + return StickyHeader( + header: Text(name, style: Theme.of(context).textTheme.headlineSmall), + content: ListView.builder( + shrinkWrap: true, + padding: EdgeInsets.zero, + physics: const NeverScrollableScrollPhysics(), + itemCount: group?.length, + itemBuilder: (context, index) { + final poster = group![index]; + return PosterListItem( + key: Key(poster.id), + poster: poster, + subTitle: poster.subTitle(sortingOptions), + excludeActions: excludeActions, + otherActions: otherActions(poster), + selected: selected.contains(poster), + onUserDataChanged: (id, newData) => libraryProvider.updateUserData(id, newData), + onItemRemoved: (oldItem) => libraryProvider.removeFromPosters([oldItem.id]), + onItemUpdated: (newItem) => libraryProvider.updateItem(newItem), + onPressed: (action, item) async => onItemPressed(action, key, item, ref, context), + ); + }, + ), + ); + }, + ); + } + return SliverList.builder( + itemCount: items.length, + itemBuilder: (context, index) { + final poster = items[index]; + return PosterListItem( + poster: poster, + selected: selected.contains(poster), + excludeActions: excludeActions, + otherActions: otherActions(poster), + subTitle: poster.subTitle(sortingOptions), + onUserDataChanged: (id, newData) => libraryProvider.updateUserData(id, newData), + onItemRemoved: (oldItem) => libraryProvider.removeFromPosters([oldItem.id]), + onItemUpdated: (newItem) => libraryProvider.updateItem(newItem), + onPressed: (action, item) async => onItemPressed(action, key, item, ref, context), + ); + }, + ); + case LibraryViewTypes.masonry: + if (groupByType != GroupBy.none) { + final groupedItems = groupItemsBy(context, items, groupByType); + return SliverList.builder( + itemCount: groupedItems.length, + itemBuilder: (context, index) { + final name = groupedItems.keys.elementAt(index); + final group = groupedItems[name]; + if (group?.isEmpty ?? false) { + return Text(context.localized.empty); + } + return Padding( + padding: EdgeInsets.only(top: index == 0 ? 0 : 64.0), + child: StickyHeader( + header: Text(name, style: Theme.of(context).textTheme.headlineMedium), + overlapHeaders: true, + content: Padding( + padding: const EdgeInsets.only(top: 16.0), + child: MasonryGridView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + mainAxisSpacing: (8 * decimal) + 8, + crossAxisSpacing: (8 * decimal) + 8, + gridDelegate: SliverSimpleGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: + (MediaQuery.sizeOf(context).width ~/ (lerpDouble(250, 75, posterSizeMultiplier) ?? 1.0)) + .toDouble() * + 20, + ), + itemCount: group!.length, + itemBuilder: (context, index) { + final item = group[index]; + return PosterWidget( + key: Key(item.id), + poster: item, + aspectRatio: item.primaryRatio, + selected: selected.contains(item), + inlineTitle: true, + heroTag: true, + subTitle: item.subTitle(sortingOptions), + excludeActions: excludeActions, + otherActions: otherActions(group[index]), + onUserDataChanged: (id, newData) => libraryProvider.updateUserData(id, newData), + onItemRemoved: (oldItem) => libraryProvider.removeFromPosters([oldItem.id]), + onItemUpdated: (newItem) => libraryProvider.updateItem(newItem), + onPressed: (action, item) async => onItemPressed(action, key, item, ref, context), + ); + }, + ), + )), + ); + }, + ); + } else { + return SliverMasonryGrid.count( + mainAxisSpacing: (8 * decimal) + 8, + crossAxisSpacing: (8 * decimal) + 8, + crossAxisCount: posterSize.toInt(), + childCount: items.length, + itemBuilder: (context, index) { + final item = items[index]; + return PosterWidget( + poster: item, + key: Key(item.id), + aspectRatio: item.primaryRatio, + selected: selected.contains(item), + inlineTitle: true, + heroTag: true, + excludeActions: excludeActions, + otherActions: otherActions(item), + subTitle: item.subTitle(sortingOptions), + onUserDataChanged: (id, newData) => libraryProvider.updateUserData(id, newData), + onItemRemoved: (oldItem) => libraryProvider.removeFromPosters([oldItem.id]), + onItemUpdated: (newItem) => libraryProvider.updateItem(newItem), + onPressed: (action, item) async => onItemPressed(action, key, item, ref, context), + ); + }, + ); + } + } + } + + Map> groupItemsBy(BuildContext context, List list, GroupBy groupOption) { + switch (groupOption) { + case GroupBy.dateAdded: + return groupBy( + items, + (poster) => DateFormat.yMMMMd().format(DateTime( + poster.overview.dateAdded!.year, poster.overview.dateAdded!.month, poster.overview.dateAdded!.day))); + case GroupBy.releaseDate: + return groupBy(list, (poster) => poster.overview.yearAired?.toString() ?? context.localized.unknown); + case GroupBy.rating: + return groupBy(list, (poster) => poster.overview.parentalRating ?? context.localized.noRating); + case GroupBy.tags: + return groupByList(context, list, true); + case GroupBy.genres: + return groupByList(context, list, false); + case GroupBy.name: + return groupBy(list, (poster) => poster.name[0].capitalize()); + case GroupBy.type: + return groupBy(list, (poster) => poster.type.label(context)); + case GroupBy.none: + return {}; + } + } + + Future onItemPressed( + Function() action, Key? key, ItemBaseModel item, WidgetRef ref, BuildContext context) async { + final selectMode = ref.read(librarySearchProvider(key!).select((value) => value.selecteMode)); + if (selectMode) { + ref.read(librarySearchProvider(key).notifier).toggleSelection(item); + return; + } + switch (item) { + case PhotoModel _: + final photoList = items.whereType().toList(); + if (context.mounted) { + await Navigator.of(context, rootNavigator: true).push( + PageTransition( + child: PhotoViewerScreen( + items: photoList, + loadingItems: ref.read(librarySearchProvider(key).notifier).fetchGallery(), + indexOfSelected: photoList.indexWhere((element) => element.id == item.id), + ), + type: PageTransitionType.fade), + ); + } + if (context.mounted) context.refreshData(); + break; + default: + action.call(); + break; + } + } +} + +Map> groupByList(BuildContext context, List items, bool tags) { + Map tagsCount = {}; + for (var item in items) { + for (var tag in (tags ? item.overview.tags : item.overview.genres)) { + tagsCount[tag] = (tagsCount[tag] ?? 0) + 1; + } + } + + List sortedTags = tagsCount.keys.toList()..sort((a, b) => tagsCount[a]!.compareTo(tagsCount[b]!)); + + Map> groupedItems = {}; + + for (var item in items) { + List itemTags = (tags ? item.overview.tags : item.overview.genres); + itemTags.sort((a, b) => sortedTags.indexOf(a).compareTo(sortedTags.indexOf(b))); + String key = itemTags.take(2).join(', '); + key = key.isNotEmpty ? key : context.localized.none; + groupedItems[key] = [...(groupedItems[key] ?? []), item]; + } + + return groupedItems; +} diff --git a/lib/screens/library_search/widgets/suggestion_search_bar.dart b/lib/screens/library_search/widgets/suggestion_search_bar.dart new file mode 100644 index 0000000..d61ae16 --- /dev/null +++ b/lib/screens/library_search/widgets/suggestion_search_bar.dart @@ -0,0 +1,184 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/main.dart'; +import 'package:fladder/theme.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_typeahead/flutter_typeahead.dart'; +import 'package:page_transition/page_transition.dart'; + +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/providers/library_search_provider.dart'; +import 'package:fladder/util/debouncer.dart'; + +class SuggestionSearchBar extends ConsumerStatefulWidget { + final String? title; + final bool autoFocus; + final TextEditingController? textEditingController; + final Duration debounceDuration; + final SuggestionsController? suggestionsBoxController; + final Function(String value)? onSubmited; + final Function(String value)? onChanged; + final Function(ItemBaseModel value)? onItem; + const SuggestionSearchBar({ + this.title, + this.autoFocus = false, + this.textEditingController, + this.debounceDuration = const Duration(milliseconds: 250), + this.suggestionsBoxController, + this.onSubmited, + this.onChanged, + this.onItem, + super.key, + }); + + @override + ConsumerState createState() => _SearchBarState(); +} + +class _SearchBarState extends ConsumerState { + late final Debouncer debouncer = Debouncer(widget.debounceDuration); + late final SuggestionsController suggestionsBoxController = + widget.suggestionsBoxController ?? SuggestionsController(); + late final TextEditingController textEditingController = widget.textEditingController ?? TextEditingController(); + bool isEmpty = true; + final FocusNode focusNode = FocusNode(); + + @override + void initState() { + super.initState(); + if (widget.autoFocus) { + focusNode.requestFocus(); + } + super.initState(); + } + + @override + Widget build(BuildContext context) { + ref.listen(librarySearchProvider(widget.key!).select((value) => value.searchQuery), (previous, next) { + if (textEditingController.text != next) { + setState(() { + textEditingController.text = next; + }); + } + }); + return Card( + elevation: 2, + shadowColor: Colors.transparent, + child: TypeAheadField( + focusNode: focusNode, + hideOnEmpty: isEmpty, + emptyBuilder: (context) => Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + "${context.localized.noSuggestionsFound}...", + style: Theme.of(context).textTheme.titleMedium, + ), + ), + suggestionsController: suggestionsBoxController, + decorationBuilder: (context, child) => DecoratedBox( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.secondaryContainer, + borderRadius: FladderTheme.defaultShape.borderRadius, + ), + child: child, + ), + builder: (context, controller, focusNode) => TextField( + focusNode: focusNode, + controller: controller, + onSubmitted: (value) { + widget.onSubmited!(value); + suggestionsBoxController.close(); + }, + onChanged: (value) { + setState(() { + isEmpty = value.isEmpty; + }); + }, + decoration: InputDecoration( + hintText: widget.title ?? "${context.localized.search}...", + prefixIcon: Icon(IconsaxOutline.search_normal), + contentPadding: EdgeInsets.only(top: 13), + suffixIcon: controller.text.isNotEmpty + ? IconButton( + onPressed: () { + widget.onSubmited?.call(''); + controller.text = ''; + suggestionsBoxController.close(); + setState(() { + isEmpty = true; + }); + }, + icon: const Icon(Icons.clear)) + : null, + border: InputBorder.none, + ), + ), + loadingBuilder: (context) => const SizedBox( + height: 50, + child: Center(child: CircularProgressIndicator(strokeCap: StrokeCap.round)), + ), + onSelected: (suggestion) { + suggestionsBoxController.close(); + }, + itemBuilder: (context, suggestion) { + return ListTile( + onTap: () { + if (widget.onItem != null) { + widget.onItem?.call(suggestion); + } else { + Navigator.of(context) + .push(PageTransition(child: suggestion.detailScreenWidget, type: PageTransitionType.fade)); + } + }, + contentPadding: const EdgeInsets.symmetric(horizontal: 8), + title: SizedBox( + height: 50, + child: Row( + children: [ + Card( + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)), + child: AspectRatio( + aspectRatio: 0.8, + child: CachedNetworkImage( + cacheManager: CustomCacheManager.instance, + imageUrl: suggestion.images?.primary?.path ?? "", + fit: BoxFit.cover, + ), + ), + ), + const SizedBox(width: 8), + Flexible( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Flexible( + child: Text( + suggestion.name, + maxLines: 1, + overflow: TextOverflow.ellipsis, + )), + if (suggestion.overview.yearAired.toString().isNotEmpty) + Flexible( + child: + Opacity(opacity: 0.45, child: Text(suggestion.overview.yearAired?.toString() ?? ""))), + ], + ), + ), + ], + ), + ), + ); + }, + suggestionsCallback: (pattern) async { + if (pattern.isEmpty) return []; + if (widget.key != null) { + return (await ref.read(librarySearchProvider(widget.key!).notifier).fetchSuggestions(pattern)); + } + return []; + }, + ), + ); + } +} diff --git a/lib/screens/login/lock_screen.dart b/lib/screens/login/lock_screen.dart new file mode 100644 index 0000000..4e5d0b1 --- /dev/null +++ b/lib/screens/login/lock_screen.dart @@ -0,0 +1,145 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; + +import 'package:fladder/models/account_model.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/routes/build_routes/route_builder.dart'; +import 'package:fladder/screens/login/widgets/login_icon.dart'; +import 'package:fladder/screens/shared/fladder_snackbar.dart'; +import 'package:fladder/screens/shared/passcode_input.dart'; +import 'package:fladder/util/auth_service.dart'; + +final lockScreenActiveProvider = StateProvider((ref) => false); + +class LockScreen extends ConsumerStatefulWidget { + final bool selfLock; + const LockScreen({this.selfLock = false, super.key}); + + @override + ConsumerState createState() => _LockScreenState(); +} + +class _LockScreenState extends ConsumerState with WidgetsBindingObserver { + bool poppingLockScreen = false; + + @override + void didChangeAppLifecycleState(AppLifecycleState state) async { + switch (state) { + case AppLifecycleState.resumed: + hackyFixForBlackNavbar(); + default: + break; + } + } + + void hackyFixForBlackNavbar() { + SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge, overlays: []); + SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( + statusBarColor: Colors.transparent, + systemNavigationBarColor: Colors.transparent, + systemNavigationBarDividerColor: Colors.transparent, + )); + } + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addObserver(this); + Future.microtask(() { + ref.read(lockScreenActiveProvider.notifier).update((state) => true); + final user = ref.read(userProvider); + if (user != null && !widget.selfLock) { + tapLoggedInAccount(user); + } + }); + hackyFixForBlackNavbar(); + } + + void handleLogin(AccountModel user) { + ref.read(lockScreenActiveProvider.notifier).update((state) => false); + poppingLockScreen = true; + context.pop(); + } + + void tapLoggedInAccount(AccountModel user) async { + switch (user.authMethod) { + case Authentication.autoLogin: + handleLogin(user); + break; + case Authentication.biometrics: + final authenticated = await AuthService.authenticateUser(context, user); + if (authenticated && context.mounted) { + handleLogin(user); + } + break; + case Authentication.passcode: + if (context.mounted) { + showPassCodeDialog(context, (newPin) { + if (newPin == user.localPin) { + handleLogin(user); + } else { + fladderSnackbar(context, title: context.localized.incorrectPinTryAgain); + } + }); + } + break; + case Authentication.none: + handleLogin(user); + break; + } + } + + @override + Widget build(BuildContext context) { + final user = ref.watch(userProvider); + return PopScope( + canPop: false, + onPopInvoked: (didPop) { + if (!poppingLockScreen) { + SystemNavigator.pop(); + } + }, + child: Scaffold( + body: Center( + child: Wrap( + crossAxisAlignment: WrapCrossAlignment.center, + alignment: WrapAlignment.center, + runAlignment: WrapAlignment.center, + children: [ + const Icon( + IconsaxOutline.lock_1, + size: 38, + ), + ConstrainedBox( + constraints: BoxConstraints( + maxHeight: 400, + maxWidth: 400, + ), + child: Padding( + padding: const EdgeInsets.all(64.0), + child: LoginIcon( + user: user!, + onPressed: () => tapLoggedInAccount(user), + ), + ), + ), + ElevatedButton.icon( + onPressed: () { + ref.read(lockScreenActiveProvider.notifier).update((state) => false); + context.routeGo(LoginRoute()); + }, + icon: const Icon(Icons.login_rounded), + label: Text(context.localized.login), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/screens/login/login_edit_user.dart b/lib/screens/login/login_edit_user.dart new file mode 100644 index 0000000..5dfbf85 --- /dev/null +++ b/lib/screens/login/login_edit_user.dart @@ -0,0 +1,99 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/account_model.dart'; +import 'package:fladder/providers/auth_provider.dart'; +import 'package:fladder/providers/shared_provider.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:intl/intl.dart'; + +class LoginEditUser extends ConsumerWidget { + final AccountModel user; + final ValueChanged? onTapServer; + const LoginEditUser({required this.user, this.onTapServer, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return AlertDialog.adaptive( + title: Center(child: Text(user.name)), + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const Divider(), + if (user.credentials.serverName.isNotEmpty) + Row( + children: [ + const Icon(Icons.dns_rounded), + const SizedBox(width: 8), + Text(user.credentials.serverName), + ], + ), + if (user.credentials.server.isNotEmpty) + Row( + children: [ + const Icon(Icons.http_rounded), + const SizedBox(width: 8), + Text(user.credentials.server), + if (onTapServer != null) ...{ + const SizedBox(width: 8), + IconButton.filledTonal( + onPressed: () { + onTapServer?.call(user.credentials.server); + }, + icon: const Icon( + Icons.send_rounded, + ), + ) + } + ], + ), + Row( + children: [ + Icon(user.authMethod.icon), + const SizedBox(width: 8), + Text(user.authMethod.name(context)), + ], + ), + Row( + children: [ + Icon(IconsaxBold.clock), + const SizedBox(width: 8), + Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(DateFormat.yMMMEd().format(user.lastUsed)), + Text(DateFormat.Hms().format(user.lastUsed)), + ], + ), + ], + ), + const Divider(), + Tooltip( + message: "Removes the user and forces a logout", + waitDuration: const Duration(milliseconds: 500), + child: SizedBox( + height: 50, + child: ElevatedButton.icon( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.red, + foregroundColor: Colors.white, + ), + onPressed: () async { + await ref.read(sharedUtilityProvider).removeAccount(user); + ref.read(authProvider.notifier).getSavedAccounts(); + if (context.mounted) { + Navigator.of(context).pop(); + } + }, + icon: const Icon(Icons.remove_rounded), + label: const Text("Remove user"), + ), + ), + ), + ].addPadding(const EdgeInsets.symmetric(vertical: 8)), + ), + ); + } +} diff --git a/lib/screens/login/login_screen.dart b/lib/screens/login/login_screen.dart new file mode 100644 index 0000000..646a537 --- /dev/null +++ b/lib/screens/login/login_screen.dart @@ -0,0 +1,393 @@ +import 'dart:async'; +import 'dart:developer'; + +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/screens/login/lock_screen.dart'; +import 'package:fladder/screens/login/widgets/discover_servers_widget.dart'; +import 'package:fladder/screens/shared/fladder_logo.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/string_extensions.dart'; +import 'package:flutter/material.dart'; + +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; + +import 'package:fladder/models/account_model.dart'; +import 'package:fladder/providers/auth_provider.dart'; +import 'package:fladder/providers/shared_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/routes/build_routes/home_routes.dart'; +import 'package:fladder/routes/build_routes/route_builder.dart'; +import 'package:fladder/screens/login/login_edit_user.dart'; +import 'package:fladder/screens/login/login_user_grid.dart'; +import 'package:fladder/screens/shared/animated_fade_size.dart'; +import 'package:fladder/screens/shared/fladder_snackbar.dart'; +import 'package:fladder/screens/shared/outlined_text_field.dart'; +import 'package:fladder/screens/shared/passcode_input.dart'; +import 'package:fladder/util/auth_service.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/widgets/navigation_scaffold/components/fladder_appbar.dart'; + +class LoginScreen extends ConsumerStatefulWidget { + const LoginScreen({super.key}); + + @override + ConsumerState createState() => _LoginPageState(); +} + +class _LoginPageState extends ConsumerState { + List users = const []; + bool loading = false; + String? invalidUrl = ""; + bool startCheckingForErrors = false; + bool addingNewUser = false; + bool editingUsers = false; + late final TextEditingController serverTextController = TextEditingController(text: ""); + + final usernameController = TextEditingController(); + final passwordController = TextEditingController(); + final FocusNode focusNode = FocusNode(); + + void startAddingNewUser() { + setState(() { + addingNewUser = true; + editingUsers = false; + }); + } + + @override + void initState() { + super.initState(); + Future.microtask(() { + ref.read(userProvider.notifier).clear(); + final currentAccounts = ref.read(authProvider.notifier).getSavedAccounts(); + addingNewUser = currentAccounts.isEmpty; + ref.read(lockScreenActiveProvider.notifier).update((state) => true); + }); + } + + @override + Widget build(BuildContext context) { + final loggedInUsers = ref.watch(authProvider.select((value) => value.accounts)); + final authLoading = ref.watch(authProvider.select((value) => value.loading)); + return Scaffold( + appBar: const FladderAppbar(), + floatingActionButton: !addingNewUser + ? Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + if (!AdaptiveLayout.of(context).isDesktop) + FloatingActionButton( + key: Key("edit_button"), + child: Icon(IconsaxOutline.edit_2), + onPressed: () => setState(() => editingUsers = !editingUsers), + ), + FloatingActionButton( + key: Key("new_button"), + child: Icon(IconsaxOutline.add_square), + onPressed: startAddingNewUser, + ), + ].addInBetween(const SizedBox(width: 16)), + ) + : null, + body: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 900), + child: ListView( + shrinkWrap: true, + padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 32), + children: [ + Center( + child: FladderLogo(), + ), + AnimatedFadeSize( + child: addingNewUser + ? addUserFields(loggedInUsers, authLoading) + : Column( + key: UniqueKey(), + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + LoginUserGrid( + users: loggedInUsers, + editMode: editingUsers, + onPressed: (user) async => tapLoggedInAccount(user), + onLongPress: (user) => openUserEditDialogue(context, user), + ), + ], + ), + ), + ].addPadding(const EdgeInsets.symmetric(vertical: 16)), + ), + ), + ), + ); + } + + void _parseUrl(String url) { + setState(() { + ref.read(authProvider.notifier).setServer(""); + users = []; + + if (url.isEmpty) { + invalidUrl = ""; + return; + } + if (!Uri.parse(url).isAbsolute) { + invalidUrl = context.localized.invalidUrl; + return; + } + + if (!url.startsWith('https://') && !url.startsWith('http://')) { + invalidUrl = context.localized.invalidUrlDesc; + return; + } + + invalidUrl = null; + + if (invalidUrl == null) { + ref.read(authProvider.notifier).setServer(url.rtrim('/')); + } + }); + } + + void openUserEditDialogue(BuildContext context, AccountModel user) { + showDialog( + context: context, + builder: (context) => LoginEditUser( + user: user, + onTapServer: (value) { + setState(() { + _parseUrl(value); + serverTextController.text = value; + startAddingNewUser(); + }); + context.pop(); + }, + ), + ); + } + + void tapLoggedInAccount(AccountModel user) async { + switch (user.authMethod) { + case Authentication.autoLogin: + handleLogin(user); + break; + case Authentication.biometrics: + final authenticated = await AuthService.authenticateUser(context, user); + if (authenticated) { + handleLogin(user); + } + break; + case Authentication.passcode: + if (context.mounted) { + showPassCodeDialog(context, (newPin) { + if (newPin == user.localPin) { + handleLogin(user); + } else { + fladderSnackbar(context, title: context.localized.incorrectPinTryAgain); + } + }); + } + break; + case Authentication.none: + handleLogin(user); + break; + } + } + + Future handleLogin(AccountModel user) async { + await ref.read(authProvider.notifier).switchUser(); + await ref.read(sharedUtilityProvider).updateAccountInfo(user.copyWith( + lastUsed: DateTime.now(), + )); + ref.read(userProvider.notifier).updateUser(user.copyWith(lastUsed: DateTime.now())); + + loggedInGoToHome(); + } + + void loggedInGoToHome() { + ref.read(lockScreenActiveProvider.notifier).update((state) => false); + if (context.mounted) { + context.routeGo(DashboardRoute()); + } + } + + Future Function()? get enterCredentialsTryLogin => emptyFields() + ? null + : () async { + log('try login'); + serverTextController.text = serverTextController.text.rtrim('/'); + ref.read(authProvider.notifier).setServer(serverTextController.text.rtrim('/')); + final response = await ref.read(authProvider.notifier).authenticateByName( + usernameController.text, + passwordController.text, + ); + if (response?.isSuccessful == false) { + fladderSnackbar(context, + title: + "(${response?.base.statusCode}) ${response?.base.reasonPhrase ?? context.localized.somethingWentWrongPasswordCheck}"); + } else if (response?.body != null) { + loggedInGoToHome(); + } + }; + + bool emptyFields() { + return usernameController.text.isEmpty || passwordController.text.isEmpty; + } + + void retrieveListOfUsers() async { + serverTextController.text = serverTextController.text.rtrim('/'); + ref.read(authProvider.notifier).setServer(serverTextController.text); + setState(() => loading = true); + final response = await ref.read(authProvider.notifier).getPublicUsers(); + if ((response == null || response.isSuccessful == false) && context.mounted) { + fladderSnackbar(context, title: response?.base.reasonPhrase ?? context.localized.unableToConnectHost); + setState(() => startCheckingForErrors = true); + } + if (response?.body?.isEmpty == true) { + await Future.delayed(const Duration(seconds: 1)); + } + setState(() { + users = response?.body ?? []; + loading = false; + }); + } + + Widget addUserFields(List accounts, bool authLoading) { + return Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + if (accounts.isNotEmpty) + Padding( + padding: const EdgeInsets.all(8.0), + child: IconButton.filledTonal( + onPressed: () { + setState(() { + addingNewUser = false; + loading = false; + startCheckingForErrors = false; + serverTextController.text = ""; + usernameController.text = ""; + passwordController.text = ""; + invalidUrl = ""; + }); + ref.read(authProvider.notifier).setServer(""); + }, + icon: const Icon( + IconsaxOutline.arrow_left_2, + ), + ), + ), + Flexible( + child: OutlinedTextField( + controller: serverTextController, + onChanged: _parseUrl, + onSubmitted: (value) => retrieveListOfUsers(), + autoFillHints: const [AutofillHints.url], + keyboardType: TextInputType.url, + textInputAction: TextInputAction.go, + label: context.localized.server, + errorText: (invalidUrl == null || serverTextController.text.isEmpty || !startCheckingForErrors) + ? null + : invalidUrl, + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Tooltip( + message: context.localized.retrievePublicListOfUsers, + waitDuration: const Duration(seconds: 1), + child: IconButton.filled( + onPressed: () => retrieveListOfUsers(), + icon: const Icon( + IconsaxOutline.refresh, + ), + ), + ), + ), + ], + ), + AnimatedFadeSize( + child: invalidUrl == null + ? Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + if (loading || users.isNotEmpty) + AnimatedFadeSize( + duration: const Duration(milliseconds: 250), + child: loading + ? CircularProgressIndicator(key: UniqueKey(), strokeCap: StrokeCap.round) + : LoginUserGrid( + users: users, + onPressed: (value) { + usernameController.text = value.name; + passwordController.text = ""; + focusNode.requestFocus(); + }, + ), + ), + AutofillGroup( + child: Column( + children: [ + OutlinedTextField( + controller: usernameController, + autoFillHints: const [AutofillHints.username], + textInputAction: TextInputAction.next, + onChanged: (value) => setState(() {}), + label: context.localized.userName, + ), + OutlinedTextField( + controller: passwordController, + autoFillHints: const [AutofillHints.password], + keyboardType: TextInputType.visiblePassword, + focusNode: focusNode, + textInputAction: TextInputAction.send, + onSubmitted: (value) => enterCredentialsTryLogin?.call(), + onChanged: (value) => setState(() {}), + label: context.localized.password, + ), + FilledButton( + onPressed: enterCredentialsTryLogin, + child: authLoading + ? SizedBox( + width: 18, + height: 18, + child: CircularProgressIndicator( + color: Theme.of(context).colorScheme.inversePrimary, + strokeCap: StrokeCap.round), + ) + : Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text(context.localized.login), + const SizedBox(width: 8), + Icon(IconsaxBold.send_1), + ], + ), + ), + ].addPadding(const EdgeInsets.symmetric(vertical: 4)), + ), + ), + ].addPadding(const EdgeInsets.symmetric(vertical: 10)), + ) + : DiscoverServersWidget( + serverCredentials: accounts.map((e) => e.credentials).toList(), + onPressed: (server) { + serverTextController.text = server.address; + _parseUrl(server.address); + retrieveListOfUsers(); + }, + ), + ) + ].addPadding(const EdgeInsets.symmetric(vertical: 8)), + ); + } +} diff --git a/lib/screens/login/login_user_grid.dart b/lib/screens/login/login_user_grid.dart new file mode 100644 index 0000000..27012aa --- /dev/null +++ b/lib/screens/login/login_user_grid.dart @@ -0,0 +1,149 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/account_model.dart'; +import 'package:fladder/providers/auth_provider.dart'; +import 'package:fladder/screens/shared/user_icon.dart'; +import 'package:fladder/screens/shared/flat_button.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:reorderable_grid/reorderable_grid.dart'; + +class LoginUserGrid extends ConsumerWidget { + final List users; + final bool editMode; + final ValueChanged? onPressed; + final ValueChanged? onLongPress; + const LoginUserGrid({this.users = const [], this.onPressed, this.editMode = false, this.onLongPress, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final mainAxisExtent = 175.0; + final maxCount = (MediaQuery.of(context).size.width ~/ mainAxisExtent).clamp(1, 3); + + return ReorderableGridView.builder( + onReorder: (oldIndex, newIndex) => ref.read(authProvider.notifier).reOrderUsers(oldIndex, newIndex), + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + autoScroll: true, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: users.length == 1 ? 1 : maxCount, + mainAxisSpacing: 24, + crossAxisSpacing: 24, + mainAxisExtent: mainAxisExtent, + ), + itemCount: users.length, + itemBuilder: (context, index) { + final user = users[index]; + return _CardHolder( + key: Key(user.id), + content: Stack( + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + mainAxisSize: MainAxisSize.max, + children: [ + Flexible( + child: UserIcon( + labelStyle: Theme.of(context).textTheme.headlineMedium, + user: user, + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + children: [ + Icon( + user.authMethod.icon, + size: 18, + ), + const SizedBox(width: 4), + Flexible( + child: Text( + user.name, + maxLines: 2, + softWrap: true, + )), + ], + ), + if (user.credentials.serverName.isNotEmpty) + Opacity( + opacity: 0.75, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + children: [ + const Icon( + IconsaxBold.driver_2, + size: 14, + ), + const SizedBox(width: 4), + Flexible( + child: Text( + user.credentials.serverName, + maxLines: 2, + softWrap: true, + ), + ), + ], + ), + ) + ].addInBetween(SizedBox(width: 4, height: 4)), + ), + if (editMode) + Align( + alignment: Alignment.topRight, + child: Card( + color: Theme.of(context).colorScheme.errorContainer, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: const Icon( + IconsaxBold.edit_2, + size: 14, + ), + ), + ), + ) + ], + ), + onTap: () => editMode ? onLongPress?.call(user) : onPressed?.call(user), + onLongPress: () => onLongPress?.call(user), + ); + }, + ); + } +} + +class _CardHolder extends StatelessWidget { + final Widget content; + final Function() onTap; + final Function() onLongPress; + + const _CardHolder({ + required this.content, + required this.onTap, + required this.onLongPress, + super.key, + }); + + @override + Widget build(BuildContext context) { + return Card( + elevation: 1, + shadowColor: Colors.transparent, + clipBehavior: Clip.antiAlias, + margin: EdgeInsets.zero, + child: ConstrainedBox( + constraints: const BoxConstraints(maxHeight: 150, maxWidth: 150), + child: FlatButton( + onTap: onTap, + onLongPress: AdaptiveLayout.of(context).isDesktop ? onLongPress : null, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: content, + ), + ), + ), + ); + } +} diff --git a/lib/screens/login/widgets/discover_servers_widget.dart b/lib/screens/login/widgets/discover_servers_widget.dart new file mode 100644 index 0000000..6e1b788 --- /dev/null +++ b/lib/screens/login/widgets/discover_servers_widget.dart @@ -0,0 +1,161 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/credentials_model.dart'; +import 'package:fladder/providers/discovery_provider.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/theme_extensions.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class DiscoverServersWidget extends ConsumerWidget { + final List serverCredentials; + final Function(DiscoveryInfo server) onPressed; + const DiscoverServersWidget({ + required this.serverCredentials, + required this.onPressed, + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final existingServers = serverCredentials + .map( + (credentials) => DiscoveryInfo( + id: credentials.serverId, + name: credentials.serverName, + address: credentials.server, + endPointAddress: null), + ) + .toSet() + .toList(); + final discoverdServersStream = ref.watch(serverDiscoveryProvider); + return ListView( + padding: const EdgeInsets.all(6), + shrinkWrap: true, + children: [ + if (existingServers.isNotEmpty) ...[ + Row( + children: [ + Text( + context.localized.saved, + style: context.textTheme.bodyLarge, + ), + const Spacer(), + Opacity(opacity: 0.65, child: Icon(IconsaxOutline.bookmark, size: 16)), + ], + ), + const SizedBox(height: 4), + ...existingServers + .map( + (server) => _ServerInfoCard( + server: server, + onPressed: onPressed, + ), + ) + .toList() + .addInBetween(const SizedBox(height: 4)), + const Divider(), + ], + Row( + children: [ + Text( + context.localized.discovered, + style: context.textTheme.bodyLarge, + ), + const Spacer(), + Opacity(opacity: 0.65, child: Icon(IconsaxBold.airdrop, size: 16)), + ], + ), + const SizedBox(height: 4), + discoverdServersStream.when( + data: (data) { + final servers = data.where((discoverdServer) => !existingServers.contains(discoverdServer)); + return servers.isNotEmpty + ? Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ...servers.map( + (serverInfo) => _ServerInfoCard( + server: serverInfo, + onPressed: onPressed, + ), + ) + ].toList().addInBetween(const SizedBox(height: 4)), + ) + : Center( + child: Opacity( + opacity: 0.65, + child: Text( + context.localized.noServersFound, + style: context.textTheme.bodyLarge, + ), + )); + }, + error: (error, stackTrace) => Text(context.localized.error), + loading: () => Center( + child: SizedBox.square( + dimension: 24.0, + child: CircularProgressIndicator.adaptive(strokeCap: StrokeCap.round), + ), + ), + ), + const SizedBox(height: 32), + ], + ); + } +} + +class _ServerInfoCard extends StatelessWidget { + final Function(DiscoveryInfo server) onPressed; + final DiscoveryInfo server; + const _ServerInfoCard({ + required this.server, + required this.onPressed, + }); + + @override + Widget build(BuildContext context) { + return Card( + child: InkWell( + onTap: () => onPressed(server), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12), + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Card( + color: Theme.of(context).colorScheme.primaryContainer, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Icon( + IconsaxBold.driver, + color: Theme.of(context).colorScheme.onPrimaryContainer, + ), + ), + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + server.name, + style: context.textTheme.bodyLarge, + ), + Opacity( + opacity: 0.6, + child: Text( + server.address, + style: context.textTheme.bodyMedium, + ), + ), + ], + ), + ), + Icon(IconsaxOutline.edit_2, size: 16) + ].addInBetween(const SizedBox(width: 12)), + ), + ), + ), + ); + } +} diff --git a/lib/screens/login/widgets/login_icon.dart b/lib/screens/login/widgets/login_icon.dart new file mode 100644 index 0000000..dad6138 --- /dev/null +++ b/lib/screens/login/widgets/login_icon.dart @@ -0,0 +1,97 @@ +import 'package:fladder/models/account_model.dart'; +import 'package:fladder/screens/shared/flat_button.dart'; +import 'package:fladder/screens/shared/user_icon.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class LoginIcon extends ConsumerWidget { + final AccountModel user; + final Function()? onPressed; + final Function()? onLongPress; + final Function()? onNewPressed; + const LoginIcon({ + required this.user, + this.onPressed, + this.onLongPress, + this.onNewPressed, + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return AspectRatio( + aspectRatio: 1.0, + child: Card( + elevation: 1, + clipBehavior: Clip.antiAlias, + margin: EdgeInsets.zero, + child: Stack( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Expanded( + flex: 4, + child: UserIcon( + labelStyle: Theme.of(context).textTheme.displayMedium, + size: const Size(125, 125), + user: user, + ), + ), + Flexible( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (onNewPressed != null) + Icon( + user.authMethod.icon, + size: 26, + ), + const SizedBox(width: 4), + Flexible( + child: Text( + user.name, + maxLines: 2, + style: Theme.of(context).textTheme.titleLarge, + softWrap: true, + ), + ), + ], + ), + ), + if (user.credentials.serverName.isNotEmpty) + Flexible( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.dns_rounded, + size: 14, + ), + const SizedBox(width: 4), + Flexible( + child: Text( + user.credentials.serverName, + maxLines: 2, + softWrap: true, + ), + ), + ], + ), + ) + ].addInBetween(SizedBox(width: 8, height: 8)), + ), + ), + FlatButton( + onTap: onPressed, + onLongPress: onLongPress, + ) + ], + ), + ), + ); + } +} diff --git a/lib/screens/media_content.dart b/lib/screens/media_content.dart new file mode 100644 index 0000000..8b53297 --- /dev/null +++ b/lib/screens/media_content.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class MediaContent extends ConsumerStatefulWidget { + const MediaContent({super.key}); + + @override + ConsumerState createState() => MediaContentState(); +} + +class MediaContentState extends ConsumerState { + @override + Widget build(BuildContext context) { + return Container(); + } +} diff --git a/lib/screens/metadata/edit_item.dart b/lib/screens/metadata/edit_item.dart new file mode 100644 index 0000000..6fc06a3 --- /dev/null +++ b/lib/screens/metadata/edit_item.dart @@ -0,0 +1,165 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/providers/edit_item_provider.dart'; +import 'package:fladder/screens/metadata/edit_screens/edit_fields.dart'; +import 'package:fladder/screens/metadata/edit_screens/edit_image_content.dart'; +import 'package:fladder/screens/shared/fladder_snackbar.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/refresh_state.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +Future showEditItemPopup( + BuildContext context, + String itemId, +) async { + ItemBaseModel? updatedItem; + var shouldRefresh = false; + await showDialog( + context: context, + useSafeArea: false, + builder: (context) { + Widget editWidget() => EditDialogSwitcher( + id: itemId, + itemUpdated: (newItem) => updatedItem = newItem, + refreshOnClose: (refresh) => shouldRefresh = refresh, + ); + return AdaptiveLayout.of(context).inputDevice == InputDevice.pointer + ? Dialog( + insetPadding: EdgeInsets.all(64), + child: editWidget(), + ) + : Dialog.fullscreen( + child: editWidget(), + ); + }, + ); + if (shouldRefresh == true) { + context.refreshData(); + } + return updatedItem; +} + +class EditDialogSwitcher extends ConsumerStatefulWidget { + final String id; + final Function(ItemBaseModel? newItem) itemUpdated; + final Function(bool refresh) refreshOnClose; + + const EditDialogSwitcher({required this.id, required this.itemUpdated, required this.refreshOnClose, super.key}); + + @override + ConsumerState createState() => _EditDialogSwitcherState(); +} + +class _EditDialogSwitcherState extends ConsumerState with TickerProviderStateMixin { + late final TabController tabController = TabController(length: 5, vsync: this); + + Future refreshEditor() async { + return ref.read(editItemProvider.notifier).fetchInformation(widget.id); + } + + @override + void initState() { + super.initState(); + Future.microtask(() => refreshEditor()); + } + + @override + Widget build(BuildContext context) { + final currentItem = ref.watch(editItemProvider.select((value) => value.item)); + final saving = ref.watch(editItemProvider.select((value) => value.saving)); + final state = ref.watch(editItemProvider).editedJson; + final generalFields = ref.watch(editItemProvider.notifier).getFields ?? {}; + final advancedFields = ref.watch(editItemProvider.notifier).advancedFields ?? {}; + + Map widgets = { + Tab(text: "General"): EditFields(fields: generalFields, json: state), + Tab(text: "Primary"): EditImageContent(type: ImageType.primary), + Tab(text: "Logo"): EditImageContent(type: ImageType.logo), + Tab(text: "Backdrops"): EditImageContent(type: ImageType.backdrop), + Tab(text: "Advanced"): EditFields(fields: advancedFields, json: state), + }; + + return Card( + color: Theme.of(context).colorScheme.surface, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox(height: MediaQuery.paddingOf(context).top), + Container( + color: Theme.of(context).colorScheme.surface, + child: Padding( + padding: const EdgeInsets.all(16), + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Text( + currentItem?.detailedName(context) ?? currentItem?.name ?? "", + overflow: TextOverflow.ellipsis, + maxLines: 2, + style: Theme.of(context).textTheme.titleLarge, + ), + ), + IconButton(onPressed: () => refreshEditor(), icon: Icon(IconsaxOutline.refresh)) + ], + ), + ), + ), + Container( + color: Theme.of(context).colorScheme.surface, + child: TabBar( + isScrollable: true, + controller: tabController, + tabs: widgets.keys.toList(), + ), + ), + Flexible(child: TabBarView(controller: tabController, children: widgets.values.toList())), + Container( + color: Theme.of(context).colorScheme.surface, + child: Padding( + padding: const EdgeInsets.all(16), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + ElevatedButton(onPressed: () => Navigator.of(context).pop(), child: Text(context.localized.close)), + const SizedBox(width: 16), + FilledButton( + onPressed: saving + ? null + : () async { + final response = await ref.read(editItemProvider.notifier).saveInformation(); + if (response != null && context.mounted) { + if (response.isSuccessful) { + widget.itemUpdated(response.body); + fladderSnackbar(context, + title: context.localized.metaDataSavedFor( + currentItem?.detailedName(context) ?? currentItem?.name ?? "")); + } else { + fladderSnackbarResponse(context, response); + } + } + widget.refreshOnClose(true); + Navigator.of(context).pop(); + }, + child: saving + ? SizedBox( + width: 21, + height: 21, + child: CircularProgressIndicator.adaptive( + backgroundColor: Theme.of(context).colorScheme.onPrimary, strokeCap: StrokeCap.round), + ) + : Text(context.localized.save), + ), + ], + ), + ), + ) + ], + ), + ); + } +} diff --git a/lib/screens/metadata/edit_screens/edit_fields.dart b/lib/screens/metadata/edit_screens/edit_fields.dart new file mode 100644 index 0000000..17b7628 --- /dev/null +++ b/lib/screens/metadata/edit_screens/edit_fields.dart @@ -0,0 +1,738 @@ +import 'package:collection/collection.dart'; +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/providers/edit_item_provider.dart'; +import 'package:fladder/screens/settings/settings_list_tile.dart'; +import 'package:fladder/screens/shared/focused_outlined_text_field.dart'; +import 'package:fladder/screens/shared/media/external_urls.dart'; +import 'package:fladder/screens/shared/outlined_text_field.dart'; +import 'package:fladder/util/jelly_id.dart'; +import 'package:fladder/util/list_extensions.dart'; +import 'package:fladder/util/string_extensions.dart'; +import 'package:fladder/widgets/shared/adaptive_date_picker.dart'; +import 'package:fladder/widgets/shared/enum_selection.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:intl/intl.dart'; + +class EditFields extends ConsumerStatefulWidget { + final Map fields; + final Map? json; + const EditFields({ + required this.fields, + required this.json, + super.key, + }); + + @override + ConsumerState createState() => _EditGeneralState(); +} + +class _EditGeneralState extends ConsumerState { + TextEditingController? currentController = TextEditingController(); + String? currentEditingKey; + List expandedKeys = []; + + final personName = TextEditingController(); + PersonKind personType = PersonKind.actor; + final personRole = TextEditingController(); + + @override + Widget build(BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Flexible( + child: ListView( + padding: EdgeInsets.symmetric(horizontal: 16), + shrinkWrap: true, + children: [ + if (widget.json != null) + ...widget.fields.entries.map( + (e) { + final keyLabel = e.key.toUpperCaseSplit(); + return Padding( + padding: const EdgeInsets.symmetric(vertical: 12), + child: switch (e.value) { + Map _ => Builder(builder: (context) { + final map = e.value as Map; + return SettingsListTile( + label: Text(keyLabel), + trailing: EnumBox( + current: map.entries.firstWhereOrNull((element) => element.value == true)?.key ?? "", + itemBuilder: (context) => [ + PopupMenuItem( + child: Text(""), + onTap: () => ref.read(editItemProvider.notifier).updateField(MapEntry(e.key, "")), + ), + ...map.entries.map( + (mapEntry) => PopupMenuItem( + child: Text(mapEntry.key), + onTap: () => ref + .read(editItemProvider.notifier) + .updateField(MapEntry(e.key, mapEntry.key)), + ), + ) + ], + ), + ); + }), + List _ => Padding( + padding: const EdgeInsets.symmetric(vertical: 21), + child: Builder(builder: (context) { + final expanded = expandedKeys.contains(e.key); + final list = e.value as List; + return Card( + child: InkWell( + onTap: () => setState(() => expandedKeys = expandedKeys.toggle(e.key)), + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + keyLabel, + style: Theme.of(context).textTheme.titleLarge, + ), + const Spacer(), + IconButton( + onPressed: () => + setState(() => expandedKeys = expandedKeys.toggle(e.key)), + icon: Icon(expanded + ? Icons.keyboard_arrow_up_rounded + : Icons.keyboard_arrow_down_rounded), + ) + ], + ), + if (expanded) ...{ + const SizedBox(height: 6), + ...list.map( + (genre) => Row( + children: [ + Text(genre.toString()), + const Spacer(), + IconButton( + onPressed: () => ref.read(editItemProvider.notifier).updateField( + MapEntry(e.key, list..remove(genre)), + ), + icon: Icon(Icons.remove_rounded)) + ], + ), + ), + OutlinedTextField( + label: "Add", + controller: TextEditingController(), + onSubmitted: (value) { + ref.read(editItemProvider.notifier).updateField( + MapEntry(e.key, list..add(value)), + ); + }, + ) + }, + ], + ), + ), + ), + ); + }), + ), + List _ => Padding( + padding: const EdgeInsets.symmetric(vertical: 21), + child: Builder(builder: (context) { + final expanded = expandedKeys.contains(e.key); + final list = e.value as List; + + List> listToMap(List people) { + return people.map((e) => e.toPerson().toJson()).toList(); + } + + return Card( + child: InkWell( + onTap: () => setState(() => expandedKeys = expandedKeys.toggle(e.key)), + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + keyLabel, + style: Theme.of(context).textTheme.titleLarge, + ), + const Spacer(), + IconButton( + onPressed: () => + setState(() => expandedKeys = expandedKeys.toggle(e.key)), + icon: Icon(expanded + ? Icons.keyboard_arrow_up_rounded + : Icons.keyboard_arrow_down_rounded), + ) + ], + ), + if (expanded) ...{ + const SizedBox(height: 6), + ...list.map( + (person) => Padding( + padding: const EdgeInsets.symmetric(vertical: 6), + child: Row( + children: [ + SizedBox( + height: 50, + width: 50, + child: Card( + elevation: 2, + color: Theme.of(context).colorScheme.onPrimary, + child: Center( + child: Text( + person.name.getInitials(), + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith(fontWeight: FontWeight.bold), + ), + ), + ), + ), + const SizedBox(width: 6), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(person.name), + Opacity( + opacity: 0.65, + child: Text(person.role.isNotEmpty + ? "${person.role} (${person.type}) " + : person.type?.value ?? ""), + ), + ], + ), + const Spacer(), + IconButton( + onPressed: () { + ref.read(editItemProvider.notifier).updateField( + MapEntry(e.key, listToMap(list..remove(person)))); + }, + icon: Icon(Icons.remove_rounded)) + ], + ), + ), + ), + const SizedBox(height: 16), + Row( + children: [ + Expanded( + child: OutlinedTextField( + label: "Name", + controller: personName, + ), + ), + const SizedBox(width: 16), + Flexible( + child: EnumBox( + current: personType.name.toUpperCaseSplit(), + itemBuilder: (context) => [ + ...PersonKind.values + .whereNot( + (element) => element == PersonKind.swaggerGeneratedUnknown) + .map( + (entry) => PopupMenuItem( + child: Text(entry.name.toUpperCaseSplit()), + onTap: () { + setState(() { + personType = entry; + }); + }, + ), + ) + ], + ), + ), + const SizedBox(width: 16), + IconButton( + onPressed: () { + ref.read(editItemProvider.notifier).updateField(MapEntry( + e.key, + listToMap(list + ..add( + Person( + id: jellyId, + name: personName.text, + type: personType, + role: personRole.text, + ), + )))); + setState(() { + personName.text = ""; + personType = PersonKind.actor; + personRole.text = ""; + }); + }, + icon: Icon(Icons.add_rounded), + ) + ], + ), + }, + ], + ), + ), + ), + ); + }), + ), + List _ => Padding( + padding: const EdgeInsets.symmetric(vertical: 21), + child: Builder(builder: (context) { + final expanded = expandedKeys.contains(e.key); + final list = e.value as List; + final name = TextEditingController(); + final url = TextEditingController(); + return Card( + child: InkWell( + onTap: () => setState(() => expandedKeys = expandedKeys.toggle(e.key)), + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + keyLabel, + style: Theme.of(context).textTheme.titleLarge, + ), + const Spacer(), + IconButton( + onPressed: () => + setState(() => expandedKeys = expandedKeys.toggle(e.key)), + icon: Icon(expanded + ? Icons.keyboard_arrow_up_rounded + : Icons.keyboard_arrow_down_rounded), + ) + ], + ), + if (expanded) ...{ + const SizedBox(height: 6), + ...list.map( + (externalUrl) => Row( + children: [ + Text(externalUrl.name), + const Spacer(), + Tooltip( + message: "Open in browser", + child: IconButton( + onPressed: () => launchUrl(context, externalUrl.url), + icon: Icon(Icons.open_in_browser_rounded)), + ), + IconButton( + onPressed: () { + ref.read(editItemProvider.notifier).updateField( + MapEntry( + e.key, + (list..remove(externalUrl)) + .map((e) => e.toMap()) + .toList()), + ); + }, + icon: Icon(Icons.remove_rounded)) + ], + ), + ), + Row( + children: [ + Flexible( + child: OutlinedTextField( + label: "Name", + controller: name, + ), + ), + const SizedBox(width: 16), + Flexible( + child: OutlinedTextField( + label: "Url", + controller: url, + ), + ), + const SizedBox(width: 16), + IconButton( + onPressed: () { + ref.read(editItemProvider.notifier).updateField( + MapEntry( + e.key, + (list + ..add( + ExternalUrls(name: name.text, url: url.text), + )) + .map((e) => e.toMap()) + .toList()), + ); + }, + icon: Icon(Icons.add_rounded), + ) + ], + ), + }, + ], + ), + ), + ), + ); + }), + ), + List _ => Padding( + padding: const EdgeInsets.symmetric(vertical: 21), + child: Builder(builder: (context) { + final expanded = expandedKeys.contains(e.key); + + final list = e.value as List; + + void setMapping(List newList) { + ref.read(editItemProvider.notifier).updateField( + MapEntry(e.key, newList.map((e) => e.toMap()).toList()), + ); + } + + return Card( + child: InkWell( + onTap: () => setState(() => expandedKeys = expandedKeys.toggle(e.key)), + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + keyLabel, + style: Theme.of(context).textTheme.titleLarge, + ), + const Spacer(), + IconButton( + onPressed: () => + setState(() => expandedKeys = expandedKeys.toggle(e.key)), + icon: Icon(expanded + ? Icons.keyboard_arrow_up_rounded + : Icons.keyboard_arrow_down_rounded), + ) + ], + ), + if (expanded) ...[ + const SizedBox(height: 6), + ...list.map( + (studio) => Row( + children: [ + Text(studio.name), + const Spacer(), + IconButton( + onPressed: () => setMapping(list..remove(studio)), + icon: Icon(Icons.remove_rounded)) + ], + ), + ), + const SizedBox(height: 6), + OutlinedTextField( + label: "Add", + controller: TextEditingController(), + onSubmitted: (value) => + setMapping(list..add(Studio(id: jellyId, name: value))), + ) + ] + ], + ), + ), + ), + ); + }), + ), + int value => Builder(builder: (context) { + final controller = currentEditingKey == e.key + ? currentController + : TextEditingController(text: value.toString()); + return FocusedOutlinedTextField( + label: switch (e.key) { + "IndexNumber" => "Episode Number", + "ParentIndexNumber" => "Season Number", + _ => keyLabel, + }, + controller: controller, + inputFormatters: [FilteringTextInputFormatter.digitsOnly], + onFocus: (focused) { + if (focused) { + currentController = controller; + currentEditingKey = e.key; + } else { + currentController = null; + currentEditingKey = null; + } + }, + onSubmitted: (value) { + final newYear = int.tryParse(value); + if (newYear != null) { + ref.read(editItemProvider.notifier).updateField( + MapEntry(e.key, newYear), + ); + } + }, + keyboardType: TextInputType.number, + onChanged: (value) { + if (currentEditingKey != e.key) { + currentEditingKey = e.key; + currentController = controller; + } + final newYear = int.tryParse(value); + if (newYear != null) { + ref.read(editItemProvider.notifier).updateField( + MapEntry(e.key, newYear), + ); + } + }, + ); + }), + double value => Builder(builder: (context) { + final controller = currentEditingKey == e.key + ? currentController + : TextEditingController(text: value.toString()); + return FocusedOutlinedTextField( + label: keyLabel, + controller: controller, + onFocus: (focused) { + if (focused) { + currentController = controller; + currentEditingKey = e.key; + } else { + currentController = null; + currentEditingKey = null; + } + }, + onSubmitted: (newValue) { + final newRating = double.tryParse(newValue); + if (newRating != null) { + ref.read(editItemProvider.notifier).updateField( + MapEntry(e.key, newRating), + ); + } else { + controller?.text = value.toString(); + } + currentController = null; + }, + keyboardType: TextInputType.number, + ); + }), + DateTime _ => Row( + children: [ + Flexible( + child: FocusedOutlinedTextField( + label: keyLabel, + onTap: () async { + FocusScope.of(context).requestFocus(FocusNode()); + final newDate = await showAdaptiveDatePicker( + context, + initialDateTime: e.value, + ); + if (newDate == null) return; + ref + .read(editItemProvider.notifier) + .updateField(MapEntry(e.key, newDate.toIso8601String())); + }, + controller: + TextEditingController(text: DateFormat.yMMMEd().format((e.value as DateTime))), + ), + ), + const SizedBox(width: 12), + IconButton( + onPressed: () async { + final newDate = await showDatePicker( + context: context, + currentDate: DateTime.now(), + initialDate: e.value, + firstDate: DateTime(1950), + lastDate: DateTime(2100), + ); + if (newDate == null) return; + ref + .read(editItemProvider.notifier) + .updateField(MapEntry(e.key, newDate.toIso8601String())); + }, + icon: Icon(IconsaxOutline.calendar_2)) + ], + ), + DisplayOrder _ => Builder(builder: (context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SettingsListTile( + label: Text(keyLabel), + trailing: EnumBox( + current: (e.value as DisplayOrder).value.toUpperCaseSplit(), + itemBuilder: (context) => DisplayOrder.values + .map( + (mapEntry) => PopupMenuItem( + child: Text(mapEntry.value.toUpperCaseSplit()), + onTap: () => ref + .read(editItemProvider.notifier) + .updateField(MapEntry(e.key, mapEntry.value)), + ), + ) + .toList(), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Text("Order episodes by air date, DVD order, or absolute numbering."), + ) + ], + ); + }), + ShowStatus _ => Builder(builder: (context) { + return SettingsListTile( + label: Text(keyLabel), + trailing: EnumBox( + current: (e.value as ShowStatus).value, + itemBuilder: (context) => ShowStatus.values + .map( + (mapEntry) => PopupMenuItem( + child: Text(mapEntry.value), + onTap: () => ref + .read(editItemProvider.notifier) + .updateField(MapEntry(e.key, mapEntry.value)), + ), + ) + .toList(), + ), + ); + }), + bool _ => SettingsListTile( + label: Text(keyLabel), + trailing: Switch.adaptive( + value: e.value as bool, + onChanged: (value) => + ref.read(editItemProvider.notifier).updateField(MapEntry(e.key, value)), + ), + ), + Duration _ => Builder(builder: (context) { + final valueInMinutes = (e.value as Duration).inMinutes.toString(); + final controller = currentEditingKey == e.key + ? currentController + : TextEditingController(text: valueInMinutes); + return FocusedOutlinedTextField( + label: keyLabel, + controller: controller, + onFocus: (focused) { + if (focused) { + currentController = controller; + currentEditingKey = e.key; + } else { + currentController = null; + currentEditingKey = null; + } + }, + keyboardType: TextInputType.number, + onSubmitted: (value) { + final newMinutes = int.tryParse(value); + if (newMinutes != null) { + ref.read(editItemProvider.notifier).updateField( + MapEntry(e.key, Duration(minutes: newMinutes).inMilliseconds * 10000), + ); + } else { + controller?.text = valueInMinutes; + } + }, + ); + }), + Map _ => Builder(builder: (context) { + final map = e.value as Map; + return Card( + child: InkWell( + onTap: () => setState(() => expandedKeys = expandedKeys.toggle(e.key)), + child: Padding( + padding: const EdgeInsets.all(12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text(keyLabel, style: Theme.of(context).textTheme.titleLarge), + const SizedBox(height: 6), + Text( + "Uncheck a field to lock it and prevent its data from being changed.", + ), + const SizedBox(height: 6), + Column( + children: map.entries + .map((values) => Row( + children: [ + Text(values.key.value), + const Spacer(), + Switch.adaptive( + value: !values.value, + onChanged: (value) { + final newEntries = map; + newEntries.update(values.key, (value) => !value); + final newValues = newEntries.entries + .where((element) => element.value == true) + .map((e) => e.key.value); + ref + .read(editItemProvider.notifier) + .updateField(MapEntry(e.key, newValues.toList())); + }, + ) + ], + )) + .toList(), + ) + ], + ), + ), + ), + ); + }), + String value => Builder(builder: (context) { + final controller = + currentEditingKey == e.key ? currentController : TextEditingController(text: value); + return FocusedOutlinedTextField( + label: keyLabel, + maxLines: e.key == "Overview" ? 5 : 1, + controller: controller, + onFocus: (focused) { + if (focused) { + currentEditingKey = e.key; + currentController = controller; + } else { + currentController = null; + currentEditingKey = null; + } + }, + onSubmitted: (value) => + ref.read(editItemProvider.notifier).updateField(MapEntry(e.key, value)), + onChanged: (value) { + if (currentEditingKey != e.key) { + currentEditingKey = e.key; + currentController = controller; + } + return ref.read(editItemProvider.notifier).updateField(MapEntry(e.key, value)); + }, + ); + }), + _ => Text("Not supported ${e.value.runtimeType}: ${e.value}"), + }, + ); + }, + ) + else + Padding( + padding: const EdgeInsets.all(8.0), + child: Center( + child: CircularProgressIndicator.adaptive(strokeCap: StrokeCap.round), + ), + ), + const SizedBox(height: 16), + ], + ), + ), + ], + ); + } +} diff --git a/lib/screens/metadata/edit_screens/edit_image_content.dart b/lib/screens/metadata/edit_screens/edit_image_content.dart new file mode 100644 index 0000000..4670216 --- /dev/null +++ b/lib/screens/metadata/edit_screens/edit_image_content.dart @@ -0,0 +1,243 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.dart'; +import 'package:fladder/models/item_editing_model.dart'; +import 'package:fladder/providers/edit_item_provider.dart'; +import 'package:fladder/providers/settings/client_settings_provider.dart'; +import 'package:fladder/screens/settings/settings_list_tile.dart'; +import 'package:fladder/screens/shared/file_picker.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class EditImageContent extends ConsumerStatefulWidget { + final ImageType type; + const EditImageContent({required this.type, super.key}); + + @override + ConsumerState createState() => _EditImageContentState(); +} + +class _EditImageContentState extends ConsumerState { + bool loading = false; + + Future loadAll() async { + setState(() { + loading = true; + }); + await ref.read(editItemProvider.notifier).fetchRemoteImages(type: widget.type); + setState(() { + loading = false; + }); + } + + @override + void initState() { + super.initState(); + Future.microtask(() => loadAll()); + } + + @override + Widget build(BuildContext context) { + final posterSize = MediaQuery.sizeOf(context).width / + (AdaptiveLayout.poster(context).gridRatio * + ref.watch(clientSettingsProvider.select((value) => value.posterSize))); + final decimal = posterSize - posterSize.toInt(); + final includeAllImages = ref.watch(editItemProvider.select((value) => value.includeAllImages)); + final images = ref.watch(editItemProvider.select((value) => switch (widget.type) { + ImageType.backdrop => value.backdrop.images, + ImageType.logo => value.logo.images, + ImageType.primary || _ => value.primary.images, + })); + + final customImages = ref.watch(editItemProvider.select((value) => switch (widget.type) { + ImageType.backdrop => value.backdrop.customImages, + ImageType.logo => value.logo.customImages, + ImageType.primary || _ => value.primary.customImages, + })); + + final selectedImage = ref.watch(editItemProvider.select((value) => switch (widget.type) { + ImageType.logo => value.logo.selected, + ImageType.primary => value.primary.selected, + _ => null, + })); + + final serverImages = ref.watch(editItemProvider.select((value) => switch (widget.type) { + ImageType.logo => value.logo.serverImages, + ImageType.primary => value.primary.serverImages, + ImageType.backdrop => value.backdrop.serverImages, + _ => null, + })); + + final selections = ref.watch(editItemProvider.select((value) => switch (widget.type) { + ImageType.backdrop => value.backdrop.selection, + _ => [], + })); + + final serverImageCards = serverImages?.map((image) { + final selected = selectedImage == null; + return Stack( + alignment: Alignment.center, + children: [ + AspectRatio( + aspectRatio: image.ratio, + child: Tooltip( + message: "Server image", + child: Container( + decoration: BoxDecoration( + color: selected ? Theme.of(context).colorScheme.primary : Colors.transparent, + borderRadius: BorderRadius.circular(10), + border: + Border.all(color: Colors.transparent, width: 4, strokeAlign: BorderSide.strokeAlignInside), + ), + child: Card( + color: selected ? Theme.of(context).colorScheme.onPrimary : null, + child: InkWell( + onTap: () => ref.read(editItemProvider.notifier).selectImage(widget.type, null), + child: CachedNetworkImage( + cacheKey: image.hashCode.toString(), + imageUrl: image.url ?? "", + ), + ), + ), + ), + ), + ), + Align( + alignment: Alignment.bottomRight, + child: Transform.translate( + offset: Offset(2, 2), + child: IconButton.filledTonal( + style: FilledButton.styleFrom( + backgroundColor: Theme.of(context).colorScheme.error, + foregroundColor: Theme.of(context).colorScheme.onError, + ), + onPressed: () async { + await showDialog( + context: context, + builder: (context) => AlertDialog.adaptive( + title: Text("Delete image"), + content: Text("Deleting is permanent are you sure?"), + actions: [ + ElevatedButton(onPressed: () => Navigator.of(context).pop(), child: Text("Cancel")), + FilledButton( + style: FilledButton.styleFrom( + backgroundColor: Theme.of(context).colorScheme.error, + foregroundColor: Theme.of(context).colorScheme.onError, + ), + onPressed: () async { + await ref.read(editItemProvider.notifier).deleteImage(widget.type, image); + Navigator.of(context).pop(); + }, + child: Text( + "Delete", + ), + ) + ], + ), + ); + }, + icon: Icon(Icons.delete_rounded), + ), + ), + ) + ], + ); + }) ?? + []; + + final imageCards = [...customImages, ...images].map((image) { + final selected = switch (widget.type) { + ImageType.backdrop => selections.contains(image), + _ => selectedImage == image, + }; + return Stack( + alignment: Alignment.center, + children: [ + AspectRatio( + aspectRatio: image.ratio, + child: Tooltip( + message: "${image.providerName} - ${image.language} \n${image.width}x${image.height}", + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + border: Border.all( + color: selected ? Theme.of(context).colorScheme.primary : Colors.transparent, + width: 4, + strokeAlign: BorderSide.strokeAlignInside), + ), + child: Card( + color: selected ? Theme.of(context).colorScheme.onPrimary : null, + child: InkWell( + onTap: () => ref.read(editItemProvider.notifier).selectImage(widget.type, image), + child: image.imageData != null + ? Image(image: Image.memory(image.imageData!).image) + : CachedNetworkImage( + imageUrl: image.url ?? "", + ), + ), + ), + ), + ), + ), + ], + ); + }).toList(); + return Column( + children: [ + SizedBox( + height: 80, + child: FilePickerBar( + multipleFiles: switch (widget.type) { + ImageType.backdrop => true, + _ => false, + }, + extensions: FladderFile.imageTypes, + urlPicked: (url) { + final newFile = EditingImageModel(providerName: "Custom(URL)", url: url); + ref.read(editItemProvider.notifier).addCustomImages(widget.type, [newFile]); + }, + onFilesPicked: (file) { + final newFiles = file.map( + (e) => EditingImageModel( + providerName: "Custom(${e.name})", + imageData: e.data, + ), + ); + ref.read(editItemProvider.notifier).addCustomImages(widget.type, newFiles); + }, + ), + ), + SettingsListTile( + label: Text("Include all languages"), + trailing: Switch.adaptive( + value: includeAllImages, + onChanged: (value) { + ref.read(editItemProvider.notifier).setIncludeImages(value); + loadAll(); + }, + ), + ), + Flexible( + child: Stack( + children: [ + GridView( + shrinkWrap: true, + scrollDirection: Axis.vertical, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + mainAxisSpacing: (8 * decimal) + 8, + crossAxisSpacing: (8 * decimal) + 8, + childAspectRatio: 1.0, + crossAxisCount: posterSize.toInt(), + ), + children: [...serverImageCards, ...imageCards], + ), + if (loading) Center(child: CircularProgressIndicator.adaptive(strokeCap: StrokeCap.round)), + if (!loading && [...serverImageCards, ...imageCards].isEmpty) + Center(child: Text("No ${widget.type.value}s found")) + ], + ), + ), + ], + ); + } +} diff --git a/lib/screens/metadata/identifty_screen.dart b/lib/screens/metadata/identifty_screen.dart new file mode 100644 index 0000000..f7d828b --- /dev/null +++ b/lib/screens/metadata/identifty_screen.dart @@ -0,0 +1,361 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:collection/collection.dart'; +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/providers/items/identify_provider.dart'; +import 'package:fladder/screens/shared/adaptive_dialog.dart'; +import 'package:fladder/screens/shared/fladder_snackbar.dart'; +import 'package:fladder/screens/shared/focused_outlined_text_field.dart'; +import 'package:fladder/screens/shared/media/external_urls.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/string_extensions.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +Future showIdentifyScreen(BuildContext context, ItemBaseModel item) async { + return showDialogAdaptive( + context: context, + builder: (context) => IdentifyScreen( + item: item, + ), + ); +} + +class IdentifyScreen extends ConsumerStatefulWidget { + final ItemBaseModel item; + const IdentifyScreen({required this.item, super.key}); + + @override + ConsumerState createState() => _IdentifyScreenState(); +} + +class _IdentifyScreenState extends ConsumerState with TickerProviderStateMixin { + late AutoDisposeStateNotifierProvider provider = identifyProvider(widget.item.id); + late final TabController tabController = TabController(length: 2, vsync: this); + + TextEditingController? currentController; + String? currentKey; + int currentTab = 0; + + @override + void initState() { + super.initState(); + Future.microtask(() => ref.read(provider.notifier).fetchInformation()); + } + + @override + Widget build(BuildContext context) { + final state = ref.watch(provider); + final posters = state.results; + final processing = state.processing; + return MediaQuery.removePadding( + context: context, + child: Card( + color: Theme.of(context).colorScheme.surface, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + color: Theme.of(context).colorScheme.surface, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox(height: MediaQuery.paddingOf(context).top), + Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + children: [ + Text( + widget.item.detailedName(context) ?? widget.item.name, + style: Theme.of(context).textTheme.titleLarge, + ), + const Spacer(), + IconButton( + onPressed: () async => await ref.read(provider.notifier).fetchInformation(), + icon: Icon(IconsaxOutline.refresh)), + ], + ), + ), + TabBar( + isScrollable: true, + controller: tabController, + onTap: (value) { + setState(() { + currentTab = value; + }); + }, + tabs: [ + Tab( + text: context.localized.search, + ), + Tab( + text: context.localized.result, + ) + ], + ) + ], + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.all(16), + child: TabBarView( + controller: tabController, + children: [ + inputFields(state), + if (posters.isEmpty) + Center( + child: processing + ? CircularProgressIndicator.adaptive(strokeCap: StrokeCap.round) + : Text(context.localized.noResults), + ) + else + Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text(context.localized.replaceAllImages), + const SizedBox(width: 16), + Switch.adaptive( + value: state.replaceAllImages, + onChanged: (value) { + ref + .read(provider.notifier) + .update((state) => state.copyWith(replaceAllImages: value)); + }, + ), + ], + ), + Flexible( + child: ListView( + shrinkWrap: true, + children: posters + .map((result) => ListTile( + title: Row( + children: [ + SizedBox( + width: 75, + child: Card( + child: CachedNetworkImage( + imageUrl: result.imageUrl ?? "", + errorWidget: (context, url, error) => SizedBox( + height: 75, + child: Card( + child: Center( + child: Text(result.name?.getInitials() ?? ""), + ), + ), + ), + ), + ), + ), + const SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "${result.name ?? ""}${result.productionYear != null ? "(${result.productionYear})" : ""}"), + Opacity( + opacity: 0.65, + child: Text(result.providerIds?.keys.join(',') ?? "")) + ], + ), + ), + Tooltip( + message: context.localized.openWebLink, + child: IconButton( + onPressed: () { + final providerKeyEntry = result.providerIds?.entries.first; + final providerKey = providerKeyEntry?.key; + final providerValue = providerKeyEntry?.value; + + final externalId = state.externalIds + .firstWhereOrNull((element) => element.key == providerKey) + ?.urlFormatString; + + final url = + externalId?.replaceAll("{0}", providerValue?.toString() ?? ""); + + launchUrl(context, url ?? ""); + }, + icon: Icon(Icons.launch_rounded)), + ), + Tooltip( + message: "Select result", + child: IconButton( + onPressed: !processing + ? () async { + final response = + await ref.read(provider.notifier).setIdentity(result); + if (response?.isSuccessful == true) { + fladderSnackbar(context, + title: + context.localized.setIdentityTo(result.name ?? "")); + } else { + fladderSnackbarResponse(context, response, + altTitle: context.localized.somethingWentWrong); + } + + Navigator.of(context).pop(); + } + : null, + icon: Icon(Icons.save_alt_rounded), + ), + ) + ], + ), + )) + .toList(), + ), + ), + ], + ) + ], + ), + ), + ), + Container( + color: Theme.of(context).colorScheme.surface, + child: Padding( + padding: const EdgeInsets.all(16), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + ElevatedButton(onPressed: () => Navigator.of(context).pop(), child: Text(context.localized.cancel)), + const SizedBox(width: 16), + FilledButton( + onPressed: !processing + ? () async { + await ref.read(provider.notifier).remoteSearch(); + tabController.animateTo(1); + } + : null, + child: processing + ? SizedBox( + width: 21, + height: 21, + child: CircularProgressIndicator.adaptive( + backgroundColor: Theme.of(context).colorScheme.onPrimary, strokeCap: StrokeCap.round), + ) + : Text(context.localized.search), + ), + SizedBox(height: MediaQuery.paddingOf(context).bottom), + ], + ), + ), + ), + ], + ), + ), + ); + } + + ListView inputFields(IdentifyModel state) { + return ListView( + shrinkWrap: true, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + FilledButton( + onPressed: () { + currentController = null; + currentKey = ""; + ref.read(provider.notifier).clearFields(); + }, + child: Text(context.localized.clear)), + ], + ), + const SizedBox(height: 6), + Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Builder(builder: (context) { + final controller = + currentKey == "Name" ? currentController : TextEditingController(text: state.searchString); + return FocusedOutlinedTextField( + label: context.localized.userName, + controller: controller, + onChanged: (value) { + currentController = controller; + currentKey = "Name"; + return ref.read(provider.notifier).update((state) => state.copyWith(searchString: value)); + }, + onSubmitted: (value) { + return ref.read(provider.notifier).update((state) => state.copyWith(searchString: value)); + }, + ); + }), + ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Builder(builder: (context) { + final controller = + currentKey == "Year" ? currentController : TextEditingController(text: state.year?.toString() ?? ""); + return FocusedOutlinedTextField( + label: context.localized.year(1), + controller: controller, + keyboardType: TextInputType.number, + onChanged: (value) { + currentController = controller; + currentKey = "Year"; + if (value.isEmpty) { + ref.read(provider.notifier).update((state) => state.copyWith( + year: () => null, + )); + return; + } + final newYear = int.tryParse(value); + if (newYear != null) { + ref.read(provider.notifier).update((state) => state.copyWith( + year: () => newYear, + )); + } else { + controller?.text = state.year?.toString() ?? ""; + } + }, + onSubmitted: (value) { + currentController = null; + currentKey = null; + if (value.isEmpty) { + ref.read(provider.notifier).update((state) => state.copyWith( + year: () => null, + )); + } + final newYear = int.tryParse(value); + if (newYear != null) { + ref.read(provider.notifier).update((state) => state.copyWith( + year: () => newYear, + )); + } + }, + ); + }), + ), + ...state.keys.entries.map( + (searchKey) => Builder(builder: (context) { + final controller = + currentKey == searchKey.key ? currentController : TextEditingController(text: searchKey.value); + return Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: FocusedOutlinedTextField( + label: searchKey.key, + controller: controller, + onChanged: (value) { + currentController = controller; + currentKey = searchKey.key; + ref.read(provider.notifier).updateKey(MapEntry(searchKey.key, value)); + }, + onSubmitted: (value) => ref.read(provider.notifier).updateKey(MapEntry(searchKey.key, value)), + ), + ); + }), + ), + ], + ); + } +} diff --git a/lib/screens/metadata/info_screen.dart b/lib/screens/metadata/info_screen.dart new file mode 100644 index 0000000..6834781 --- /dev/null +++ b/lib/screens/metadata/info_screen.dart @@ -0,0 +1,217 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/information_model.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/providers/items/information_provider.dart'; +import 'package:fladder/screens/shared/fladder_snackbar.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/widgets/shared/clickable_text.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter/services.dart'; + +Future showInfoScreen(BuildContext context, ItemBaseModel item) async { + return showDialog( + context: context, + builder: (context) => ItemInfoScreen( + item: item, + ), + ); +} + +class ItemInfoScreen extends ConsumerStatefulWidget { + final ItemBaseModel item; + const ItemInfoScreen({required this.item, super.key}); + + @override + ConsumerState createState() => ItemInfoScreenState(); +} + +class ItemInfoScreenState extends ConsumerState { + late AutoDisposeStateNotifierProvider provider = + informationProvider(widget.item.id); + + @override + void initState() { + super.initState(); + Future.microtask(() => ref.read(provider.notifier).getItemInformation(widget.item)); + } + + Widget tileRow(String title, String value) { + return Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Flexible( + child: ClickableText( + text: title, + onTap: () async { + await Clipboard.setData(ClipboardData(text: value)); + fladderSnackbar(context, title: "Copied to clipboard"); + }, + style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold), + ), + ), + Text( + ": ", + style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold), + ), + Flexible( + flex: 3, + child: SelectableText( + value, + style: Theme.of(context).textTheme.titleMedium, + ), + ), + ], + ); + } + + Card streamModel(String title, Map map) { + return Card( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Flexible( + child: ClickableText( + text: title, + style: Theme.of(context).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.bold), + ), + ), + IconButton( + onPressed: () async { + await Clipboard.setData(ClipboardData(text: InformationModel.mapToString(map))); + fladderSnackbar(context, title: "Copied to clipboard"); + }, + icon: const Icon(Icons.copy_all_rounded)) + ], + ), + const SizedBox(height: 6), + ...map.entries + .where((element) => element.value != null) + .map((mapEntry) => tileRow(mapEntry.key, mapEntry.value.toString())) + ], + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + final info = ref.watch(provider); + final videoStreams = (info.model?.videoStreams.map((map) => streamModel("Video", map)) ?? []).toList(); + final audioStreams = (info.model?.audioStreams.map((map) => streamModel("Audio", map)) ?? []).toList(); + final subStreams = (info.model?.subStreams.map((map) => streamModel("Subtitle", map)) ?? []).toList(); + return Dialog( + child: Card( + color: Theme.of(context).colorScheme.surface, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + color: Theme.of(context).colorScheme.surface, + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(16), + child: Text( + widget.item.name, + style: Theme.of(context).textTheme.titleLarge, + ), + ), + Opacity(opacity: 0.3, child: const Divider()), + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + const Spacer(), + const SizedBox(width: 6), + IconButton( + onPressed: () async { + await Clipboard.setData(ClipboardData(text: info.model.toString())); + if (context.mounted) { + fladderSnackbar(context, title: "Copied to clipboard"); + } + }, + icon: const Icon(Icons.copy_all_rounded)), + const SizedBox(width: 6), + IconButton( + onPressed: () => ref.read(provider.notifier).getItemInformation(widget.item), + icon: const Icon(IconsaxOutline.refresh), + ), + ], + ), + ), + ], + ), + ), + const SizedBox(height: 6), + Flexible( + fit: FlexFit.loose, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: ListView( + shrinkWrap: true, + children: [ + Stack( + alignment: Alignment.center, + children: [ + if (info.model != null) ...{ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(width: double.infinity, child: streamModel("Info", info.model!.baseInformation)), + if ([...videoStreams, ...audioStreams, ...subStreams].isNotEmpty) ...{ + const Divider(), + Wrap( + alignment: WrapAlignment.start, + runAlignment: WrapAlignment.start, + crossAxisAlignment: WrapCrossAlignment.start, + runSpacing: 16, + spacing: 16, + children: [ + ...videoStreams, + ...audioStreams, + ...subStreams, + ], + ), + }, + ], + ), + }, + AnimatedOpacity( + opacity: info.loading ? 1 : 0, + duration: const Duration(milliseconds: 250), + child: const Center(child: CircularProgressIndicator.adaptive(strokeCap: StrokeCap.round)), + ) + ], + ), + ], + ), + ), + ), + Container( + color: Theme.of(context).colorScheme.surface, + child: Padding( + padding: const EdgeInsets.all(16), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + FilledButton(onPressed: () => Navigator.of(context).pop(), child: Text(context.localized.close)) + ], + ), + ), + ) + ], + ), + ), + ); + } +} diff --git a/lib/screens/metadata/refresh_metadata.dart b/lib/screens/metadata/refresh_metadata.dart new file mode 100644 index 0000000..a4980a2 --- /dev/null +++ b/lib/screens/metadata/refresh_metadata.dart @@ -0,0 +1,123 @@ +import 'package:fladder/jellyfin/enum_models.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/screens/settings/settings_list_tile.dart'; +import 'package:fladder/screens/shared/fladder_snackbar.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/widgets/shared/enum_selection.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +Future showRefreshPopup(BuildContext context, String itemId, String itemName) async { + return showDialog( + context: context, + builder: (context) => RefreshPopupDialog( + itemId: itemId, + name: itemName, + ), + ); +} + +class RefreshPopupDialog extends ConsumerStatefulWidget { + final String itemId; + final String name; + + const RefreshPopupDialog({required this.itemId, required this.name, super.key}); + + @override + ConsumerState createState() => _RefreshPopupDialogState(); +} + +class _RefreshPopupDialogState extends ConsumerState { + MetadataRefresh refreshMode = MetadataRefresh.defaultRefresh; + bool replaceAllMetadata = false; + + @override + Widget build(BuildContext context) { + return Dialog( + child: Card( + color: Theme.of(context).colorScheme.surface, + child: ConstrainedBox( + constraints: BoxConstraints( + maxWidth: AdaptiveLayout.of(context).inputDevice == InputDevice.pointer ? 700 : double.infinity), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + color: Theme.of(context).colorScheme.surface, + child: Padding( + padding: const EdgeInsets.all(16), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Flexible( + child: Text( + context.localized.refreshPopup(widget.name), + style: Theme.of(context).textTheme.titleLarge, + ), + ), + ], + ), + ), + ), + const SizedBox(height: 16), + EnumBox( + current: refreshMode.label(context), + itemBuilder: (context) => MetadataRefresh.values + .map((value) => PopupMenuItem( + value: value, + child: Text(value.label(context)), + onTap: () => setState(() { + refreshMode = value; + }), + )) + .toList(), + ), + if (refreshMode != MetadataRefresh.defaultRefresh) + SettingsListTile( + label: Text(context.localized.replaceExistingImages), + trailing: Switch.adaptive( + value: replaceAllMetadata, + onChanged: (value) => setState(() => replaceAllMetadata = value), + ), + ), + SettingsListTile( + label: Text( + context.localized.refreshPopupContentMetadata, + style: Theme.of(context).textTheme.bodyLarge, + ), + ), + const SizedBox(height: 16), + Container( + color: Theme.of(context).colorScheme.surface, + child: Padding( + padding: const EdgeInsets.all(16), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + FilledButton( + onPressed: () async { + final response = await ref.read(userProvider.notifier).refreshMetaData( + widget.itemId, + metadataRefreshMode: refreshMode, + replaceAllMetadata: replaceAllMetadata, + ); + if (!response.isSuccessful) { + fladderSnackbarResponse(context, response); + } else { + fladderSnackbar(context, title: context.localized.scanningName(widget.name)); + } + Navigator.of(context).pop(); + }, + child: Text(context.localized.refresh)), + ], + ), + ), + ) + ], + ), + ), + ), + ); + } +} diff --git a/lib/screens/photo_viewer/photo_viewer_controls.dart b/lib/screens/photo_viewer/photo_viewer_controls.dart new file mode 100644 index 0000000..5bb59a6 --- /dev/null +++ b/lib/screens/photo_viewer/photo_viewer_controls.dart @@ -0,0 +1,343 @@ +import 'package:extended_image/extended_image.dart'; +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/items/photos_model.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/providers/settings/photo_view_settings_provider.dart'; +import 'package:fladder/screens/shared/flat_button.dart'; +import 'package:fladder/screens/shared/input_fields.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/throttler.dart'; +import 'package:fladder/widgets/shared/elevated_icon.dart'; +import 'package:fladder/widgets/shared/progress_floating_button.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_cache_manager/flutter_cache_manager.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:share_plus/share_plus.dart'; +import 'package:square_progress_indicator/square_progress_indicator.dart'; +import 'package:wakelock_plus/wakelock_plus.dart'; +import 'package:window_manager/window_manager.dart'; + +class PhotoViewerControls extends ConsumerStatefulWidget { + final EdgeInsets padding; + final PhotoModel photo; + final int itemCount; + final bool loadingMoreItems; + final int currentIndex; + final ValueChanged onPhotoChanged; + final Function() openOptions; + final ExtendedPageController pageController; + final Function(bool? value)? toggleOverlay; + const PhotoViewerControls({ + required this.padding, + required this.photo, + required this.pageController, + required this.loadingMoreItems, + required this.openOptions, + required this.onPhotoChanged, + required this.itemCount, + required this.currentIndex, + this.toggleOverlay, + super.key, + }); + + @override + ConsumerState createState() => _PhotoViewerControllsState(); +} + +class _PhotoViewerControllsState extends ConsumerState with WindowListener { + final FocusNode focusNode = FocusNode(); + final Throttler throttler = Throttler(duration: const Duration(milliseconds: 130)); + late int currentPage = widget.pageController.page?.round() ?? 0; + double dragUpDelta = 0.0; + + final controller = TextEditingController(); + late final timerController = + RestarableTimerController(ref.read(photoViewSettingsProvider).timer, const Duration(milliseconds: 32), () { + if (widget.pageController.page == widget.itemCount - 1) { + widget.pageController.animateToPage(0, duration: const Duration(milliseconds: 250), curve: Curves.easeInOut); + } else { + widget.pageController.nextPage(duration: const Duration(milliseconds: 250), curve: Curves.easeInOut); + } + }); + + void _resetOnScroll() { + if (currentPage != widget.pageController.page?.round()) { + currentPage = widget.pageController.page?.round() ?? 0; + } + } + + @override + void initState() { + super.initState(); + Future.microtask(() => () { + if (AdaptiveLayout.of(context).isDesktop) focusNode.requestFocus(); + }); + + windowManager.addListener(this); + widget.pageController.addListener( + () { + _resetOnScroll(); + timerController.reset(); + }, + ); + } + + @override + void onWindowMinimize() { + timerController.cancel(); + super.onWindowMinimize(); + } + + @override + void dispose() { + timerController.dispose(); + windowManager.removeListener(this); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + if (AdaptiveLayout.of(context).isDesktop) focusNode.requestFocus(); + + final gradient = [ + Colors.black.withOpacity(0.6), + Colors.black.withOpacity(0.3), + Colors.black.withOpacity(0.1), + Colors.black.withOpacity(0.0), + ]; + + if (AdaptiveLayout.of(context).isDesktop) { + focusNode.requestFocus(); + } + + final padding = MediaQuery.of(context).padding; + return PopScope( + onPopInvoked: (popped) async { + await WakelockPlus.disable(); + }, + child: KeyboardListener( + focusNode: focusNode, + autofocus: true, + onKeyEvent: (value) { + if (value is KeyDownEvent) { + if (value.logicalKey == LogicalKeyboardKey.arrowLeft) { + throttler.run(() => widget.pageController + .previousPage(duration: const Duration(milliseconds: 125), curve: Curves.easeInOut)); + } + if (value.logicalKey == LogicalKeyboardKey.arrowRight) { + throttler.run(() => + widget.pageController.nextPage(duration: const Duration(milliseconds: 125), curve: Curves.easeInOut)); + } + if (value.logicalKey == LogicalKeyboardKey.keyK) { + timerController.playPause(); + } + if (value.logicalKey == LogicalKeyboardKey.space) { + widget.toggleOverlay?.call(null); + } + } + }, + child: Stack( + children: [ + Align( + alignment: Alignment.topCenter, + widthFactor: 1, + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: gradient, + ), + ), + child: Padding( + padding: EdgeInsets.only(top: widget.padding.top), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + if (AdaptiveLayout.of(context).isDesktop) const SizedBox(height: 25), + Padding( + padding: const EdgeInsets.symmetric(vertical: 12) + .add(EdgeInsets.only(left: padding.left, right: padding.right)), + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + ElevatedIconButton( + onPressed: () => Navigator.of(context).pop(widget.pageController.page?.toInt()), + icon: getBackIcon(context), + ), + const SizedBox(width: 8), + Expanded( + child: Tooltip( + message: widget.photo.name, + child: Text( + widget.photo.name, + maxLines: 2, + style: Theme.of(context) + .textTheme + .titleMedium + ?.copyWith(fontWeight: FontWeight.bold, shadows: [ + BoxShadow(blurRadius: 1, spreadRadius: 1, color: Colors.black.withOpacity(0.7)), + BoxShadow(blurRadius: 4, spreadRadius: 4, color: Colors.black.withOpacity(0.4)), + BoxShadow(blurRadius: 20, spreadRadius: 6, color: Colors.black.withOpacity(0.2)), + ]), + ), + ), + ), + const SizedBox(width: 8), + Stack( + children: [ + Positioned.fill( + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: Theme.of(context).colorScheme.onPrimary), + child: SquareProgressIndicator( + value: widget.currentIndex / (widget.itemCount - 1), + borderRadius: 7, + clockwise: false, + color: Theme.of(context).colorScheme.primary, + ), + ), + ), + Padding( + padding: const EdgeInsets.all(9), + child: Row( + children: [ + Text( + "${widget.currentIndex + 1} / ${widget.loadingMoreItems ? "-" : "${widget.itemCount}"} ", + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith(fontWeight: FontWeight.bold), + ), + if (widget.loadingMoreItems) + SizedBox.square( + dimension: 16, + child: CircularProgressIndicator.adaptive( + strokeCap: StrokeCap.round, + ), + ), + ].addInBetween(SizedBox(width: 6)), + ), + ), + Positioned.fill( + child: FlatButton( + borderRadiusGeometry: BorderRadius.circular(8), + onTap: () async { + showDialog( + context: context, + builder: (context) => Dialog( + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), + child: SizedBox( + width: 125, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.localized.goTo, + style: Theme.of(context) + .textTheme + .bodyLarge + ?.copyWith(fontWeight: FontWeight.bold), + ), + const SizedBox(height: 5), + IntInputField( + controller: TextEditingController( + text: (widget.currentIndex + 1).toString()), + onSubmitted: (value) { + final position = + ((value ?? 0) - 1).clamp(0, widget.itemCount - 1); + widget.pageController.jumpToPage(position); + Navigator.of(context).pop(); + }, + ), + ], + ), + ), + ), + ), + ); + }, + ), + ) + ], + ), + const SizedBox(width: 12), + ], + ), + ), + ], + ), + ), + ), + ), + Align( + alignment: Alignment.bottomCenter, + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: gradient.reversed.toList(), + ), + ), + width: double.infinity, + child: Padding( + padding: EdgeInsets.only(bottom: widget.padding.bottom), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: + const EdgeInsets.all(8.0).add(EdgeInsets.only(left: padding.left, right: padding.right)), + child: Row( + children: [ + ElevatedIconButton( + onPressed: widget.openOptions, + icon: IconsaxOutline.more_2, + ), + Spacer(), + ElevatedIconButton( + onPressed: markAsFavourite, + color: widget.photo.userData.isFavourite ? Colors.red : null, + icon: widget.photo.userData.isFavourite ? IconsaxBold.heart : IconsaxOutline.heart, + ), + ProgressFloatingButton( + controller: timerController, + ), + ].addPadding(const EdgeInsets.symmetric(horizontal: 8)), + ), + ) + ], + ), + ), + ), + ), + ], + ), + ), + ); + } + + void markAsFavourite() { + ref.read(userProvider.notifier).setAsFavorite(!widget.photo.userData.isFavourite, widget.photo.id); + + widget.onPhotoChanged(widget.photo + .copyWith(userData: widget.photo.userData.copyWith(isFavourite: !widget.photo.userData.isFavourite))); + } + + Future sharePhoto() async { + final file = await DefaultCacheManager().getSingleFile(widget.photo.downloadPath(ref)); + await Share.shareXFiles([ + XFile( + file.path, + ), + ]); + await file.delete(); + } +} diff --git a/lib/screens/photo_viewer/photo_viewer_screen.dart b/lib/screens/photo_viewer/photo_viewer_screen.dart new file mode 100644 index 0000000..937f45b --- /dev/null +++ b/lib/screens/photo_viewer/photo_viewer_screen.dart @@ -0,0 +1,526 @@ +import 'dart:async'; + +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:extended_image/extended_image.dart'; +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/main.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/photos_model.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/screens/photo_viewer/photo_viewer_controls.dart'; +import 'package:fladder/providers/settings/photo_view_settings_provider.dart'; +import 'package:fladder/screens/photo_viewer/simple_video_player.dart'; +import 'package:fladder/screens/shared/default_titlebar.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/item_base_model/item_base_model_extensions.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/themes_data.dart'; +import 'package:fladder/widgets/navigation_scaffold/components/fladder_appbar.dart'; +import 'package:fladder/widgets/shared/animated_icon.dart'; +import 'package:fladder/widgets/shared/elevated_icon.dart'; +import 'package:fladder/widgets/shared/hover_widget.dart'; +import 'package:fladder/widgets/shared/item_actions.dart'; +import 'package:fladder/widgets/shared/modal_bottom_sheet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_blurhash/flutter_blurhash.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class PhotoViewerScreen extends ConsumerStatefulWidget { + final List? items; + final int indexOfSelected; + final Future>? loadingItems; + const PhotoViewerScreen({ + this.items, + this.indexOfSelected = 0, + this.loadingItems, + super.key, + }); + + @override + ConsumerState createState() => _PhotoViewerScreenState(); +} + +class _PhotoViewerScreenState extends ConsumerState with WidgetsBindingObserver { + late List photos = widget.items ?? []; + late final ExtendedPageController controller = ExtendedPageController(initialPage: widget.indexOfSelected); + double currentScale = 1.0; + late int currentPage = widget.indexOfSelected.clamp(0, photos.length - 1); + bool showInterface = true; + bool toolbarHover = false; + + late final double topPadding = MediaQuery.of(context).viewPadding.top; + late final double bottomPadding = MediaQuery.of(context).viewPadding.bottom; + bool loadingItems = false; + + @override + void didChangeAppLifecycleState(AppLifecycleState state) async { + switch (state) { + case AppLifecycleState.resumed: + SystemChrome.setEnabledSystemUIMode(!showInterface ? SystemUiMode.leanBack : SystemUiMode.edgeToEdge, + overlays: []); + SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( + statusBarColor: Colors.transparent, + systemNavigationBarColor: Colors.transparent, + systemNavigationBarDividerColor: Colors.transparent, + )); + default: + break; + } + } + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addObserver(this); + WidgetsBinding.instance.addPostFrameCallback( + (timeStamp) async { + cacheNeighbors(widget.indexOfSelected, 2); + if (widget.loadingItems != null) { + setState(() { + loadingItems = true; + }); + + final newItems = await Future.value(widget.loadingItems); + + setState(() { + photos = {...photos, ...newItems}.toList(); + loadingItems = false; + }); + } + }, + ); + } + + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + + Future removePhoto(ItemBaseModel photo) async { + if (photos.length == 1) { + Navigator.of(context).pop(); + } else { + setState(() { + photos.remove(photo); + }); + } + } + + void _showOverlay({bool? show}) { + setState(() { + showInterface = show ?? !showInterface; + }); + SystemChrome.setEnabledSystemUIMode( + !showInterface ? SystemUiMode.leanBack : SystemUiMode.edgeToEdge, + overlays: [], + ); + SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( + statusBarColor: Colors.transparent, + systemNavigationBarColor: Colors.transparent, + systemNavigationBarDividerColor: Colors.transparent, + )); + } + + final gestureConfig = GestureConfig( + inertialSpeed: 300, + initialAlignment: InitialAlignment.center, + inPageView: true, + initialScale: 1.0, + maxScale: 6, + minScale: 1, + animationMinScale: 0.1, + animationMaxScale: 7, + cacheGesture: false, + reverseMousePointerScrollDirection: true, + hitTestBehavior: HitTestBehavior.translucent, + ); + + @override + Widget build(BuildContext context) { + return Theme( + data: ThemesData.of(context).dark, + child: PopScope( + onPopInvoked: (popped) async => SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge, overlays: []), + child: MouseRegion( + opaque: AdaptiveLayout.of(context).isDesktop, + onEnter: (event) => setState(() => _showOverlay(show: true)), + onExit: (event) => setState(() => _showOverlay(show: false)), + child: Scaffold( + appBar: photos.isEmpty + ? FladderAppbar( + automaticallyImplyLeading: true, + ) + : null, + body: photos.isEmpty + ? Center( + child: Text(context.localized.noItemsToShow), + ) + : buildViewer(), + ), + ), + ), + ); + } + + Widget buildViewer() { + final currentPhoto = photos[currentPage]; + final imageHash = currentPhoto.images?.primary?.hash; + return Stack( + children: [ + AnimatedSwitcher( + duration: const Duration(milliseconds: 250), + child: ref.watch(photoViewSettingsProvider.select((value) => value.theaterMode)) && imageHash != null + ? Opacity( + key: Key(currentPhoto.id), + opacity: 0.7, + child: SizedBox.expand( + child: Image( + fit: BoxFit.cover, + filterQuality: FilterQuality.high, + image: BlurHashImage(imageHash), + ), + ), + ) + : Container( + color: Colors.black, + ), + ), + GestureDetector( + onTapUp: (details) => _showOverlay(), + onDoubleTapDown: AdaptiveLayout.of(context).isDesktop + ? null + : (details) async { + await openOptions( + context, + currentPhoto, + removePhoto, + ); + }, + onLongPress: () { + if (currentPhoto.userData.isFavourite == true) { + HapticFeedback.lightImpact(); + } else { + markAsFavourite(currentPhoto, value: true); + HapticFeedback.heavyImpact(); + } + }, + child: ExtendedImageGesturePageView.builder( + itemCount: photos.length, + controller: controller, + onPageChanged: (index) => setState(() { + currentPage = index; + cacheNeighbors(index, 3); + SystemChrome.setEnabledSystemUIMode(!showInterface ? SystemUiMode.leanBack : SystemUiMode.edgeToEdge, + overlays: []); + }), + itemBuilder: (context, index) { + final photo = photos[index]; + return ExtendedImage( + key: Key(photo.id), + fit: BoxFit.contain, + mode: ExtendedImageMode.gesture, + initGestureConfigHandler: (state) => gestureConfig, + handleLoadingProgress: true, + onDoubleTap: (state) { + return; + }, + gaplessPlayback: true, + loadStateChanged: (state) { + return Stack( + alignment: Alignment.center, + fit: StackFit.expand, + children: [ + if (state.extendedImageLoadState != LoadState.completed) + Positioned.fill( + child: CachedNetworkImage( + fit: BoxFit.contain, + cacheManager: CustomCacheManager.instance, + imageUrl: photo.thumbnail?.primary?.path ?? "", + ), + ), + switch (state.extendedImageLoadState) { + LoadState.loading => Center( + child: CircularProgressIndicator.adaptive(strokeCap: StrokeCap.round), + ), + LoadState.completed => switch (photo.internalType) { + FladderItemType.video => SimpleVideoPlayer( + onTapped: _showOverlay, + showOverlay: showInterface, + video: photos[index], + ), + _ => state.completedWidget, + }, + LoadState.failed || _ => Align( + alignment: Alignment.topRight, + child: Padding( + padding: EdgeInsets.all(24).copyWith(top: topPadding + 85), + child: Card( + child: Padding( + padding: const EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.localized.failedToLoadImage, + style: Theme.of(context).textTheme.bodyLarge, + ), + const SizedBox(height: 6), + FilledButton.tonal( + onPressed: () => state.reLoadImage(), + child: Text(context.localized.retry), + ) + ], + ), + ), + ), + ), + ), + } + ], + ); + }, + image: CachedNetworkImageProvider( + photo.images?.primary?.path ?? "", + cacheManager: CustomCacheManager.instance, + ), + ); + }, + ), + ), + IgnorePointer( + ignoring: !showInterface, + child: AnimatedOpacity( + duration: const Duration(milliseconds: 500), + opacity: showInterface ? 1 : 0, + child: PhotoViewerControls( + padding: EdgeInsets.only(top: topPadding, bottom: bottomPadding), + currentIndex: currentPage, + itemCount: photos.length, + loadingMoreItems: loadingItems, + pageController: controller, + photo: currentPhoto, + toggleOverlay: (value) => setState(() => showInterface = value ?? !showInterface), + openOptions: () => openOptions(context, currentPhoto, removePhoto), + onPhotoChanged: (photo) { + setState(() { + int index = photos.indexOf(currentPhoto); + photos.remove(currentPhoto); + photos.insert(index, photo); + }); + }, + ), + ), + ), + if (AdaptiveLayout.of(context).isDesktop) ...{ + Align( + alignment: Alignment.centerRight, + child: HoverWidget( + child: (visible) => AnimatedOpacity( + duration: const Duration(milliseconds: 500), + opacity: visible ? 1 : 0, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Container( + alignment: Alignment.centerRight, + width: 50, + height: MediaQuery.sizeOf(context).height * 0.5, + child: IconButton.filledTonal( + style: + IconButton.styleFrom(shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8))), + onPressed: () => + controller.nextPage(duration: const Duration(milliseconds: 125), curve: Curves.easeInOut), + icon: const Icon(IconsaxBold.arrow_right_1), + ), + ), + ), + ), + ), + ), + Align( + alignment: Alignment.centerLeft, + child: HoverWidget( + child: (visible) => AnimatedOpacity( + duration: const Duration(milliseconds: 500), + opacity: visible ? 1 : 0, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Container( + alignment: Alignment.centerLeft, + width: 50, + height: MediaQuery.sizeOf(context).height * 0.5, + child: IconButton.filledTonal( + style: + IconButton.styleFrom(shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8))), + onPressed: () => + controller.previousPage(duration: const Duration(milliseconds: 125), curve: Curves.easeInOut), + icon: const Icon(IconsaxBold.arrow_left), + ), + ), + ), + ), + ), + ), + }, + if (AdaptiveLayout.of(context).isDesktop) + AnimatedOpacity( + duration: const Duration(milliseconds: 500), + opacity: showInterface + ? 1 + : toolbarHover + ? 1 + : 0, + child: Align( + alignment: Alignment.topCenter, + widthFactor: 1, + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Colors.black.withOpacity(0.5), + Colors.black.withOpacity(0), + ], + ), + ), + height: 45, + child: MouseRegion( + onEnter: (event) => setState(() => toolbarHover = true), + onExit: (event) => setState(() => toolbarHover = false), + child: const Column( + children: [ + DefaultTitleBar( + brightness: Brightness.dark, + ), + ], + ), + ), + ), + ), + ), + Align( + child: AnimatedOpacity( + duration: const Duration(milliseconds: 300), + opacity: showInterface ? 0 : 1, + child: AnimatedVisibilityIcon( + key: Key(currentPhoto.id), + isFilled: currentPhoto.userData.isFavourite, + filledIcon: IconsaxBold.heart, + outlinedIcon: IconsaxOutline.heart, + ), + ), + ) + ], + ); + } + + Future openOptions(BuildContext context, PhotoModel currentPhoto, Function(ItemBaseModel item) onRemove) => + showBottomSheetPill( + context: context, + content: (context, scrollController) { + return ListView( + shrinkWrap: true, + controller: scrollController, + children: [ + Padding( + padding: EdgeInsets.symmetric(horizontal: 12), + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Consumer(builder: (context, ref, child) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ElevatedIconButtonLabel( + label: context.localized.loop, + onPressed: () => ref + .read(photoViewSettingsProvider.notifier) + .update((state) => state.copyWith(repeat: !state.repeat)), + icon: ref.watch(photoViewSettingsProvider.select((value) => value.repeat)) + ? IconsaxOutline.repeat + : IconsaxOutline.repeate_one, + ), + ElevatedIconButtonLabel( + label: context.localized.audio, + onPressed: () => ref + .read(photoViewSettingsProvider.notifier) + .update((state) => state.copyWith(mute: !state.mute)), + icon: ref.watch(photoViewSettingsProvider.select((value) => value.mute)) + ? IconsaxOutline.volume_slash + : IconsaxOutline.volume_high, + ), + ElevatedIconButtonLabel( + label: context.localized.autoPlay, + onPressed: () => ref + .read(photoViewSettingsProvider.notifier) + .update((state) => state.copyWith(autoPlay: !state.autoPlay)), + icon: ref.watch(photoViewSettingsProvider.select((value) => value.autoPlay)) + ? IconsaxOutline.play_remove + : IconsaxOutline.play, + ), + ElevatedIconButtonLabel( + label: context.localized.backgroundBlur, + onPressed: () => ref + .read(photoViewSettingsProvider.notifier) + .update((state) => state.copyWith(theaterMode: !state.theaterMode)), + icon: ref.watch(photoViewSettingsProvider.select((value) => value.theaterMode)) + ? IconsaxOutline.filter_remove + : IconsaxOutline.filter, + ), + ].addInBetween(const SizedBox(width: 18)), + ); + }), + ), + ), + Divider(), + ...currentPhoto + .generateActions( + context, + ref, + exclude: { + ItemActions.details, + ItemActions.markPlayed, + ItemActions.markUnplayed, + }, + onDeleteSuccesFully: onRemove, + ) + .listTileItems(context, useIcons: true), + ], + ); + }, + ); + + void markAsFavourite(PhotoModel photo, {bool? value}) { + ref.read(userProvider.notifier).setAsFavorite(value ?? !photo.userData.isFavourite, photo.id); + + setState(() { + int index = photos.indexOf(photo); + photos.remove(photo); + photos.insert( + index, photo.copyWith(userData: photo.userData.copyWith(isFavourite: value ?? !photo.userData.isFavourite))); + }); + } + + void cacheNeighbors(int index, int range) { + photos + .getRange((index - range).clamp(0, photos.length - 1), (index + range).clamp(0, photos.length - 1)) + .forEach((element) { + precacheImage( + CachedNetworkImageProvider( + element.thumbnail?.primary?.path ?? "", + cacheManager: CustomCacheManager.instance, + ), + context); + if (AdaptiveLayout.of(context).isDesktop) { + precacheImage( + CachedNetworkImageProvider( + element.images?.primary?.path ?? "", + cacheManager: CustomCacheManager.instance, + ), + context); + } + }); + } +} diff --git a/lib/screens/photo_viewer/simple_video_player.dart b/lib/screens/photo_viewer/simple_video_player.dart new file mode 100644 index 0000000..406600c --- /dev/null +++ b/lib/screens/photo_viewer/simple_video_player.dart @@ -0,0 +1,261 @@ +import 'dart:async'; + +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/providers/settings/photo_view_settings_provider.dart'; +import 'package:fladder/util/fladder_image.dart'; +import 'package:fladder/widgets/shared/fladder_slider.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:media_kit/media_kit.dart'; +import 'package:media_kit_video/media_kit_video.dart'; + +import 'package:fladder/models/items/photos_model.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/util/duration_extensions.dart'; +import 'package:wakelock_plus/wakelock_plus.dart'; +import 'package:window_manager/window_manager.dart'; + +class SimpleVideoPlayer extends ConsumerStatefulWidget { + final PhotoModel video; + final bool showOverlay; + final VoidCallback onTapped; + const SimpleVideoPlayer({required this.video, required this.showOverlay, required this.onTapped, super.key}); + + @override + ConsumerState createState() => _SimpleVideoPlayerState(); +} + +class _SimpleVideoPlayerState extends ConsumerState with WindowListener, WidgetsBindingObserver { + final Player player = Player( + configuration: const PlayerConfiguration(libass: true), + ); + late VideoController controller = VideoController(player); + late String videoUrl = ""; + + bool playing = false; + bool wasPlaying = false; + Duration position = Duration.zero; + Duration lastPosition = Duration.zero; + Duration duration = Duration.zero; + + List subscriptions = []; + + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + switch (state) { + case AppLifecycleState.resumed: + if (playing) player.play(); + break; + case AppLifecycleState.hidden: + case AppLifecycleState.paused: + case AppLifecycleState.detached: + if (playing) player.pause(); + break; + default: + break; + } + } + + @override + void initState() { + super.initState(); + windowManager.addListener(this); + WidgetsBinding.instance.addObserver(this); + playing = player.state.playing; + position = player.state.position; + duration = player.state.duration; + Future.microtask(() async => {_init()}); + } + + @override + void onWindowMinimize() { + if (playing) player.pause(); + super.onWindowMinimize(); + } + + void _init() async { + final Map directOptions = { + 'Static': 'true', + 'mediaSourceId': widget.video.id, + 'api_key': ref.read(userProvider)?.credentials.token, + }; + + final params = Uri(queryParameters: directOptions).query; + + videoUrl = '${ref.read(userProvider)?.server ?? ""}/Videos/${widget.video.id}/stream?$params'; + + subscriptions.addAll( + [ + player.stream.playing.listen((event) { + setState(() { + playing = event; + }); + if (playing) { + WakelockPlus.enable(); + } else { + WakelockPlus.disable(); + } + }), + player.stream.position.listen((event) { + setState(() { + position = event; + }); + }), + player.stream.completed.listen((event) { + if (event) { + _restartVideo(); + } + }), + player.stream.duration.listen((event) { + setState(() { + duration = event; + }); + }), + ], + ); + await player.setVolume(ref.watch(photoViewSettingsProvider.select((value) => value.mute)) ? 0 : 100); + await player.open(Media(videoUrl), play: !ref.watch(photoViewSettingsProvider).autoPlay); + } + + void _restartVideo() { + if (ref.read(photoViewSettingsProvider.select((value) => value.repeat))) { + player.play(); + } + } + + @override + void dispose() { + Future.microtask(() async { + await player.dispose(); + }); + for (final s in subscriptions) { + s.cancel(); + } + WidgetsBinding.instance.removeObserver(this); + windowManager.removeListener(this); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final textStyle = Theme.of(context) + .textTheme + .titleMedium + ?.copyWith(fontWeight: FontWeight.bold, shadows: [const Shadow(blurRadius: 2)]); + ref.listen( + photoViewSettingsProvider.select((value) => value.mute), + (previous, next) { + if (previous != next) { + player.setVolume(next ? 0 : 100); + } + }, + ); + return GestureDetector( + onTap: widget.onTapped, + child: Stack( + alignment: Alignment.center, + children: [ + Positioned.fill( + child: FladderImage( + image: widget.video.thumbnail?.primary, + enableBlur: true, + fit: BoxFit.contain, + ), + ), + //Fixes small overlay problems with thumbnail + Transform.scale( + scaleY: 1.004, + child: Video( + fit: BoxFit.contain, + fill: const Color.fromARGB(0, 123, 62, 62), + controller: controller, + controls: NoVideoControls, + wakelock: false, + ), + ), + IgnorePointer( + ignoring: !widget.showOverlay, + child: AnimatedOpacity( + opacity: widget.showOverlay ? 1 : 0, + duration: const Duration(milliseconds: 250), + child: Stack( + fit: StackFit.expand, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12) + .add(EdgeInsets.only(bottom: 80 + MediaQuery.of(context).padding.bottom)), + child: Align( + alignment: Alignment.bottomCenter, + child: SizedBox( + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Flexible( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 40, + child: FladderSlider( + min: 0.0, + max: duration.inMilliseconds.toDouble(), + value: position.inMilliseconds.toDouble().clamp( + 0, + duration.inMilliseconds.toDouble(), + ), + onChangeEnd: (e) async { + await player.seek(Duration(milliseconds: e ~/ 1)); + if (wasPlaying) { + player.play(); + } + }, + onChangeStart: (value) { + wasPlaying = player.state.playing; + player.pause(); + }, + onChanged: (e) { + setState(() => position = Duration(milliseconds: e ~/ 1)); + }, + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Row( + children: [ + Text(position.readAbleDuration, style: textStyle), + const Spacer(), + Text((duration - position).readAbleDuration, style: textStyle), + ], + ), + ), + ], + ), + ), + const SizedBox(width: 16), + IconButton( + color: Theme.of(context).colorScheme.onSurface, + onPressed: () { + player.playOrPause(); + }, + icon: Icon( + player.state.playing ? IconsaxBold.pause_circle : IconsaxBold.play_circle, + shadows: [ + BoxShadow(blurRadius: 16, spreadRadius: 2, color: Colors.black.withOpacity(0.15)) + ], + ), + ) + ], + ), + ), + ), + ), + ], + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/screens/playlists/add_to_playlists.dart b/lib/screens/playlists/add_to_playlists.dart new file mode 100644 index 0000000..16bcd73 --- /dev/null +++ b/lib/screens/playlists/add_to_playlists.dart @@ -0,0 +1,159 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/providers/playlist_provider.dart'; +import 'package:fladder/screens/shared/adaptive_dialog.dart'; +import 'package:fladder/screens/shared/fladder_snackbar.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/widgets/shared/modal_bottom_sheet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/screens/shared/outlined_text_field.dart'; + +Future addItemToPlaylist(BuildContext context, List item) { + return showDialogAdaptive(context: context, builder: (context) => AddToPlaylist(items: item)); +} + +class AddToPlaylist extends ConsumerStatefulWidget { + final List items; + const AddToPlaylist({required this.items, super.key}); + + @override + ConsumerState createState() => _AddToPlaylistState(); +} + +class _AddToPlaylistState extends ConsumerState { + final TextEditingController controller = TextEditingController(); + late final provider = playlistProvider; + + @override + void initState() { + super.initState(); + Future.microtask(() => ref.read(provider.notifier).setItems(widget.items)); + } + + @override + Widget build(BuildContext context) { + final collectonOptions = ref.watch(provider); + return Card( + color: Theme.of(context).colorScheme.surface, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox(height: MediaQuery.paddingOf(context).top), + Container( + color: Theme.of(context).colorScheme.surface, + child: Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + if (widget.items.length == 1) + Text( + 'Add to collection', + style: Theme.of(context).textTheme.titleLarge, + ) + else + Text( + 'Add ${widget.items.length} item(s) to collection', + style: Theme.of(context).textTheme.titleLarge, + ), + IconButton( + onPressed: () => ref.read(provider.notifier).setItems(widget.items), + icon: const Icon(IconsaxOutline.refresh), + ) + ], + ), + ), + if (widget.items.length == 1) ItemBottomSheetPreview(item: widget.items.first), + ], + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: Row( + children: [ + Flexible( + child: OutlinedTextField( + label: 'New Playlist', + controller: controller, + onChanged: (value) => setState(() {}), + ), + ), + const SizedBox(width: 32), + IconButton( + onPressed: controller.text.isNotEmpty + ? () async { + final response = await ref.read(provider.notifier).addToNewPlaylist( + name: controller.text, + ); + if (context.mounted) { + fladderSnackbar(context, + title: response.isSuccessful + ? "Added to new ${controller.text} playlist" + : 'Unable to create new playlist - (${response.statusCode}) - ${response.base.reasonPhrase}'); + } + setState(() => controller.text = ''); + } + : null, + icon: const Icon(Icons.add_rounded)), + const SizedBox(width: 8), + ], + ), + ), + Flexible( + child: ListView( + shrinkWrap: true, + children: [ + ...collectonOptions.collections.entries.map( + (e) { + return ListTile( + title: Text(e.key.name), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton.filledTonal( + style: IconButton.styleFrom( + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8))), + onPressed: () async { + final response = await ref.read(provider.notifier).addToPlaylist(playlist: e.key); + if (context.mounted) { + fladderSnackbar(context, + title: response.isSuccessful + ? "Added to ${e.key.name} playlist" + : 'Unable to add to playlist - (${response.statusCode}) - ${response.base.reasonPhrase}'); + } + }, + icon: Icon(Icons.add_rounded, color: Theme.of(context).colorScheme.primary), + ), + ], + ), + ); + }, + ), + const SizedBox(height: 8), + ], + ), + ), + Container( + color: Theme.of(context).colorScheme.surface, + child: Padding( + padding: const EdgeInsets.all(16), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + FilledButton( + onPressed: () => Navigator.of(context).pop(), + child: Text(context.localized.close), + ) + ], + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/screens/search/search_screen.dart b/lib/screens/search/search_screen.dart new file mode 100644 index 0000000..beac561 --- /dev/null +++ b/lib/screens/search/search_screen.dart @@ -0,0 +1,89 @@ +import 'package:fladder/providers/search_provider.dart'; +import 'package:fladder/screens/shared/media/poster_grid.dart'; +import 'package:fladder/util/debouncer.dart'; +import 'package:fladder/util/string_extensions.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class SearchScreen extends ConsumerStatefulWidget { + const SearchScreen({super.key}); + + @override + ConsumerState createState() => _SearchScreenState(); +} + +class _SearchScreenState extends ConsumerState { + final TextEditingController _controller = TextEditingController(); + + final Debouncer searchDebouncer = Debouncer(const Duration(milliseconds: 500)); + + @override + void initState() { + super.initState(); + Future.microtask(() { + ref.read(searchProvider.notifier).clear(); + }); + } + + @override + Widget build(BuildContext context) { + final searchResults = ref.watch(searchProvider); + return Scaffold( + appBar: AppBar( + bottom: PreferredSize( + preferredSize: const Size.fromHeight(0), + child: Stack( + children: [ + Transform.translate( + offset: const Offset(0, 4), + child: Container( + height: 1, + color: Theme.of(context).colorScheme.outlineVariant, + ), + ), + Transform.translate( + offset: const Offset(0, -4), + child: AnimatedOpacity( + opacity: searchResults.loading ? 1 : 0, + duration: const Duration(milliseconds: 250), + child: Transform.translate( + offset: const Offset(0, 5), + child: const LinearProgressIndicator(), + ), + ), + ), + ], + ), + ), + title: TextField( + controller: _controller, + autofocus: true, + decoration: const InputDecoration( + hintText: "Search library...", + border: InputBorder.none, + ), + onSubmitted: (value) { + ref.read(searchProvider.notifier).searchQuery(); + }, + onChanged: (query) { + ref.read(searchProvider.notifier).setQuery(query); + searchDebouncer.run(() { + ref.read(searchProvider.notifier).searchQuery(); + }); + }, + ), + ), + body: ListView( + children: searchResults.results.entries + .map( + (e) => PosterGrid( + stickyHeader: false, + name: e.key.name.capitalize(), + posters: e.value, + ), + ) + .toList(), + ), + ); + } +} diff --git a/lib/screens/settings/client_settings_page.dart b/lib/screens/settings/client_settings_page.dart new file mode 100644 index 0000000..15f1f8e --- /dev/null +++ b/lib/screens/settings/client_settings_page.dart @@ -0,0 +1,476 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:file_picker/file_picker.dart'; +import 'package:fladder/models/settings/home_settings_model.dart'; +import 'package:fladder/providers/settings/client_settings_provider.dart'; +import 'package:fladder/providers/settings/home_settings_provider.dart'; +import 'package:fladder/providers/shared_provider.dart'; +import 'package:fladder/providers/sync_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/routes/build_routes/route_builder.dart'; +import 'package:fladder/screens/settings/settings_list_tile.dart'; +import 'package:fladder/screens/settings/settings_scaffold.dart'; +import 'package:fladder/screens/settings/widgets/settings_label_divider.dart'; +import 'package:fladder/screens/shared/default_alert_dialog.dart'; +import 'package:fladder/screens/shared/input_fields.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/custom_color_themes.dart'; +import 'package:fladder/util/local_extension.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/option_dialogue.dart'; +import 'package:fladder/util/simple_duration_picker.dart'; +import 'package:fladder/util/size_formatting.dart'; +import 'package:fladder/util/theme_mode_extension.dart'; +import 'package:fladder/widgets/shared/enum_selection.dart'; +import 'package:fladder/widgets/shared/fladder_slider.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +class ClientSettingsPage extends ConsumerStatefulWidget { + const ClientSettingsPage({super.key}); + + @override + ConsumerState createState() => _ClientSettingsPageState(); +} + +class _ClientSettingsPageState extends ConsumerState { + late final nextUpDaysEditor = TextEditingController( + text: ref.read(clientSettingsProvider.select((value) => value.nextUpDateCutoff?.inDays ?? 14)).toString()); + + late final libraryPageSizeController = TextEditingController( + text: ref.read(clientSettingsProvider.select((value) => value.libraryPageSize))?.toString() ?? ""); + + @override + Widget build(BuildContext context) { + final clientSettings = ref.watch(clientSettingsProvider); + final showBackground = AdaptiveLayout.of(context).layout != LayoutState.phone && + AdaptiveLayout.of(context).size != ScreenLayout.single; + final currentFolder = ref.watch(syncProvider.notifier).savePath; + Locale currentLocale = WidgetsBinding.instance.platformDispatcher.locale; + + final canSync = ref.watch(userProvider.select((value) => value?.canDownload ?? false)); + return Card( + elevation: showBackground ? 2 : 0, + child: SettingsScaffold( + label: "Fladder", + items: [ + if (canSync && !kIsWeb) ...[ + SettingsLabelDivider(label: context.localized.downloadsTitle), + if (AdaptiveLayout.of(context).isDesktop) ...[ + SettingsListTile( + label: Text(context.localized.downloadsPath), + subLabel: Text(currentFolder ?? "-"), + onTap: currentFolder != null + ? () async => await showDialog( + context: context, + builder: (context) => AlertDialog.adaptive( + title: Text(context.localized.pathEditTitle), + content: Text(context.localized.pathEditDesc), + actions: [ + ElevatedButton( + onPressed: () async { + String? selectedDirectory = await FilePicker.platform.getDirectoryPath( + dialogTitle: context.localized.pathEditSelect, initialDirectory: currentFolder); + if (selectedDirectory != null) { + ref.read(clientSettingsProvider.notifier).setSyncPath(selectedDirectory); + } + Navigator.of(context).pop(); + }, + child: Text(context.localized.change), + ) + ], + ), + ) + : () async { + String? selectedDirectory = await FilePicker.platform.getDirectoryPath( + dialogTitle: context.localized.pathEditSelect, initialDirectory: currentFolder); + if (selectedDirectory != null) { + ref.read(clientSettingsProvider.notifier).setSyncPath(selectedDirectory); + } + }, + trailing: currentFolder?.isNotEmpty == true + ? IconButton( + color: Theme.of(context).colorScheme.error, + onPressed: () async => await showDialog( + context: context, + builder: (context) => AlertDialog.adaptive( + title: Text(context.localized.pathClearTitle), + content: Text(context.localized.pathEditDesc), + actions: [ + ElevatedButton( + onPressed: () { + ref.read(clientSettingsProvider.notifier).setSyncPath(null); + Navigator.of(context).pop(); + }, + child: Text(context.localized.clear), + ) + ], + ), + ), + icon: Icon(IconsaxOutline.folder_minus), + ) + : null, + ), + ], + FutureBuilder( + future: ref.watch(syncProvider.notifier).directorySize, + builder: (context, snapshot) { + final data = snapshot.data ?? 0; + return SettingsListTile( + label: Text(context.localized.downloadsSyncedData), + subLabel: Text(data.byteFormat ?? ""), + trailing: FilledButton( + onPressed: () { + showDefaultAlertDialog( + context, + context.localized.downloadsClearTitle, + context.localized.downloadsClearDesc, + (context) async { + await ref.read(syncProvider.notifier).clear(); + setState(() {}); + context.pop(); + }, + context.localized.clear, + (context) => context.pop(), + context.localized.cancel, + ); + }, + child: Text(context.localized.clear), + ), + ); + }, + ), + const Divider(), + ], + SettingsLabelDivider(label: context.localized.lockscreen), + SettingsListTile( + label: Text(context.localized.timeOut), + subLabel: Text(timePickerString(context, clientSettings.timeOut)), + onTap: () async { + final timePicker = await showSimpleDurationPicker( + context: context, + initialValue: clientSettings.timeOut ?? const Duration(), + ); + + ref.read(clientSettingsProvider.notifier).setTimeOut(timePicker != null + ? Duration(minutes: timePicker.inMinutes, seconds: timePicker.inSeconds % 60) + : null); + }, + ), + const Divider(), + SettingsLabelDivider(label: context.localized.dashboard), + SettingsListTile( + label: Text(context.localized.settingsHomeCarouselTitle), + subLabel: Text(context.localized.settingsHomeCarouselDesc), + trailing: EnumBox( + current: ref.watch( + homeSettingsProvider.select( + (value) => value.carouselSettings.label(context), + ), + ), + itemBuilder: (context) => HomeCarouselSettings.values + .map( + (entry) => PopupMenuItem( + value: entry, + child: Text(entry.label(context)), + onTap: () => ref + .read(homeSettingsProvider.notifier) + .update((context) => context.copyWith(carouselSettings: entry)), + ), + ) + .toList(), + ), + ), + SettingsListTile( + label: Text(context.localized.settingsHomeNextUpTitle), + subLabel: Text(context.localized.settingsHomeNextUpDesc), + trailing: EnumBox( + current: ref.watch( + homeSettingsProvider.select( + (value) => value.nextUp.label(context), + ), + ), + itemBuilder: (context) => HomeNextUp.values + .map( + (entry) => PopupMenuItem( + value: entry, + child: Text(entry.label(context)), + onTap: () => + ref.read(homeSettingsProvider.notifier).update((context) => context.copyWith(nextUp: entry)), + ), + ) + .toList(), + ), + ), + const Divider(), + SettingsLabelDivider(label: context.localized.settingsVisual), + SettingsListTile( + label: Text(context.localized.displayLanguage), + trailing: EnumBox( + current: ref.watch( + clientSettingsProvider.select( + (value) => (value.selectedLocale ?? currentLocale).label(), + ), + ), + itemBuilder: (context) { + return [ + ...AppLocalizations.supportedLocales.map( + (entry) => PopupMenuItem( + value: entry, + child: Text( + entry.label(), + style: TextStyle( + fontWeight: currentLocale.languageCode == entry.languageCode ? FontWeight.bold : null, + ), + ), + onTap: () => ref + .read(clientSettingsProvider.notifier) + .update((state) => state.copyWith(selectedLocale: entry)), + ), + ) + ]; + }, + ), + ), + SettingsListTile( + label: Text(context.localized.settingsBlurredPlaceholderTitle), + subLabel: Text(context.localized.settingsBlurredPlaceholderDesc), + onTap: () => + ref.read(clientSettingsProvider.notifier).setBlurPlaceholders(!clientSettings.blurPlaceHolders), + trailing: Switch( + value: clientSettings.blurPlaceHolders, + onChanged: (value) => ref.read(clientSettingsProvider.notifier).setBlurPlaceholders(value), + ), + ), + SettingsListTile( + label: Text(context.localized.settingsBlurEpisodesTitle), + subLabel: Text(context.localized.settingsBlurEpisodesDesc), + onTap: () => + ref.read(clientSettingsProvider.notifier).setBlurEpisodes(!clientSettings.blurUpcomingEpisodes), + trailing: Switch( + value: clientSettings.blurUpcomingEpisodes, + onChanged: (value) => ref.read(clientSettingsProvider.notifier).setBlurEpisodes(value), + ), + ), + SettingsListTile( + label: Text(context.localized.settingsEnableOsMediaControls), + onTap: () => ref.read(clientSettingsProvider.notifier).setMediaKeys(!clientSettings.enableMediaKeys), + trailing: Switch( + value: clientSettings.enableMediaKeys, + onChanged: (value) => ref.read(clientSettingsProvider.notifier).setMediaKeys(value), + ), + ), + SettingsListTile( + label: Text(context.localized.settingsNextUpCutoffDays), + trailing: SizedBox( + width: 100, + child: IntInputField( + suffix: context.localized.days, + controller: nextUpDaysEditor, + onSubmitted: (value) { + if (value != null) { + ref.read(clientSettingsProvider.notifier).update((current) => current.copyWith( + nextUpDateCutoff: Duration(days: value), + )); + } + }, + )), + ), + SettingsListTile( + label: Text(context.localized.libraryPageSizeTitle), + subLabel: Text(context.localized.libraryPageSizeDesc), + trailing: SizedBox( + width: 100, + child: IntInputField( + controller: libraryPageSizeController, + placeHolder: "500", + onSubmitted: (value) => ref.read(clientSettingsProvider.notifier).update( + (current) => current.copyWith(libraryPageSize: value), + ), + )), + ), + SettingsListTile( + label: Text(AdaptiveLayout.of(context).isDesktop + ? context.localized.settingsShowScaleSlider + : context.localized.settingsPosterPinch), + onTap: () => ref.read(clientSettingsProvider.notifier).update( + (current) => current.copyWith(pinchPosterZoom: !current.pinchPosterZoom), + ), + trailing: Switch( + value: clientSettings.pinchPosterZoom, + onChanged: (value) => ref.read(clientSettingsProvider.notifier).update( + (current) => current.copyWith(pinchPosterZoom: value), + ), + ), + ), + Column( + children: [ + SettingsListTile( + label: Text(context.localized.settingsPosterSize), + trailing: Text( + clientSettings.posterSize.toString(), + style: Theme.of(context).textTheme.bodyLarge, + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: FladderSlider( + min: 0.5, + max: 1.5, + value: clientSettings.posterSize, + divisions: 20, + onChanged: (value) => ref + .read(clientSettingsProvider.notifier) + .update((current) => current.copyWith(posterSize: value)), + ), + ), + const Divider(), + ], + ), + SettingsLabelDivider(label: context.localized.theme), + SettingsListTile( + label: Text(context.localized.mode), + subLabel: Text(clientSettings.themeMode.label(context)), + onTap: () => openOptionDialogue( + context, + label: "${context.localized.theme} ${context.localized.mode}", + items: ThemeMode.values, + itemBuilder: (type) => RadioListTile( + value: type, + title: Text(type?.label(context) ?? context.localized.other), + contentPadding: EdgeInsets.zero, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), + groupValue: ref.read(clientSettingsProvider.select((value) => value.themeMode)), + onChanged: (value) => ref.read(clientSettingsProvider.notifier).setThemeMode(value), + ), + ), + ), + SettingsListTile( + label: Text(context.localized.color), + subLabel: Text(clientSettings.themeColor?.name ?? context.localized.dynamicText), + onTap: () => openOptionDialogue( + context, + isNullable: !kIsWeb, + label: context.localized.themeColor, + items: ColorThemes.values, + itemBuilder: (type) => Consumer( + builder: (context, ref, child) => ListTile( + title: Row( + children: [ + Checkbox( + value: type == ref.watch(clientSettingsProvider.select((value) => value.themeColor)), + onChanged: (value) => ref.read(clientSettingsProvider.notifier).setThemeColor(type), + ), + const SizedBox(width: 4), + Container( + height: 24, + width: 24, + decoration: BoxDecoration( + gradient: type == null + ? const SweepGradient( + center: FractionalOffset.center, + colors: [ + Color(0xFF4285F4), // blue + Color(0xFF34A853), // green + Color(0xFFFBBC05), // yellow + Color(0xFFEA4335), // red + Color(0xFF4285F4), // blue again to seamlessly transition to the start + ], + stops: [0.0, 0.25, 0.5, 0.75, 1.0], + ) + : null, + color: type?.color, + borderRadius: BorderRadius.circular(4), + ), + ), + const SizedBox(width: 8), + Text(type?.name ?? context.localized.dynamicText), + ], + ), + contentPadding: EdgeInsets.zero, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), + onTap: () => ref.read(clientSettingsProvider.notifier).setThemeColor(type), + ), + ), + ), + ), + SettingsListTile( + label: Text(context.localized.amoledBlack), + subLabel: Text(clientSettings.amoledBlack ? context.localized.enabled : context.localized.disabled), + onTap: () => ref.read(clientSettingsProvider.notifier).setAmoledBlack(!clientSettings.amoledBlack), + trailing: Switch( + value: clientSettings.amoledBlack, + onChanged: (value) => ref.read(clientSettingsProvider.notifier).setAmoledBlack(value), + ), + ), + if (AdaptiveLayout.of(context).isDesktop) ...[ + const Divider(), + SettingsLabelDivider(label: context.localized.controls), + SettingsListTile( + label: Text(context.localized.mouseDragSupport), + subLabel: Text(clientSettings.mouseDragSupport ? context.localized.enabled : context.localized.disabled), + onTap: () => ref + .read(clientSettingsProvider.notifier) + .update((current) => current.copyWith(mouseDragSupport: !clientSettings.mouseDragSupport)), + trailing: Switch( + value: clientSettings.mouseDragSupport, + onChanged: (value) => ref.read(clientSettingsProvider.notifier).setAmoledBlack(value), + ), + ), + ], + const SizedBox(height: 64), + SettingsListTile( + label: Text( + context.localized.clearAllSettings, + ), + contentColor: Theme.of(context).colorScheme.error, + onTap: () { + showDialog( + context: context, + builder: (context) => Dialog( + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.localized.clearAllSettingsQuestion, + style: Theme.of(context).textTheme.titleLarge, + ), + const SizedBox(height: 16), + Text( + context.localized.unableToReverseAction, + ), + const SizedBox(height: 16), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + FilledButton( + onPressed: () => context.pop(), + child: Text(context.localized.cancel), + ), + const SizedBox(width: 8), + ElevatedButton( + onPressed: () async { + await ref.read(sharedPreferencesProvider).clear(); + context.routeGo(LoginRoute()); + }, + child: Text(context.localized.clear), + ) + ], + ), + ], + ), + ), + ), + ); + }, + ), + const SizedBox(height: 16), + ], + ), + ); + } +} diff --git a/lib/screens/settings/player_settings_page.dart b/lib/screens/settings/player_settings_page.dart new file mode 100644 index 0000000..def9a5c --- /dev/null +++ b/lib/screens/settings/player_settings_page.dart @@ -0,0 +1,123 @@ +import 'package:fladder/providers/settings/video_player_settings_provider.dart'; +import 'package:fladder/screens/settings/settings_list_tile.dart'; +import 'package:fladder/screens/settings/settings_scaffold.dart'; +import 'package:fladder/screens/settings/widgets/settings_label_divider.dart'; +import 'package:fladder/screens/settings/widgets/settings_message_box.dart'; +import 'package:fladder/screens/settings/widgets/subtitle_editor.dart'; +import 'package:fladder/screens/shared/animated_fade_size.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/box_fit_extension.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/option_dialogue.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'dart:io' show Platform; + +class PlayerSettingsPage extends ConsumerStatefulWidget { + const PlayerSettingsPage({super.key}); + + @override + ConsumerState createState() => _PlayerSettingsPageState(); +} + +class _PlayerSettingsPageState extends ConsumerState { + @override + Widget build(BuildContext context) { + final videoSettings = ref.watch(videoPlayerSettingsProvider); + final provider = ref.read(videoPlayerSettingsProvider.notifier); + final showBackground = AdaptiveLayout.of(context).layout != LayoutState.phone && + AdaptiveLayout.of(context).size != ScreenLayout.single; + return Card( + elevation: showBackground ? 2 : 0, + child: SettingsScaffold( + label: context.localized.settingsPlayerTitle, + items: [ + SettingsLabelDivider(label: context.localized.video), + if (!AdaptiveLayout.of(context).isDesktop && !kIsWeb) + SettingsListTile( + label: Text(context.localized.videoScalingFillScreenTitle), + subLabel: Text(context.localized.videoScalingFillScreenDesc), + onTap: () => provider.setFillScreen(!videoSettings.fillScreen), + trailing: Switch( + value: videoSettings.fillScreen, + onChanged: (value) => provider.setFillScreen(value), + ), + ), + AnimatedFadeSize( + child: videoSettings.fillScreen + ? SettingsMessageBox( + context.localized.videoScalingFillScreenNotif, + messageType: MessageType.warning, + ) + : Container(), + ), + SettingsListTile( + label: Text(context.localized.videoScalingFillScreenTitle), + subLabel: Text(videoSettings.videoFit.label(context)), + onTap: () => openOptionDialogue( + context, + label: context.localized.videoScalingFillScreenTitle, + items: BoxFit.values, + itemBuilder: (type) => RadioListTile.adaptive( + title: Text(type?.label(context) ?? ""), + value: type, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), + contentPadding: EdgeInsets.zero, + groupValue: ref.read(videoPlayerSettingsProvider.select((value) => value.videoFit)), + onChanged: (value) { + provider.setFitType(value); + Navigator.pop(context); + }, + ), + ), + ), + const Divider(), + SettingsLabelDivider(label: context.localized.advanced), + SettingsListTile( + label: Text(context.localized.settingsPlayerVideoHWAccelTitle), + subLabel: Text(context.localized.settingsPlayerVideoHWAccelDesc), + onTap: () => provider.setHardwareAccel(!videoSettings.hardwareAccel), + trailing: Switch( + value: videoSettings.hardwareAccel, + onChanged: (value) => provider.setHardwareAccel(value), + ), + ), + if (!kIsWeb) ...[ + SettingsListTile( + label: Text(context.localized.settingsPlayerNativeLibassAccelTitle), + subLabel: Text(context.localized.settingsPlayerNativeLibassAccelDesc), + onTap: () => provider.setUseLibass(!videoSettings.useLibass), + trailing: Switch( + value: videoSettings.useLibass, + onChanged: (value) => provider.setUseLibass(value), + ), + ), + AnimatedFadeSize( + child: videoSettings.useLibass && videoSettings.hardwareAccel && Platform.isAndroid + ? SettingsMessageBox( + context.localized.settingsPlayerMobileWarning, + messageType: MessageType.warning, + ) + : Container(), + ), + ], + SettingsListTile( + label: Text(context.localized.settingsPlayerCustomSubtitlesTitle), + subLabel: Text(context.localized.settingsPlayerCustomSubtitlesDesc), + onTap: videoSettings.useLibass + ? null + : () { + showDialog( + context: context, + barrierDismissible: false, + useSafeArea: false, + builder: (context) => const SubtitleEditor(), + ); + }, + ), + ], + ), + ); + } +} diff --git a/lib/screens/settings/quick_connect_window.dart b/lib/screens/settings/quick_connect_window.dart new file mode 100644 index 0000000..e2a196b --- /dev/null +++ b/lib/screens/settings/quick_connect_window.dart @@ -0,0 +1,119 @@ +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/screens/login/widgets/login_icon.dart'; +import 'package:fladder/screens/shared/outlined_text_field.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +Future openQuickConnectDialog( + BuildContext context, +) async { + return showDialog(context: context, builder: (context) => QuickConnectDialog()); +} + +class QuickConnectDialog extends ConsumerStatefulWidget { + const QuickConnectDialog({super.key}); + + @override + ConsumerState createState() => _QuickConnectDialogState(); +} + +class _QuickConnectDialogState extends ConsumerState { + final controller = TextEditingController(); + bool loading = false; + String? error; + String? success; + + @override + Widget build(BuildContext context) { + final user = ref.watch(userProvider); + return AlertDialog.adaptive( + title: Text(context.localized.quickConnectTitle), + scrollable: true, + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text(context.localized.quickConnectAction), + if (user != null) SizedBox(child: LoginIcon(user: user)), + Flexible( + child: OutlinedTextField( + label: context.localized.code, + controller: controller, + keyboardType: TextInputType.number, + onChanged: (value) { + if (value.isNotEmpty) { + setState(() { + error = null; + success = null; + }); + } + }, + inputFormatters: [FilteringTextInputFormatter.digitsOnly], + ), + ), + AnimatedContainer( + duration: const Duration(milliseconds: 250), + child: error != null || success != null + ? Card( + key: Key(context.localized.error), + color: success == null + ? Theme.of(context).colorScheme.errorContainer + : Theme.of(context).colorScheme.surfaceContainer, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + success ?? error ?? "", + style: TextStyle( + color: success == null + ? Theme.of(context).colorScheme.onErrorContainer + : Theme.of(context).colorScheme.onSurface), + ), + ), + ) + : null, + ), + ElevatedButton( + onPressed: loading + ? null + : () async { + setState(() { + error = null; + loading = true; + }); + final response = await ref.read(userProvider.notifier).quickConnect(controller.text); + if (response.isSuccessful) { + setState( + () { + error = null; + success = context.localized.loggedIn; + }, + ); + await Future.delayed(Duration(seconds: 2)); + Navigator.of(context).pop(); + } else { + if (controller.text.isEmpty) { + error = context.localized.quickConnectInputACode; + } else { + error = context.localized.quickConnectWrongCode; + } + } + loading = false; + setState( + () {}, + ); + controller.text = ""; + }, + child: loading + ? SizedBox.square( + child: CircularProgressIndicator(), + dimension: 16.0, + ) + : Text(context.localized.login), + ) + ].addInBetween(const SizedBox(height: 16)), + ), + ); + } +} diff --git a/lib/screens/settings/security_settings_page.dart b/lib/screens/settings/security_settings_page.dart new file mode 100644 index 0000000..99602c2 --- /dev/null +++ b/lib/screens/settings/security_settings_page.dart @@ -0,0 +1,41 @@ +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/screens/settings/settings_list_tile.dart'; +import 'package:fladder/screens/settings/settings_scaffold.dart'; +import 'package:fladder/screens/settings/widgets/settings_label_divider.dart'; +import 'package:fladder/screens/shared/authenticate_button_options.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class SecuritySettingsPage extends ConsumerStatefulWidget { + const SecuritySettingsPage({super.key}); + + @override + ConsumerState createState() => _UserSettingsPageState(); +} + +class _UserSettingsPageState extends ConsumerState { + @override + Widget build(BuildContext context) { + final user = ref.watch(userProvider); + final showBackground = AdaptiveLayout.of(context).layout != LayoutState.phone && + AdaptiveLayout.of(context).size != ScreenLayout.single; + return Card( + elevation: showBackground ? 2 : 0, + child: SettingsScaffold( + label: context.localized.settingsProfileTitle, + items: [ + SettingsLabelDivider(label: context.localized.settingSecurityApplockTitle), + SettingsListTile( + label: Text(context.localized.settingSecurityApplockTitle), + subLabel: Text(user?.authMethod.name(context) ?? ""), + onTap: () => showAuthOptionsDialogue(context, user!, (newUser) { + ref.read(userProvider.notifier).updateUser(newUser); + }), + ), + ], + ), + ); + } +} diff --git a/lib/screens/settings/settings_list_tile.dart b/lib/screens/settings/settings_list_tile.dart new file mode 100644 index 0000000..b7e853c --- /dev/null +++ b/lib/screens/settings/settings_list_tile.dart @@ -0,0 +1,72 @@ +import 'package:flutter/material.dart'; + +class SettingsListTile extends StatelessWidget { + final Widget label; + final Widget? subLabel; + final Widget? trailing; + final bool selected; + final IconData? icon; + final Widget? suffix; + final Color? contentColor; + final Function()? onTap; + const SettingsListTile({ + required this.label, + this.subLabel, + this.trailing, + this.selected = false, + this.suffix, + this.icon, + this.contentColor, + this.onTap, + super.key, + }); + + @override + Widget build(BuildContext context) { + final iconWidget = icon != null ? Icon(icon) : null; + return Card( + elevation: selected ? 2 : 0, + color: selected ? null : Colors.transparent, + shadowColor: Colors.transparent, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only(topLeft: Radius.circular(8), bottomLeft: Radius.circular(8))), + margin: EdgeInsets.zero, + child: ListTile( + minVerticalPadding: 12, + minLeadingWidth: 16, + minTileHeight: 75, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), + horizontalTitleGap: 0, + titleAlignment: ListTileTitleAlignment.center, + contentPadding: const EdgeInsets.only(right: 12), + leading: (suffix ?? iconWidget) != null + ? Padding( + padding: const EdgeInsets.only(left: 8.0, right: 16.0), + child: AnimatedContainer( + duration: const Duration(milliseconds: 125), + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.primaryContainer.withOpacity(selected ? 1 : 0), + borderRadius: BorderRadius.circular(selected ? 5 : 20), + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 12), + child: (suffix ?? iconWidget), + ), + ), + ) + : suffix ?? const SizedBox(), + title: label, + titleTextStyle: Theme.of(context).textTheme.titleLarge, + trailing: Padding( + padding: const EdgeInsets.only(left: 16), + child: trailing, + ), + selected: selected, + textColor: contentColor, + iconColor: contentColor, + subtitle: subLabel, + onTap: onTap, + ), + ); + } +} diff --git a/lib/screens/settings/settings_scaffold.dart b/lib/screens/settings/settings_scaffold.dart new file mode 100644 index 0000000..6e7fb3c --- /dev/null +++ b/lib/screens/settings/settings_scaffold.dart @@ -0,0 +1,95 @@ +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/screens/shared/user_icon.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class SettingsScaffold extends ConsumerWidget { + final String label; + final bool showUserIcon; + final ScrollController? scrollController; + final List items; + final List bottomActions; + final Widget? floatingActionButton; + const SettingsScaffold({ + required this.label, + this.showUserIcon = false, + this.scrollController, + required this.items, + this.bottomActions = const [], + this.floatingActionButton, + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final padding = MediaQuery.of(context).padding; + return Scaffold( + backgroundColor: AdaptiveLayout.of(context).isDesktop ? Colors.transparent : null, + floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, + floatingActionButton: floatingActionButton, + body: Column( + children: [ + Flexible( + child: CustomScrollView( + controller: scrollController, + slivers: [ + if (AdaptiveLayout.of(context).size == ScreenLayout.single) + SliverAppBar.large( + titleSpacing: 20, + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + flexibleSpace: FlexibleSpaceBar( + titlePadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16) + .add(EdgeInsets.only(left: padding.left, right: padding.right)), + title: Row( + children: [ + Text(label, style: Theme.of(context).textTheme.headlineSmall), + const Spacer(), + if (showUserIcon) + SizedBox.fromSize( + size: const Size.fromRadius(14), + child: UserIcon( + user: ref.watch(userProvider), + cornerRadius: 200, + )) + ], + ), + expandedTitleScale: 2, + ), + expandedHeight: 175, + collapsedHeight: 100, + pinned: false, + floating: true, + ) + else + SliverToBoxAdapter( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 32), + child: Text(AdaptiveLayout.of(context).size == ScreenLayout.single ? label : "", + style: Theme.of(context).textTheme.headlineLarge), + ), + ), + SliverList( + delegate: SliverChildListDelegate(items), + ), + if (bottomActions.isEmpty) + const SliverToBoxAdapter(child: SizedBox(height: kBottomNavigationBarHeight + 40)), + ], + ), + ), + if (bottomActions.isNotEmpty) ...{ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 32) + .add(EdgeInsets.only(left: padding.left, right: padding.right)), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: bottomActions, + ), + ), + const SizedBox(height: kBottomNavigationBarHeight + 40), + }, + ], + ), + ); + } +} diff --git a/lib/screens/settings/settings_screen.dart b/lib/screens/settings/settings_screen.dart new file mode 100644 index 0000000..387a22b --- /dev/null +++ b/lib/screens/settings/settings_screen.dart @@ -0,0 +1,223 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/routes/build_routes/route_builder.dart'; +import 'package:fladder/routes/build_routes/settings_routes.dart'; +import 'package:fladder/screens/settings/quick_connect_window.dart'; +import 'package:fladder/screens/settings/settings_list_tile.dart'; +import 'package:fladder/screens/settings/settings_scaffold.dart'; +import 'package:fladder/screens/shared/animated_fade_size.dart'; +import 'package:fladder/screens/shared/fladder_icon.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/theme_extensions.dart'; +import 'package:fladder/widgets/shared/hide_on_scroll.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/providers/auth_provider.dart'; +import 'package:fladder/util/application_info.dart'; +import 'package:go_router/go_router.dart'; + +class SettingsScreen extends ConsumerStatefulWidget { + final Widget? child; + final String? location; + const SettingsScreen({this.child, this.location, super.key}); + + @override + ConsumerState createState() => _SettingsScreenState(); +} + +class _SettingsScreenState extends ConsumerState { + final scrollController = ScrollController(); + late final singlePane = widget.child == null; + final minVerticalPadding = 20.0; + + @override + Widget build(BuildContext context) { + if (singlePane) { + return Card( + elevation: 0, + child: _leftPane(context), + ); + } else { + return Row( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded(flex: 1, child: _leftPane(context)), + Expanded( + flex: 2, + child: widget.child ?? Container(), + ), + ], + ); + } + } + + IconData get deviceIcon { + if (AdaptiveLayout.of(context).isDesktop) { + return IconsaxOutline.monitor; + } + switch (AdaptiveLayout.of(context).layout) { + case LayoutState.phone: + return IconsaxOutline.mobile; + case LayoutState.tablet: + return IconsaxOutline.monitor; + case LayoutState.desktop: + return IconsaxOutline.monitor; + } + } + + bool containsRoute(CustomRoute route) => widget.location == route.route; + + Widget _leftPane(BuildContext context) { + final quickConnectAvailable = + ref.watch(userProvider.select((value) => value?.serverConfiguration?.quickConnectAvailable ?? false)); + return SettingsScaffold( + label: context.localized.settings, + scrollController: scrollController, + showUserIcon: true, + items: [ + if (context.canPop() && AdaptiveLayout.of(context).isDesktop) + Align( + alignment: Alignment.centerLeft, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: IconButton.filledTonal( + style: IconButton.styleFrom( + backgroundColor: Theme.of(context).colorScheme.surface.withOpacity(0.8), + ), + onPressed: () { + context.pop(); + }, + icon: Padding( + padding: EdgeInsets.all(AdaptiveLayout.of(context).inputDevice == InputDevice.pointer ? 0 : 4), + child: Icon(IconsaxOutline.arrow_left_2), + ), + ), + ), + ), + SettingsListTile( + label: Text(context.localized.settingsClientTitle), + subLabel: Text(context.localized.settingsClientDesc), + selected: containsRoute(ClientSettingsRoute()), + icon: deviceIcon, + onTap: () => context.routeReplaceOrPush(ClientSettingsRoute()), + ), + if (quickConnectAvailable) + SettingsListTile( + label: Text(context.localized.settingsQuickConnectTitle), + icon: IconsaxOutline.password_check, + onTap: () => openQuickConnectDialog(context), + ), + SettingsListTile( + label: Text(context.localized.settingsProfileTitle), + subLabel: Text(context.localized.settingsProfileDesc), + selected: containsRoute(SecuritySettingsRoute()), + icon: IconsaxOutline.security_user, + onTap: () => context.routeReplaceOrPush(SecuritySettingsRoute()), + ), + SettingsListTile( + label: Text(context.localized.settingsPlayerTitle), + subLabel: Text(context.localized.settingsPlayerDesc), + selected: containsRoute(PlayerSettingsRoute()), + icon: IconsaxOutline.video_play, + onTap: () => context.routeReplaceOrPush(PlayerSettingsRoute()), + ), + SettingsListTile( + label: Text(context.localized.about), + subLabel: Text("Fladder"), + suffix: Opacity( + opacity: 1, + child: FladderIconOutlined( + size: 24, + color: context.colors.onSurfaceVariant, + )), + onTap: () => showAboutDialog( + context: context, + applicationIcon: FladderIcon(size: 85), + applicationVersion: ref.watch(applicationInfoProvider).versionAndPlatform, + applicationLegalese: "Donut Factory", + ), + ), + ], + floatingActionButton: HideOnScroll( + controller: scrollController, + visibleBuilder: (visible) { + return AnimatedFadeSize( + child: visible + ? Padding( + padding: EdgeInsets.symmetric(horizontal: MediaQuery.paddingOf(context).horizontal), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + const Spacer(), + FloatingActionButton( + key: Key(context.localized.switchUser), + tooltip: context.localized.switchUser, + onPressed: () { + ref.read(userProvider.notifier).logoutUser(); + context.routeGo(LoginRoute()); + }, + child: const Icon( + IconsaxOutline.arrow_swap_horizontal, + ), + ), + const SizedBox(width: 16), + FloatingActionButton( + key: Key(context.localized.logout), + tooltip: context.localized.logout, + backgroundColor: Theme.of(context).colorScheme.errorContainer, + onPressed: () { + final user = ref.read(userProvider); + showDialog( + context: context, + builder: (context) => AlertDialog.adaptive( + title: Text(context.localized.logoutUserPopupTitle(user?.name ?? "")), + scrollable: true, + content: Text( + context.localized.logoutUserPopupContent(user?.name ?? "", user?.server ?? ""), + ), + actions: [ + ElevatedButton( + onPressed: () => Navigator.pop(context), + child: Text(context.localized.cancel), + ), + ElevatedButton( + style: ElevatedButton.styleFrom().copyWith( + foregroundColor: + WidgetStatePropertyAll(Theme.of(context).colorScheme.onErrorContainer), + backgroundColor: + WidgetStatePropertyAll(Theme.of(context).colorScheme.errorContainer), + ), + onPressed: () async { + await ref.read(authProvider.notifier).logOutUser(); + if (context.mounted) context.routeGo(SplashRoute()); + }, + child: Text(context.localized.logout), + ), + ], + ), + ); + }, + child: Icon( + IconsaxOutline.logout, + color: Theme.of(context).colorScheme.onErrorContainer, + ), + ), + ], + ), + ), + ) + : Container( + height: 0, + key: UniqueKey(), + ), + ); + }, + ), + ); + } +} diff --git a/lib/screens/settings/widgets/settings_label_divider.dart b/lib/screens/settings/widgets/settings_label_divider.dart new file mode 100644 index 0000000..8beb2ca --- /dev/null +++ b/lib/screens/settings/widgets/settings_label_divider.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class SettingsLabelDivider extends ConsumerWidget { + final String label; + const SettingsLabelDivider({required this.label, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8).add( + EdgeInsets.symmetric( + horizontal: MediaQuery.paddingOf(context).horizontal, + ), + ), + child: Text( + label, + style: Theme.of(context).textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.bold, + color: Theme.of(context).colorScheme.primary, + ), + ), + ); + } +} diff --git a/lib/screens/settings/widgets/settings_message_box.dart b/lib/screens/settings/widgets/settings_message_box.dart new file mode 100644 index 0000000..d8a722b --- /dev/null +++ b/lib/screens/settings/widgets/settings_message_box.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +enum MessageType { + info, + warning, + error; + + Color color(BuildContext context) { + switch (this) { + case info: + return Theme.of(context).colorScheme.surface; + case warning: + return Theme.of(context).colorScheme.primaryContainer; + case error: + return Theme.of(context).colorScheme.errorContainer; + } + } +} + +class SettingsMessageBox extends ConsumerWidget { + final String message; + final MessageType messageType; + const SettingsMessageBox(this.message, {this.messageType = MessageType.info, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return SizedBox( + width: double.infinity, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8).add( + EdgeInsets.symmetric( + horizontal: MediaQuery.paddingOf(context).horizontal, + ), + ), + child: Card( + elevation: 2, + color: messageType.color(context), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text(message), + ), + ), + ), + ); + } +} diff --git a/lib/screens/settings/widgets/subtitle_editor.dart b/lib/screens/settings/widgets/subtitle_editor.dart new file mode 100644 index 0000000..9428aa6 --- /dev/null +++ b/lib/screens/settings/widgets/subtitle_editor.dart @@ -0,0 +1,94 @@ +import 'package:fladder/models/settings/subtitle_settings_model.dart'; +import 'package:fladder/providers/settings/subtitle_settings_provider.dart'; +import 'package:fladder/providers/settings/video_player_settings_provider.dart'; +import 'package:fladder/screens/video_player/components/video_subtitle_controls.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/widgets/navigation_scaffold/components/fladder_appbar.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_blurhash/flutter_blurhash.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +// ignore: depend_on_referenced_packages + +class SubtitleEditor extends ConsumerStatefulWidget { + const SubtitleEditor({super.key}); + + @override + ConsumerState createState() => _SubtitleEditorState(); +} + +class _SubtitleEditorState extends ConsumerState { + @override + Widget build(BuildContext context) { + final settings = ref.watch(subtitleSettingsProvider); + final fillScreen = ref.watch(videoPlayerSettingsProvider.select((value) => value.fillScreen)); + final padding = MediaQuery.of(context).padding; + final fakeText = context.localized.subtitleConfiguratorPlaceHolder; + double lastScale = 0.0; + + return Scaffold( + body: Dialog.fullscreen( + child: GestureDetector( + onScaleUpdate: (details) { + lastScale = details.scale; + }, + onScaleEnd: (details) { + if (lastScale < 1.0) { + ref.read(videoPlayerSettingsProvider.notifier).setFillScreen(false, context: context); + } else if (lastScale > 1.0) { + ref.read(videoPlayerSettingsProvider.notifier).setFillScreen(true, context: context); + } + lastScale = 0.0; + }, + child: Stack( + children: [ + Padding( + padding: (fillScreen ? EdgeInsets.zero : EdgeInsets.only(left: padding.left, right: padding.right)), + child: const Center( + child: AspectRatio( + aspectRatio: 2.1, + child: Card( + child: Image( + image: BlurHashImage('LEF}}|0000~p8w~W%N4n~pIU4o%g'), + fit: BoxFit.fill, + ), + ), + ), + ), + ), + SubtitleText(subModel: settings, padding: padding, offset: settings.verticalOffset, text: fakeText), + Align( + alignment: Alignment.topCenter, + child: Padding( + padding: + MediaQuery.paddingOf(context).add(const EdgeInsets.all(32).add(const EdgeInsets.only(top: 48))), + child: SizedBox( + width: MediaQuery.sizeOf(context).width * 0.95, + child: const VideoSubtitleControls(), + ), + ), + ), + Padding( + padding: MediaQuery.paddingOf(context), + child: Column( + children: [ + if (AdaptiveLayout.of(context).isDesktop) const FladderAppbar(), + Row( + children: [ + const BackButton(), + Text( + context.localized.subtitleConfigurator, + style: Theme.of(context).textTheme.headlineMedium, + ) + ], + ) + ], + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/screens/shared/adaptive_dialog.dart b/lib/screens/shared/adaptive_dialog.dart new file mode 100644 index 0000000..9dd6810 --- /dev/null +++ b/lib/screens/shared/adaptive_dialog.dart @@ -0,0 +1,23 @@ +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:flutter/material.dart'; + +Future showDialogAdaptive( + {required BuildContext context, bool useSafeArea = true, required Widget Function(BuildContext context) builder}) { + if (AdaptiveLayout.of(context).inputDevice == InputDevice.pointer) { + return showDialog( + context: context, + useSafeArea: useSafeArea, + builder: (context) => Dialog( + child: builder(context), + ), + ); + } else { + return showDialog( + context: context, + useSafeArea: useSafeArea, + builder: (context) => Dialog.fullscreen( + child: builder(context), + ), + ); + } +} diff --git a/lib/screens/shared/animated_fade_size.dart b/lib/screens/shared/animated_fade_size.dart new file mode 100644 index 0000000..11e860a --- /dev/null +++ b/lib/screens/shared/animated_fade_size.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class AnimatedFadeSize extends ConsumerWidget { + final Duration duration; + final Widget child; + const AnimatedFadeSize({ + this.duration = const Duration(milliseconds: 125), + required this.child, + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return AnimatedSize( + duration: duration, + curve: Curves.easeInOutCubic, + child: AnimatedSwitcher( + duration: duration, + switchInCurve: Curves.easeInOutCubic, + switchOutCurve: Curves.easeInOutCubic, + child: child, + ), + ); + } +} diff --git a/lib/screens/shared/authenticate_button_options.dart b/lib/screens/shared/authenticate_button_options.dart new file mode 100644 index 0000000..4751d9b --- /dev/null +++ b/lib/screens/shared/authenticate_button_options.dart @@ -0,0 +1,72 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/account_model.dart'; +import 'package:fladder/screens/shared/fladder_snackbar.dart'; +import 'package:fladder/screens/shared/passcode_input.dart'; +import 'package:fladder/util/auth_service.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:flutter/material.dart'; + +showAuthOptionsDialogue( + BuildContext context, + AccountModel currentUser, + Function(AccountModel) setMethod, +) { + showDialog( + context: context, + builder: (context) => AlertDialog.adaptive( + scrollable: true, + icon: const Icon(IconsaxBold.lock_1), + title: Text(context.localized.appLockTitle(currentUser.name)), + actionsOverflowDirection: VerticalDirection.down, + actions: Authentication.values + .where((element) => element.available(context)) + .map( + (method) => SizedBox( + height: 50, + width: double.infinity, + child: ElevatedButton.icon( + onPressed: () async { + switch (method) { + case Authentication.autoLogin: + setMethod.call(currentUser.copyWith(authMethod: method)); + break; + case Authentication.biometrics: + final authenticated = await AuthService.authenticateUser(context, currentUser); + if (authenticated) { + setMethod.call(currentUser.copyWith(authMethod: method)); + } else if (context.mounted) { + fladderSnackbar(context, title: context.localized.biometricsFailedCheckAgain); + } + break; + case Authentication.passcode: + if (context.mounted) { + Navigator.of(context).pop(); + Future.microtask(() { + showPassCodeDialog(context, (newPin) { + setMethod.call(currentUser.copyWith(authMethod: method, localPin: newPin)); + }); + }); + } + return; + case Authentication.none: + setMethod.call(currentUser.copyWith(authMethod: method)); + break; + } + if (context.mounted) { + Navigator.of(context).pop(); + } + }, + icon: Icon(method.icon), + label: Text( + method.name(context), + textAlign: TextAlign.center, + ), + ), + ), + ) + .toList() + .addPadding(const EdgeInsets.symmetric(vertical: 8)), + ), + ); +} diff --git a/lib/screens/shared/chips/category_chip.dart b/lib/screens/shared/chips/category_chip.dart new file mode 100644 index 0000000..575025e --- /dev/null +++ b/lib/screens/shared/chips/category_chip.dart @@ -0,0 +1,264 @@ +import 'package:collection/collection.dart'; +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/map_bool_helper.dart'; +import 'package:fladder/widgets/shared/modal_bottom_sheet.dart'; +import 'package:fladder/widgets/shared/modal_side_sheet.dart'; +import 'package:flutter/material.dart'; + +class CategoryChip extends StatelessWidget { + final Map items; + final Widget label; + final Widget? dialogueTitle; + final Widget Function(T item) labelBuilder; + final IconData? activeIcon; + final Function(Map value)? onSave; + final VoidCallback? onCancel; + final VoidCallback? onClear; + final VoidCallback? onDismiss; + + const CategoryChip({ + required this.label, + this.dialogueTitle, + this.activeIcon, + required this.items, + required this.labelBuilder, + this.onSave, + this.onCancel, + this.onClear, + this.onDismiss, + super.key, + }); + + @override + Widget build(BuildContext context) { + var selection = items.included.isNotEmpty; + return FilterChip( + selected: selection, + showCheckmark: activeIcon == null, + label: Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (activeIcon != null) + AnimatedSize( + duration: const Duration(milliseconds: 250), + child: selection + ? Padding( + padding: const EdgeInsets.only(right: 12), + child: Icon( + activeIcon!, + size: 20, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ) + : const SizedBox(), + ), + label, + const SizedBox(width: 8), + Icon( + Icons.arrow_drop_down_rounded, + size: 20, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ], + ), + onSelected: items.isNotEmpty + ? (_) async { + final newEntry = await openActionSheet(context); + if (newEntry != null) { + onSave?.call(newEntry); + } + } + : null, + ); + } + + Future?> openActionSheet(BuildContext context) async { + Map? newEntry; + List actions() => [ + FilledButton.tonal( + onPressed: () { + Navigator.of(context).pop(); + newEntry = null; + onCancel?.call(); + }, + child: Text(context.localized.cancel), + ), + if (onClear != null) + ElevatedButton.icon( + onPressed: () { + Navigator.of(context).pop(); + newEntry = null; + onClear!(); + }, + icon: const Icon(IconsaxOutline.back_square), + label: Text(context.localized.clear), + ) + ].addInBetween(const SizedBox(width: 6)); + Widget header() => Row( + children: [ + Material( + color: Colors.transparent, + textStyle: Theme.of(context).textTheme.titleLarge, + child: dialogueTitle ?? label, + ), + const Spacer(), + FilledButton.tonal( + onPressed: () { + Navigator.of(context).pop(); + newEntry = null; + onCancel?.call(); + }, + child: Text(context.localized.cancel), + ), + if (onClear != null) + ElevatedButton.icon( + onPressed: () { + Navigator.of(context).pop(); + newEntry = null; + onClear!(); + }, + icon: const Icon(IconsaxOutline.back_square), + label: Text(context.localized.clear), + ) + ].addInBetween(const SizedBox(width: 6)), + ); + + if (AdaptiveLayout.of(context).layout != LayoutState.phone) { + await showModalSideSheet( + context, + addDivider: true, + header: dialogueTitle ?? label, + actions: actions(), + content: CategoryChipEditor( + labelBuilder: labelBuilder, + items: items, + onChanged: (value) { + newEntry = value; + }), + onDismiss: () { + if (newEntry != null) { + onSave?.call(newEntry!); + } + }, + ); + } else { + await showBottomSheetPill( + context: context, + content: (context, scrollController) => ListView( + shrinkWrap: true, + controller: scrollController, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: header(), + ), + const Divider(), + CategoryChipEditor( + labelBuilder: labelBuilder, + controller: scrollController, + items: items, + onChanged: (value) => newEntry = value), + ], + ), + onDismiss: () { + if (newEntry != null) { + onSave?.call(newEntry!); + } + }, + ); + } + return newEntry; + } +} + +class CategoryChipEditor extends StatefulWidget { + final Map items; + final Widget Function(T item) labelBuilder; + final Function(Map value) onChanged; + final ScrollController? controller; + const CategoryChipEditor({ + required this.items, + required this.labelBuilder, + required this.onChanged, + this.controller, + super.key, + }); + + @override + State> createState() => _CategoryChipEditorState(); +} + +class _CategoryChipEditorState extends State> { + late Map currentState = Map.fromEntries(widget.items.entries); + @override + Widget build(BuildContext context) { + Iterable> activeItems = widget.items.entries.where((element) => element.value); + Iterable> otherItems = widget.items.entries.where((element) => !element.value); + return ListView( + shrinkWrap: true, + controller: widget.controller, + children: [ + if (activeItems.isNotEmpty == true) ...{ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Text( + context.localized.active, + style: Theme.of(context).textTheme.titleLarge, + ), + ), + ...activeItems.mapIndexed((index, element) { + return CheckboxListTile.adaptive( + value: currentState[element.key], + title: widget.labelBuilder(element.key), + fillColor: WidgetStateProperty.resolveWith( + (states) { + if (currentState[element.key] == null) { + return Colors.redAccent; + } + return null; + }, + ), + tristate: true, + onChanged: (value) => updateKey(MapEntry(element.key, value == null ? null : element.value)), + ); + }), + Divider(), + }, + ...otherItems.mapIndexed((index, element) { + return CheckboxListTile.adaptive( + value: currentState[element.key], + title: widget.labelBuilder(element.key), + fillColor: WidgetStateProperty.resolveWith( + (states) { + if (currentState[element.key] == null || states.contains(WidgetState.selected)) { + return Colors.greenAccent; + } + return null; + }, + ), + tristate: true, + onChanged: (value) => updateKey(MapEntry(element.key, value != false ? null : element.value)), + ); + }), + ], + ); + } + + void updateKey(MapEntry entry) { + setState(() { + currentState.update( + entry.key, + (value) => entry.value, + ); + }); + widget.onChanged(Map.from(currentState.map( + (key, value) { + final origKey = widget.items[key] == true; + return MapEntry(key, origKey ? (value == null ? false : origKey) : (value == null ? true : origKey)); + }, + ))); + } +} diff --git a/lib/screens/shared/default_alert_dialog.dart b/lib/screens/shared/default_alert_dialog.dart new file mode 100644 index 0000000..323b1a5 --- /dev/null +++ b/lib/screens/shared/default_alert_dialog.dart @@ -0,0 +1,71 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; + +Future showDefaultAlertDialog( + BuildContext context, + String title, + String? content, + FutureOr Function(BuildContext context)? accept, + String? acceptTitle, + FutureOr Function(BuildContext context)? decline, + String declineTitle, +) { + return showDialog( + context: context, + builder: (context) => AlertDialog.adaptive( + title: Text(title), + content: content != null ? Text(content) : null, + actions: [ + if (decline != null) + ElevatedButton( + onPressed: () => decline.call(context), + child: Text(declineTitle), + ), + if (accept != null) + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Theme.of(context).colorScheme.errorContainer, + foregroundColor: Theme.of(context).colorScheme.onErrorContainer, + ), + onPressed: () => accept.call(context), + child: Text(acceptTitle ?? "Accept"), + ), + ], + ), + ); +} + +Future showDefaultActionDialog( + BuildContext context, + String title, + String? content, + FutureOr Function(BuildContext context)? accept, + String? acceptTitle, + FutureOr Function(BuildContext context)? decline, + String declineTitle, +) { + return showDialog( + context: context, + builder: (context) => AlertDialog.adaptive( + title: Text(title), + content: content != null ? Text(content) : null, + actions: [ + if (decline != null) + ElevatedButton( + onPressed: () => decline.call(context), + child: Text(declineTitle), + ), + if (accept != null) + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Theme.of(context).colorScheme.primaryContainer, + foregroundColor: Theme.of(context).colorScheme.onPrimaryContainer, + ), + onPressed: () => accept.call(context), + child: Text(acceptTitle ?? "Accept"), + ), + ], + ), + ); +} diff --git a/lib/screens/shared/default_titlebar.dart b/lib/screens/shared/default_titlebar.dart new file mode 100644 index 0000000..369489d --- /dev/null +++ b/lib/screens/shared/default_titlebar.dart @@ -0,0 +1,169 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:window_manager/window_manager.dart'; + +import 'package:fladder/util/adaptive_layout.dart'; + +class DefaultTitleBar extends ConsumerStatefulWidget { + final String? label; + final double? height; + final Brightness? brightness; + const DefaultTitleBar({this.height = 35, this.label, this.brightness, super.key}); + + @override + ConsumerState createState() => _DefaultTitleBarState(); +} + +class _DefaultTitleBarState extends ConsumerState with WindowListener { + @override + void initState() { + windowManager.addListener(this); + super.initState(); + } + + @override + void dispose() { + windowManager.removeListener(this); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final brightness = widget.brightness ?? Theme.of(context).brightness; + final shadows = brightness == Brightness.dark + ? [ + BoxShadow(blurRadius: 1, spreadRadius: 1, color: Theme.of(context).colorScheme.surface.withOpacity(1)), + BoxShadow(blurRadius: 8, spreadRadius: 2, color: Colors.black.withOpacity(0.2)), + BoxShadow(blurRadius: 3, spreadRadius: 2, color: Colors.black.withOpacity(0.3)), + ] + : []; + final iconColor = Theme.of(context).colorScheme.onSurface.withOpacity(0.65); + return SizedBox( + height: widget.height, + child: switch (AdaptiveLayout.of(context).platform) { + TargetPlatform.windows || TargetPlatform.linux => Row( + children: [ + Expanded( + child: DragToMoveArea( + child: Container( + color: Colors.red.withOpacity(0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.max, + children: [ + Container( + padding: const EdgeInsets.only(left: 16), + child: DefaultTextStyle( + style: TextStyle( + color: iconColor, + fontSize: 14, + ), + child: Text(widget.label ?? ""), + ), + ), + ], + ), + ), + ), + ), + Row( + children: [ + FutureBuilder( + future: windowManager.isMinimizable(), + builder: (context, data) { + final isMinimized = !(data.data ?? false); + return IconButton( + style: IconButton.styleFrom( + hoverColor: brightness == Brightness.light + ? Colors.black.withOpacity(0.1) + : Colors.white.withOpacity(0.2), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(2))), + onPressed: () async { + if (isMinimized) { + windowManager.restore(); + } else { + windowManager.minimize(); + } + }, + icon: Transform.translate( + offset: Offset(0, -2), + child: Icon( + Icons.minimize_rounded, + color: iconColor, + size: 20, + shadows: shadows, + ), + ), + ); + }), + FutureBuilder>( + future: Future.microtask(() async { + final isMaximized = await windowManager.isMaximized(); + final isFullScreen = await windowManager.isFullScreen(); + return [isMaximized, isFullScreen]; + }), + builder: (BuildContext context, AsyncSnapshot> snapshot) { + final maximized = snapshot.data?.firstOrNull ?? false; + final fullScreen = snapshot.data?.lastOrNull ?? false; + return IconButton( + style: IconButton.styleFrom( + hoverColor: brightness == Brightness.light + ? Colors.black.withOpacity(0.1) + : Colors.white.withOpacity(0.2), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(2)), + ), + onPressed: () async { + if (fullScreen == true && maximized == true) { + await windowManager.setFullScreen(false); + await windowManager.unmaximize(); + return; + } + if (fullScreen == true) { + windowManager.setFullScreen(false); + } else { + maximized == false ? windowManager.maximize() : windowManager.unmaximize(); + } + }, + icon: Transform.translate( + offset: Offset(0, 0), + child: Icon( + maximized ? Icons.maximize_rounded : Icons.crop_square_rounded, + color: iconColor, + size: 19, + shadows: shadows, + ), + ), + ); + }, + ), + IconButton( + style: IconButton.styleFrom( + hoverColor: Colors.red, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(2), + ), + ), + onPressed: () async { + windowManager.close(); + }, + icon: Transform.translate( + offset: Offset(0, -2), + child: Icon( + Icons.close_rounded, + color: iconColor, + size: 23, + shadows: shadows, + ), + ), + ), + ], + ), + ], + ), + TargetPlatform.macOS => null, + _ => Text(widget.label ?? "Fladder"), + }, + ); + } +} diff --git a/lib/screens/shared/detail_scaffold.dart b/lib/screens/shared/detail_scaffold.dart new file mode 100644 index 0000000..afdf0de --- /dev/null +++ b/lib/screens/shared/detail_scaffold.dart @@ -0,0 +1,303 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/screens/shared/animated_fade_size.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/widgets/navigation_scaffold/components/settings_user_icon.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; + +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/images_models.dart'; +import 'package:fladder/models/media_playback_model.dart'; +import 'package:fladder/providers/items/item_details_provider.dart'; +import 'package:fladder/providers/video_player_provider.dart'; +import 'package:fladder/routes/build_routes/home_routes.dart'; +import 'package:fladder/routes/build_routes/route_builder.dart'; +import 'package:fladder/theme.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/fladder_image.dart'; +import 'package:fladder/util/refresh_state.dart'; +import 'package:fladder/widgets/navigation_scaffold/components/floating_player_bar.dart'; +import 'package:fladder/widgets/shared/item_actions.dart'; +import 'package:fladder/widgets/shared/modal_bottom_sheet.dart'; +import 'package:fladder/widgets/shared/pull_to_refresh.dart'; + +class DetailScreen extends ConsumerStatefulWidget { + final String id; + final ItemBaseModel? item; + const DetailScreen({required this.id, this.item, super.key}); + + @override + ConsumerState createState() => _DetailScreenState(); +} + +class _DetailScreenState extends ConsumerState { + late Widget currentWidget = const Center( + key: Key("progress-indicator"), + child: CircularProgressIndicator.adaptive(strokeCap: StrokeCap.round), + ); + + @override + void initState() { + super.initState(); + Future.microtask(() async { + if (widget.item != null) { + setState(() { + currentWidget = widget.item!.detailScreenWidget; + }); + } else { + final response = await ref.read(itemDetailsProvider.notifier).fetchDetails(widget.id); + if (context.mounted) { + if (response != null) { + setState(() { + currentWidget = response.detailScreenWidget; + }); + } else { + context.routeGo(DashboardRoute()); + } + } + } + }); + } + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + Hero( + tag: widget.id, + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface.withOpacity(1.0), + ), + //Small offset to match detailscaffold + child: Transform.translate( + offset: Offset(0, -5), child: FladderImage(image: widget.item?.getPosters?.primary)), + ), + ), + AnimatedFadeSize( + duration: const Duration(seconds: 1), + child: currentWidget, + ) + ], + ); + } +} + +class DetailScaffold extends ConsumerStatefulWidget { + final String label; + final ItemBaseModel? item; + final List? Function(BuildContext context)? actions; + final Color? backgroundColor; + final ImagesData? backDrops; + final Function(EdgeInsets padding) content; + final Future Function()? onRefresh; + const DetailScaffold({ + required this.label, + this.item, + this.actions, + this.backgroundColor, + required this.content, + this.backDrops, + this.onRefresh, + super.key, + }); + + @override + ConsumerState createState() => _DetailScaffoldState(); +} + +class _DetailScaffoldState extends ConsumerState { + List? lastImages; + ImageData? backgroundImage; + + @override + void didUpdateWidget(covariant DetailScaffold oldWidget) { + super.didUpdateWidget(oldWidget); + if (lastImages == null) { + lastImages = widget.backDrops?.backDrop; + setState(() { + backgroundImage = widget.backDrops?.randomBackDrop; + }); + } + } + + @override + Widget build(BuildContext context) { + final padding = EdgeInsets.symmetric(horizontal: MediaQuery.of(context).size.width / 25); + final backGroundColor = Theme.of(context).colorScheme.surface.withOpacity(0.8); + final playerState = ref.watch(mediaPlaybackProvider.select((value) => value.state)); + return PullToRefresh( + onRefresh: () async { + await widget.onRefresh?.call(); + setState(() { + if (widget.backDrops?.backDrop?.contains(backgroundImage) == true) { + backgroundImage = widget.backDrops?.randomBackDrop; + } + }); + }, + refreshOnStart: true, + child: Scaffold( + floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, + floatingActionButton: switch (playerState) { + VideoPlayerState.minimized => Padding( + padding: const EdgeInsets.all(8.0), + child: FloatingPlayerBar(), + ), + _ => null, + }, + backgroundColor: Theme.of(context).colorScheme.surface, + extendBodyBehindAppBar: true, + body: Stack( + children: [ + SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics(), + child: Stack( + alignment: Alignment.topCenter, + children: [ + SizedBox( + height: MediaQuery.of(context).size.height - 10, + width: MediaQuery.of(context).size.width, + child: FladderImage( + image: backgroundImage, + ), + ), + Container( + height: MediaQuery.of(context).size.height, + width: MediaQuery.of(context).size.width, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Theme.of(context).colorScheme.surface.withOpacity(0), + Theme.of(context).colorScheme.surface.withOpacity(0.10), + Theme.of(context).colorScheme.surface.withOpacity(0.35), + Theme.of(context).colorScheme.surface.withOpacity(0.85), + Theme.of(context).colorScheme.surface, + ], + ), + ), + ), + Container( + height: MediaQuery.of(context).size.height, + width: MediaQuery.of(context).size.width, + color: widget.backgroundColor, + ), + Padding( + padding: EdgeInsets.only( + bottom: 0, + left: MediaQuery.of(context).padding.left, + top: MediaQuery.of(context).padding.top + 50), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: MediaQuery.of(context).size.height, + maxWidth: MediaQuery.of(context).size.width, + ), + child: widget.content(padding), + ), + ), + ], + ), + ), + //Top row buttons + IconTheme( + data: IconThemeData(color: Theme.of(context).colorScheme.onSurface), + child: Transform.translate( + offset: Offset(0, kToolbarHeight), + child: Row( + children: [ + Padding( + padding: EdgeInsets.only(left: 16), + child: IconButton.filledTonal( + style: IconButton.styleFrom( + backgroundColor: backGroundColor, + ), + onPressed: () { + if (context.canPop()) { + context.pop(); + } else { + context.replace(DashboardRoute().route); + } + }, + icon: Padding( + padding: + EdgeInsets.all(AdaptiveLayout.of(context).inputDevice == InputDevice.pointer ? 0 : 4), + child: Icon(IconsaxOutline.arrow_left_2), + ), + ), + ), + const Spacer(), + Padding( + padding: const EdgeInsets.only(right: 16), + child: AnimatedSize( + duration: const Duration(milliseconds: 250), + child: Container( + decoration: BoxDecoration( + color: backGroundColor, borderRadius: FladderTheme.defaultShape.borderRadius), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (widget.item != null) ...[ + Builder( + builder: (context) { + final newActions = widget.actions?.call(context); + if (AdaptiveLayout.of(context).inputDevice == InputDevice.pointer) { + return PopupMenuButton( + tooltip: context.localized.moreOptions, + enabled: newActions?.isNotEmpty == true, + icon: Icon(widget.item!.type.icon), + itemBuilder: (context) => newActions?.popupMenuItems(useIcons: true) ?? [], + ); + } else { + return IconButton( + onPressed: () => showBottomSheetPill( + context: context, + content: (context, scrollController) => ListView( + controller: scrollController, + shrinkWrap: true, + children: newActions?.listTileItems(context, useIcons: true) ?? [], + ), + ), + icon: Icon( + widget.item!.type.icon, + ), + ); + } + }, + ), + ], + if (AdaptiveLayout.of(context).inputDevice == InputDevice.pointer) + Builder( + builder: (context) => Tooltip( + message: context.localized.refresh, + child: IconButton( + onPressed: () => context.refreshData(), + icon: Icon(IconsaxOutline.refresh), + ), + ), + ) + else + SizedBox(height: 30, width: 30, child: SettingsUserIcon()), + Tooltip( + message: context.localized.home, + child: IconButton( + onPressed: () => context.routeGo(DashboardRoute()), + icon: Icon(IconsaxOutline.home), + ), + ), + ], + ), + ), + ), + ), + ], + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/screens/shared/file_picker.dart b/lib/screens/shared/file_picker.dart new file mode 100644 index 0000000..2865b3b --- /dev/null +++ b/lib/screens/shared/file_picker.dart @@ -0,0 +1,198 @@ +import 'package:desktop_drop/desktop_drop.dart'; +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/screens/shared/outlined_text_field.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:flutter/foundation.dart'; +// ignore: depend_on_referenced_packages +import 'package:path/path.dart' as p; + +import 'package:file_picker/file_picker.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class FladderFile { + final String name; + final String? path; + final Uint8List? data; + FladderFile({ + required this.name, + this.path, + this.data, + }); + + static final Set imageTypes = { + "png", + "jpg", + "jpeg", + "webp", + "gif", + }; + + @override + String toString() => 'FladderFile(name: $name, path: $path, data: ${data?.length})'; +} + +class FilePickerBar extends ConsumerStatefulWidget { + final Function(List file)? onFilesPicked; + final Function(String url)? urlPicked; + final Set extensions; + final bool multipleFiles; + final double stripesAngle; + const FilePickerBar({ + this.onFilesPicked, + this.urlPicked, + this.multipleFiles = false, + this.stripesAngle = -0.90, + this.extensions = const {}, + super.key, + }); + + @override + ConsumerState createState() => _FilePickerBarState(); +} + +class _FilePickerBarState extends ConsumerState { + final TextEditingController controller = TextEditingController(); + bool dragStart = false; + bool inputField = false; + + @override + Widget build(BuildContext context) { + final offColor = Theme.of(context).colorScheme.secondaryContainer; + final onColor = Theme.of(context).colorScheme.secondaryContainer.withOpacity(0.7); + final contentColor = Theme.of(context).colorScheme.onSecondaryContainer; + return DropTarget( + enable: !inputField, + onDragEntered: (details) => setState(() => dragStart = true), + onDragDone: (details) async { + if (widget.multipleFiles) { + List newFiles = []; + await Future.forEach(details.files, (element) async { + if (widget.extensions.contains(p.extension(element.path).substring(1))) { + newFiles.add( + FladderFile( + name: element.name, + path: element.path, + data: await element.readAsBytes(), + ), + ); + } + }); + widget.onFilesPicked?.call(newFiles); + } else { + final file = details.files.lastOrNull; + if (file != null) { + widget.onFilesPicked?.call([ + FladderFile( + name: file.name, + path: file.path, + data: await file.readAsBytes(), + ) + ]); + } + } + }, + onDragExited: (details) => setState(() => dragStart = false), + child: Container( + constraints: BoxConstraints(minHeight: 50, minWidth: 50), + decoration: BoxDecoration( + color: Colors.grey, + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment(widget.stripesAngle, -0), + stops: [0.0, 0.5, 0.5, 1], + colors: [offColor, offColor, onColor, onColor], + tileMode: TileMode.repeated, + ), + ), + child: AnimatedSwitcher( + duration: Duration(milliseconds: 250), + child: inputField + ? OutlinedTextField( + controller: controller, + autoFocus: true, + onSubmitted: (value) { + if (_parseUrl(value)) { + widget.urlPicked?.call(value); + } + controller.text = ""; + setState(() => inputField = false); + }, + ) + : Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + if (AdaptiveLayout.of(context).isDesktop || kIsWeb) + Row( + children: [ + Text( + widget.multipleFiles ? "drop multiple file(s)" : "drop a file", + style: Theme.of(context).textTheme.bodyLarge?.copyWith(color: contentColor), + ), + const SizedBox(width: 12), + Icon( + IconsaxBold.folder_add, + color: contentColor, + ) + ], + ), + TextButton( + onPressed: () => setState(() => inputField = true), + child: Text( + "enter a url", + style: Theme.of(context).textTheme.bodyLarge?.copyWith(color: contentColor), + ), + ), + FilledButton( + onPressed: dragStart + ? null + : () async { + FilePickerResult? result = await FilePicker.platform.pickFiles( + allowMultiple: widget.multipleFiles, + allowedExtensions: widget.extensions.toList(), + type: FileType.custom, + withData: true, + ); + if (result != null && result.count != 0) { + List newFiles = []; + await Future.forEach(result.files, (element) async { + newFiles.add( + FladderFile( + name: element.name, + path: element.path, + data: element.bytes, + ), + ); + }); + widget.onFilesPicked?.call(newFiles); + } + FilePicker.platform.clearTemporaryFiles(); + }, + child: Text( + widget.multipleFiles ? "file(s) picker" : "file picker", + style: Theme.of(context).textTheme.bodyLarge?.copyWith( + color: Theme.of(context).colorScheme.onPrimary, + ), + ), + ), + ], + ), + ), + ), + ); + } +} + +bool _parseUrl(String url) { + if (url.isEmpty) { + return false; + } + if (!Uri.parse(url).isAbsolute) { + return false; + } + + if (!url.startsWith('https://') && !url.startsWith('http://')) { + return false; + } + return true; +} diff --git a/lib/screens/shared/fladder_icon.dart b/lib/screens/shared/fladder_icon.dart new file mode 100644 index 0000000..a7865e0 --- /dev/null +++ b/lib/screens/shared/fladder_icon.dart @@ -0,0 +1,57 @@ +import 'package:fladder/util/theme_extensions.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'dart:ui' as ui; + +class FladderIcon extends StatelessWidget { + final double size; + const FladderIcon({this.size = 100, super.key}); + + @override + Widget build(BuildContext context) { + return Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ShaderMask( + shaderCallback: (Rect bounds) { + return ui.Gradient.linear( + const Offset(30, 30), + const Offset(80, 80), + [ + Theme.of(context).colorScheme.primary, + Theme.of(context).colorScheme.secondary, + ], + ); + }, + child: RotatedBox( + quarterTurns: 1, + child: SvgPicture.asset( + "icons/fladder_icon_grayscale.svg", + width: size, + colorFilter: const ColorFilter.mode(Colors.white, BlendMode.srcIn), + ), + ), + ), + ], + ); + } +} + +class FladderIconOutlined extends StatelessWidget { + final double size; + final Color? color; + const FladderIconOutlined({this.size = 100, this.color, super.key}); + + @override + Widget build(BuildContext context) { + return RotatedBox( + quarterTurns: 1, + child: SvgPicture.asset( + "icons/fladder_icon_outline.svg", + width: size, + colorFilter: ColorFilter.mode(color ?? context.colors.onSurfaceVariant, BlendMode.srcATop), + ), + ); + } +} diff --git a/lib/screens/shared/fladder_logo.dart b/lib/screens/shared/fladder_logo.dart new file mode 100644 index 0000000..7647d0a --- /dev/null +++ b/lib/screens/shared/fladder_logo.dart @@ -0,0 +1,32 @@ +import 'package:fladder/screens/shared/fladder_icon.dart'; +import 'package:fladder/util/application_info.dart'; +import 'package:fladder/util/string_extensions.dart'; +import 'package:fladder/util/theme_extensions.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class FladderLogo extends ConsumerWidget { + const FladderLogo({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Hero( + tag: "Fladder_Logo_Tag", + child: Wrap( + runAlignment: WrapAlignment.center, + crossAxisAlignment: WrapCrossAlignment.center, + alignment: WrapAlignment.center, + spacing: 16, + runSpacing: 8, + children: [ + const FladderIcon(), + Text( + ref.read(applicationInfoProvider).name.capitalize(), + style: context.textTheme.displayLarge, + textAlign: TextAlign.center, + ) + ], + ), + ); + } +} diff --git a/lib/screens/shared/fladder_snackbar.dart b/lib/screens/shared/fladder_snackbar.dart new file mode 100644 index 0000000..ede0939 --- /dev/null +++ b/lib/screens/shared/fladder_snackbar.dart @@ -0,0 +1,189 @@ +import 'package:chopper/chopper.dart'; +import 'package:flutter/material.dart'; + +void fladderSnackbar( + BuildContext context, { + String title = "", + bool permanent = false, + SnackBarAction? action, + bool showCloseButton = false, + Duration duration = const Duration(seconds: 3), +}) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text( + title, + style: Theme.of(context) + .textTheme + .titleMedium + ?.copyWith(fontWeight: FontWeight.w500, color: Theme.of(context).colorScheme.onSecondary), + ), + clipBehavior: Clip.none, + showCloseIcon: showCloseButton, + duration: duration, + padding: EdgeInsets.all(18), + action: action, + )); +} + +void fladderSnackbarResponse(BuildContext context, Response? response, {String? altTitle}) { + if (response != null) { + fladderSnackbar(context, + title: "(${response.base.statusCode}) ${response.base.reasonPhrase ?? "Something went wrong!"}"); + return; + } else if (altTitle != null) { + fladderSnackbar(context, title: altTitle); + } +} + +// void _showOverlay( +// BuildContext context, { +// required String title, +// Widget? leading, +// bool showCloseButton = false, +// bool permanent = false, +// Duration duration = const Duration(seconds: 3), +// }) { +// late OverlayEntry overlayEntry; + +// overlayEntry = OverlayEntry( +// builder: (context) => _OverlayAnimationWidget( +// title: title, +// leading: leading, +// showCloseButton: showCloseButton, +// permanent: permanent, +// duration: duration, +// overlayEntry: overlayEntry, +// ), +// ); + +// // Insert the overlay entry into the overlay +// Overlay.of(context).insert(overlayEntry); +// } + +// class _OverlayAnimationWidget extends StatefulWidget { +// final String title; +// final Widget? leading; +// final bool showCloseButton; +// final bool permanent; +// final Duration duration; +// final OverlayEntry overlayEntry; + +// _OverlayAnimationWidget({ +// required this.title, +// this.leading, +// this.showCloseButton = false, +// this.permanent = false, +// this.duration = const Duration(seconds: 3), +// required this.overlayEntry, +// }); + +// @override +// _OverlayAnimationWidgetState createState() => _OverlayAnimationWidgetState(); +// } + +// class _OverlayAnimationWidgetState extends State<_OverlayAnimationWidget> with SingleTickerProviderStateMixin { +// late AnimationController _controller; +// late Animation _offsetAnimation; + +// void remove() { +// // Optionally, you can use a Future.delayed to remove the overlay after a certain duration +// _controller.reverse(); +// // Remove the overlay entry after the animation completes +// Future.delayed(Duration(seconds: 1), () { +// widget.overlayEntry.remove(); +// }); +// } + +// @override +// void initState() { +// super.initState(); + +// _controller = AnimationController( +// vsync: this, +// duration: Duration(milliseconds: 250), +// ); + +// _offsetAnimation = Tween( +// begin: Offset(0.0, 1.5), +// end: Offset.zero, +// ).animate(CurvedAnimation( +// parent: _controller, +// curve: Curves.fastOutSlowIn, +// )); + +// // Start the animation +// _controller.forward(); + +// Future.delayed(widget.duration, () { +// if (!widget.permanent) { +// remove(); +// } +// }); +// } + +// @override +// void dispose() { +// _controller.dispose(); +// super.dispose(); +// } + +// @override +// Widget build(BuildContext context) { +// return Positioned( +// bottom: 10 + MediaQuery.of(context).padding.bottom, +// left: 25, +// right: 25, +// child: Dismissible( +// key: UniqueKey(), +// direction: DismissDirection.horizontal, +// confirmDismiss: (direction) async { +// remove(); +// return true; +// }, +// child: SlideTransition( +// position: _offsetAnimation, +// child: Card( +// elevation: 5, +// color: Colors.transparent, +// surfaceTintColor: Colors.transparent, +// child: Container( +// decoration: BoxDecoration( +// color: Theme.of(context).colorScheme.secondaryContainer, +// ), +// child: Padding( +// padding: const EdgeInsets.all(12.0), +// child: ConstrainedBox( +// constraints: BoxConstraints(minHeight: 45), +// child: Row( +// children: [ +// if (widget.leading != null) widget.leading!, +// Expanded( +// child: Text( +// widget.title, +// style: TextStyle( +// fontSize: 16, +// fontWeight: FontWeight.w400, +// color: Theme.of(context).colorScheme.onSecondaryContainer), +// ), +// ), +// const SizedBox(width: 6), +// if (widget.showCloseButton || widget.permanent) +// IconButton( +// onPressed: () => remove(), +// icon: Icon( +// IconsaxOutline.close_square, +// size: 28, +// color: Theme.of(context).colorScheme.onSecondaryContainer, +// ), +// ) +// ], +// ), +// ), +// ), +// ), +// ), +// ), +// ), +// ); +// } +// } diff --git a/lib/screens/shared/flat_button.dart b/lib/screens/shared/flat_button.dart new file mode 100644 index 0000000..011c1b3 --- /dev/null +++ b/lib/screens/shared/flat_button.dart @@ -0,0 +1,46 @@ +import 'package:fladder/theme.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class FlatButton extends ConsumerWidget { + final Widget? child; + final Function()? onTap; + final Function()? onLongPress; + final Function()? onDoubleTap; + final Function(TapDownDetails details)? onSecondaryTapDown; + final BorderRadius? borderRadiusGeometry; + final Color? splashColor; + final double elevation; + final Clip clipBehavior; + const FlatButton( + {this.child, + this.onTap, + this.onLongPress, + this.onDoubleTap, + this.onSecondaryTapDown, + this.borderRadiusGeometry, + this.splashColor, + this.elevation = 0, + this.clipBehavior = Clip.none, + super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Material( + color: Colors.transparent, + clipBehavior: clipBehavior, + borderRadius: borderRadiusGeometry ?? FladderTheme.defaultShape.borderRadius, + elevation: 0, + child: InkWell( + onTap: onTap, + onLongPress: onLongPress, + onDoubleTap: onDoubleTap, + onSecondaryTapDown: onSecondaryTapDown, + borderRadius: borderRadiusGeometry ?? BorderRadius.circular(10), + splashColor: splashColor ?? Theme.of(context).colorScheme.primary.withOpacity(0.5), + splashFactory: InkSparkle.splashFactory, + child: child ?? Container(), + ), + ); + } +} diff --git a/lib/screens/shared/floating_search_bar.dart b/lib/screens/shared/floating_search_bar.dart new file mode 100644 index 0000000..34fe79f --- /dev/null +++ b/lib/screens/shared/floating_search_bar.dart @@ -0,0 +1,102 @@ +import 'package:animations/animations.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/routes/build_routes/route_builder.dart'; +import 'package:fladder/routes/build_routes/settings_routes.dart'; +import 'package:fladder/screens/search/search_screen.dart'; +import 'package:fladder/util/string_extensions.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; + +class FloatingSearchBar extends ConsumerStatefulWidget { + final List trailing; + final String hintText; + final bool showLoading; + final bool showUserIcon; + final bool automaticallyImplyLeading; + final double height; + const FloatingSearchBar({ + this.trailing = const [], + this.showLoading = false, + this.showUserIcon = true, + this.height = 50, + required this.hintText, + this.automaticallyImplyLeading = true, + super.key, + }); + + @override + ConsumerState createState() => _FloatingSearchBarState(); +} + +class _FloatingSearchBarState extends ConsumerState { + @override + Widget build(BuildContext context) { + final user = ref.watch(userProvider); + return Hero( + tag: "FloatingSearchBarHome", + child: SizedBox( + height: widget.height, + width: double.infinity, + child: OpenContainer( + openBuilder: (context, action) { + return const SearchScreen(); + }, + openColor: Colors.transparent, + openElevation: 0, + closedColor: Colors.transparent, + closedElevation: 0, + closedBuilder: (context, openAction) => Card( + clipBehavior: Clip.antiAlias, + shadowColor: Colors.transparent, + elevation: 5, + margin: EdgeInsets.zero, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(500)), + child: InkWell( + onTap: () => openAction(), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (context.canPop()) + IconButton( + onPressed: () => context.pop(), + icon: const Icon(Icons.arrow_back), + ), + const SizedBox(width: 8), + Expanded( + child: Text( + widget.hintText, + style: Theme.of(context).textTheme.bodyLarge, + )), + IconButton( + onPressed: () => openAction(), + icon: const Icon( + Icons.search_rounded, + ), + ), + IconButton( + onPressed: () { + context.routeGo(SecuritySettingsRoute()); + }, + icon: ClipRRect( + borderRadius: BorderRadius.circular(200), + child: CachedNetworkImage( + imageUrl: user?.avatar ?? "", + memCacheHeight: 125, + imageBuilder: (context, imageProvider) => Image(image: imageProvider), + errorWidget: (context, url, error) => CircleAvatar( + child: Text(user?.name.getInitials() ?? ""), + ), + ), + ), + ), + ], + ), + ), + ), + ), + ), + ); + } +} diff --git a/lib/screens/shared/focused_outlined_text_field.dart b/lib/screens/shared/focused_outlined_text_field.dart new file mode 100644 index 0000000..1d11093 --- /dev/null +++ b/lib/screens/shared/focused_outlined_text_field.dart @@ -0,0 +1,89 @@ +import 'package:fladder/screens/shared/outlined_text_field.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class FocusedOutlinedTextField extends ConsumerStatefulWidget { + final String? label; + final TextEditingController? controller; + final int maxLines; + final Function()? onTap; + final Function(String value)? onChanged; + final Function(String value)? onSubmitted; + final List? autoFillHints; + final List? inputFormatters; + final bool autocorrect; + final TextStyle? style; + final double borderWidth; + final Color? fillColor; + final TextAlign textAlign; + final TextInputType? keyboardType; + final TextInputAction? textInputAction; + final Function(bool focused)? onFocus; + final String? errorText; + final bool? enabled; + const FocusedOutlinedTextField({ + this.label, + this.controller, + this.maxLines = 1, + this.onTap, + this.onChanged, + this.onSubmitted, + this.fillColor, + this.style, + this.borderWidth = 1, + this.textAlign = TextAlign.start, + this.autoFillHints, + this.inputFormatters, + this.autocorrect = true, + this.keyboardType, + this.textInputAction, + this.onFocus, + this.errorText, + this.enabled, + super.key, + }); + + @override + ConsumerState createState() => FocuesOutlinedTextFieldState(); +} + +class FocuesOutlinedTextFieldState extends ConsumerState { + late FocusNode focusNode = FocusNode(); + late bool previousFocus = focusNode.hasFocus; + + @override + void initState() { + super.initState(); + focusNode.addListener(() { + if (previousFocus != focusNode.hasFocus) { + previousFocus = focusNode.hasFocus; + widget.onFocus?.call(focusNode.hasFocus); + } + }); + } + + @override + Widget build(BuildContext context) { + return OutlinedTextField( + controller: widget.controller, + onTap: widget.onTap, + onChanged: widget.onChanged, + focusNode: focusNode, + keyboardType: widget.keyboardType, + autocorrect: widget.autocorrect, + onSubmitted: widget.onSubmitted, + textInputAction: widget.textInputAction, + style: widget.style, + maxLines: widget.maxLines, + inputFormatters: widget.inputFormatters, + textAlign: widget.textAlign, + fillColor: widget.fillColor, + errorText: widget.errorText, + autoFillHints: widget.autoFillHints, + borderWidth: widget.borderWidth, + enabled: widget.enabled, + label: widget.label, + ); + } +} diff --git a/lib/screens/shared/input_fields.dart b/lib/screens/shared/input_fields.dart new file mode 100644 index 0000000..f45a183 --- /dev/null +++ b/lib/screens/shared/input_fields.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class IntInputField extends ConsumerWidget { + final int? value; + final TextEditingController? controller; + final String? placeHolder; + final String? suffix; + final Function(int? value)? onSubmitted; + const IntInputField({ + this.value, + this.controller, + this.suffix, + this.placeHolder, + this.onSubmitted, + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Card( + color: Theme.of(context).colorScheme.secondaryContainer.withOpacity(0.25), + elevation: 0, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 6), + child: TextField( + controller: controller ?? TextEditingController(text: (value ?? 0).toString()), + keyboardType: const TextInputType.numberWithOptions(decimal: false, signed: false), + inputFormatters: [FilteringTextInputFormatter.digitsOnly], + textInputAction: TextInputAction.done, + onSubmitted: (value) => onSubmitted?.call(int.tryParse(value)), + textAlign: TextAlign.center, + decoration: InputDecoration( + contentPadding: EdgeInsets.all(0), + hintText: placeHolder, + suffixText: suffix, + border: InputBorder.none, + ), + ), + ), + ); + } +} diff --git a/lib/screens/shared/media/carousel_banner.dart b/lib/screens/shared/media/carousel_banner.dart new file mode 100644 index 0000000..dabcb89 --- /dev/null +++ b/lib/screens/shared/media/carousel_banner.dart @@ -0,0 +1,378 @@ +import 'package:async/async.dart'; +import 'package:collection/collection.dart'; +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/movie_model.dart'; +import 'package:fladder/screens/shared/media/components/media_play_button.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/fladder_image.dart'; +import 'package:fladder/util/item_base_model/item_base_model_extensions.dart'; +import 'package:fladder/util/item_base_model/play_item_helpers.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/themes_data.dart'; +import 'package:fladder/widgets/shared/item_actions.dart'; +import 'package:fladder/widgets/shared/modal_bottom_sheet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class CarouselBanner extends ConsumerStatefulWidget { + final PageController? controller; + final List items; + const CarouselBanner({ + this.controller, + required this.items, + super.key, + }); + + @override + ConsumerState createState() => _CarouselBannerState(); +} + +class _CarouselBannerState extends ConsumerState { + bool showControls = false; + bool interacting = false; + int currentPage = 0; + double dragOffset = 0; + double dragIntensity = 1; + double slidePosition = 1; + + late final RestartableTimer timer = RestartableTimer(Duration(seconds: 8), () => nextSlide()); + + @override + void initState() { + super.initState(); + timer.reset(); + } + + @override + void dispose() { + timer.cancel(); + super.dispose(); + } + + void nextSlide() { + if (!interacting) { + setState(() { + if (currentPage == widget.items.length - 1) { + currentPage = 0; + } else { + currentPage++; + } + }); + } + timer.reset(); + } + + void previousSlide() { + if (!interacting) { + setState(() { + if (currentPage == 0) { + currentPage = widget.items.length - 1; + } else { + currentPage--; + } + }); + } + timer.reset(); + } + + @override + Widget build(BuildContext context) { + final overlayColor = ThemesData.of(context).dark.colorScheme.onSecondary; + final shadows = [ + BoxShadow(blurRadius: 12, spreadRadius: 8, color: overlayColor), + ]; + final currentItem = widget.items[currentPage.clamp(0, widget.items.length - 1)]; + final actions = currentItem.generateActions(context, ref); + + final double dragOpacity = (1 - dragOffset.abs()).clamp(0, 1); + + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Flexible( + child: Card( + elevation: 16, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)), + surfaceTintColor: overlayColor, + color: overlayColor, + child: GestureDetector( + onTap: () => currentItem.navigateTo(context), + onLongPress: AdaptiveLayout.of(context).inputDevice == InputDevice.touch + ? () async { + interacting = true; + await showBottomSheetPill( + context: context, + content: (context, scrollController) => ListView( + controller: scrollController, + shrinkWrap: true, + children: actions.listTileItems(context, useIcons: true), + ), + ); + interacting = false; + timer.reset(); + } + : null, + child: MouseRegion( + onEnter: (event) => setState(() => showControls = true), + onHover: (event) => timer.reset(), + onExit: (event) => setState(() => showControls = false), + child: Stack( + fit: StackFit.expand, + children: [ + Dismissible( + key: Key("Dismissable"), + direction: DismissDirection.horizontal, + onUpdate: (details) { + setState(() { + dragOffset = details.progress * 4; + }); + }, + confirmDismiss: (direction) async { + if (direction == DismissDirection.startToEnd) { + previousSlide(); + } else { + nextSlide(); + } + return false; + }, + child: AnimatedOpacity( + duration: Duration(milliseconds: 125), + opacity: dragOpacity.abs(), + child: AnimatedSwitcher( + duration: Duration(milliseconds: 125), + child: Container( + key: Key(currentItem.id), + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(14), + ), + foregroundDecoration: BoxDecoration( + borderRadius: BorderRadius.circular(14), + border: Border.all( + color: Colors.white.withOpacity(0.10), strokeAlign: BorderSide.strokeAlignInside), + gradient: LinearGradient( + begin: Alignment.bottomLeft, + end: Alignment.topCenter, + colors: [ + overlayColor.withOpacity(1), + overlayColor.withOpacity(0.75), + overlayColor.withOpacity(0.45), + overlayColor.withOpacity(0.15), + overlayColor.withOpacity(0), + overlayColor.withOpacity(0), + overlayColor.withOpacity(0.1), + ], + ), + ), + child: SizedBox( + width: double.infinity, + height: double.infinity, + child: Padding( + padding: const EdgeInsets.all(1), + child: FladderImage( + fit: BoxFit.cover, + image: currentItem.bannerImage, + ), + ), + ), + ), + ), + ), + ), + Row( + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Flexible( + child: IgnorePointer( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Flexible( + child: Text( + currentItem.title, + maxLines: 3, + style: Theme.of(context).textTheme.displaySmall?.copyWith( + shadows: shadows, + color: Colors.white, + ), + ), + ), + if (currentItem.label(context) != null && currentItem is! MovieModel) + Flexible( + child: Text( + currentItem.label(context)!, + maxLines: 3, + style: Theme.of(context).textTheme.titleLarge?.copyWith( + shadows: shadows, + color: Colors.white.withOpacity(0.75), + ), + ), + ), + if (currentItem.overview.summary.isNotEmpty && + AdaptiveLayout.layoutOf(context) != LayoutState.phone) + Flexible( + child: Text( + currentItem.overview.summary, + maxLines: 3, + style: Theme.of(context).textTheme.titleLarge?.copyWith( + shadows: shadows, + color: Colors.white.withOpacity(0.75), + ), + ), + ), + ].addInBetween(SizedBox(height: 6)), + ), + ), + ), + Wrap( + runSpacing: 6, + spacing: 6, + children: [ + if (currentItem.playAble) + MediaPlayButton( + item: currentItem, + onPressed: () async { + await currentItem.play( + context, + ref, + ); + }, + ), + ], + ), + ].addInBetween(SizedBox(height: 16)), + ), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: AnimatedOpacity( + opacity: showControls ? 1 : 0, + duration: Duration(milliseconds: 250), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + IconButton.filledTonal( + onPressed: () => nextSlide(), + icon: Icon(IconsaxOutline.arrow_right_3), + ) + ], + ), + ), + ), + ], + ), + if (AdaptiveLayout.of(context).inputDevice == InputDevice.pointer) + Align( + alignment: Alignment.bottomRight, + child: Padding( + padding: const EdgeInsets.all(16), + child: Card( + child: PopupMenuButton( + onOpened: () => interacting = true, + onCanceled: () { + interacting = false; + timer.reset(); + }, + itemBuilder: (context) => actions.popupMenuItems(useIcons: true), + ), + ), + ), + ), + ], + ), + ), + ), + ), + ), + GestureDetector( + onHorizontalDragUpdate: (details) { + final delta = (details.primaryDelta ?? 0) / 20; + slidePosition += delta; + if (slidePosition > 1) { + nextSlide(); + slidePosition = 0; + } else if (slidePosition < -1) { + previousSlide(); + slidePosition = 0; + } + }, + onHorizontalDragStart: (details) { + slidePosition = 0; + }, + child: Container( + color: Colors.black.withOpacity(0), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Wrap( + alignment: WrapAlignment.center, + crossAxisAlignment: WrapCrossAlignment.center, + runAlignment: WrapAlignment.center, + children: widget.items.mapIndexed((index, e) { + return Tooltip( + message: '${e.name}\n${e.detailedName}', + child: Card( + elevation: 0, + color: Colors.transparent, + child: InkWell( + onTapUp: currentPage == index + ? null + : (details) { + animateToTarget(index); + timer.reset(); + }, + child: Container( + alignment: Alignment.center, + color: Colors.red.withOpacity(0), + width: 28, + height: 28, + child: AnimatedContainer( + duration: Duration(milliseconds: 125), + width: currentItem == e ? 22 : 6, + height: currentItem == e ? 10 : 6, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: currentItem == e + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.primary.withOpacity(0.25), + ), + ), + ), + ), + ), + ); + }).toList(), + ), + ), + ), + ) + ], + ); + } + + void animateToTarget(int nextIndex) { + int step = currentPage < nextIndex ? 1 : -1; + void updateItem(int item) { + Future.delayed(Duration(milliseconds: 64 ~/ ((currentPage - nextIndex).abs() / 3)), () { + setState(() { + currentPage = item; + }); + + if (currentPage != nextIndex) { + updateItem(item + step); + } + }); + timer.reset(); + } + + updateItem(currentPage + step); + } +} diff --git a/lib/screens/shared/media/chapter_row.dart b/lib/screens/shared/media/chapter_row.dart new file mode 100644 index 0000000..754e80a --- /dev/null +++ b/lib/screens/shared/media/chapter_row.dart @@ -0,0 +1,117 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fladder/models/items/chapters_model.dart'; +import 'package:fladder/screens/shared/flat_button.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/disable_keypad_focus.dart'; +import 'package:fladder/util/humanize_duration.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/widgets/shared/horizontal_list.dart'; +import 'package:fladder/widgets/shared/item_actions.dart'; +import 'package:fladder/widgets/shared/modal_bottom_sheet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class ChapterRow extends ConsumerWidget { + final List chapters; + final EdgeInsets contentPadding; + final Function(Chapter)? onPressed; + const ChapterRow({required this.contentPadding, this.onPressed, required this.chapters, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return HorizontalList( + label: context.localized.chapter(chapters.length), + height: AdaptiveLayout.poster(context).size / 1.75, + items: chapters, + itemBuilder: (context, index) { + final chapter = chapters[index]; + List generateActions() { + return [ + ItemActionButton( + action: () => onPressed?.call(chapter), label: Text(context.localized.playFrom(chapter.name))) + ]; + } + + return AspectRatio( + aspectRatio: 1.75, + child: Card( + child: Stack( + children: [ + Positioned.fill( + child: CachedNetworkImage( + imageUrl: chapter.imageUrl, + fit: BoxFit.cover, + ), + ), + Align( + alignment: Alignment.bottomLeft, + child: Padding( + padding: const EdgeInsets.all(5), + child: Card( + elevation: 0, + shadowColor: Colors.transparent, + color: Theme.of(context).cardColor.withOpacity(0.4), + child: Padding( + padding: const EdgeInsets.all(5), + child: Text( + "${chapter.name} \n${chapter.startPosition.humanize ?? context.localized.start}", + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + fontWeight: FontWeight.bold, + shadows: [ + BoxShadow(color: Theme.of(context).cardColor, blurRadius: 6, spreadRadius: 2.0) + ]), + ), + ), + ), + ), + ), + FlatButton( + onSecondaryTapDown: (details) async { + Offset localPosition = details.globalPosition; + RelativeRect position = RelativeRect.fromLTRB( + localPosition.dx - 80, localPosition.dy, localPosition.dx, localPosition.dy); + await showMenu( + context: context, + position: position, + items: generateActions().popupMenuItems(), + ); + }, + onLongPress: () { + showBottomSheetPill( + context: context, + content: (context, scrollController) { + return ListView( + shrinkWrap: true, + controller: scrollController, + children: [ + ...generateActions().listTileItems(context), + ], + ); + }, + ); + }, + ), + if (AdaptiveLayout.of(context).isDesktop) + DisableFocus( + child: Align( + alignment: Alignment.bottomRight, + child: PopupMenuButton( + tooltip: context.localized.options, + icon: const Icon( + Icons.more_vert, + color: Colors.white, + ), + itemBuilder: (context) => generateActions().popupMenuItems(), + ), + ), + ), + ], + ), + ), + ); + }, + contentPadding: contentPadding, + ); + } +} diff --git a/lib/screens/shared/media/components/chip_button.dart b/lib/screens/shared/media/components/chip_button.dart new file mode 100644 index 0000000..e343cd7 --- /dev/null +++ b/lib/screens/shared/media/components/chip_button.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class ChipButton extends ConsumerWidget { + final String label; + final Function()? onPressed; + const ChipButton({required this.label, this.onPressed, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return TextButton( + onPressed: onPressed, + style: TextButton.styleFrom( + backgroundColor: Theme.of(context).colorScheme.surface.withOpacity(0.75), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + side: BorderSide.none, + ), + ), + child: Text( + label, + style: Theme.of(context).textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w600), + ), + ); + } +} diff --git a/lib/screens/shared/media/components/media_header.dart b/lib/screens/shared/media/components/media_header.dart new file mode 100644 index 0000000..cd040c5 --- /dev/null +++ b/lib/screens/shared/media/components/media_header.dart @@ -0,0 +1,53 @@ +import 'package:fladder/models/items/images_models.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/fladder_image.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class MediaHeader extends ConsumerWidget { + final String name; + final ImageData? logo; + const MediaHeader({ + required this.name, + required this.logo, + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final maxWidth = + switch (AdaptiveLayout.layoutOf(context)) { LayoutState.desktop || LayoutState.tablet => 0.55, _ => 1 }; + return Center( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 32), + child: Material( + elevation: 30, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(150)), + shadowColor: Colors.black.withOpacity(0.35), + color: Colors.transparent, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: ConstrainedBox( + constraints: BoxConstraints( + maxHeight: MediaQuery.sizeOf(context).height * 0.2, + maxWidth: MediaQuery.sizeOf(context).width * maxWidth, + ), + child: FladderImage( + image: logo, + enableBlur: true, + frameBuilder: (context, child, frame, wasSynchronouslyLoaded) => Container( + color: Colors.red, + width: 512, + height: 512, + child: child, + ), + placeHolder: const SizedBox(height: 0), + fit: BoxFit.contain, + ), + ), + ), + ), + ), + ); + } +} diff --git a/lib/screens/shared/media/components/media_play_button.dart b/lib/screens/shared/media/components/media_play_button.dart new file mode 100644 index 0000000..ee65090 --- /dev/null +++ b/lib/screens/shared/media/components/media_play_button.dart @@ -0,0 +1,81 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/screens/shared/animated_fade_size.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class MediaPlayButton extends ConsumerWidget { + final ItemBaseModel? item; + final Function()? onPressed; + final Function()? onLongPressed; + const MediaPlayButton({ + required this.item, + this.onPressed, + this.onLongPressed, + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final resume = (item?.progress ?? 0) > 0; + Widget buttonBuilder(bool resume, ButtonStyle? style, Color? textColor) { + return ElevatedButton( + onPressed: onPressed, + onLongPress: onLongPressed, + style: style, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 10), + child: Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Flexible( + child: Text( + item?.playButtonLabel(context) ?? "", + maxLines: 2, + style: Theme.of(context).textTheme.bodyLarge?.copyWith( + fontWeight: FontWeight.bold, + color: textColor, + ), + ), + ), + const SizedBox(width: 4), + const Icon( + IconsaxBold.play, + ), + ], + ), + ), + ); + } + + return AnimatedFadeSize( + duration: const Duration(milliseconds: 250), + child: onPressed != null + ? Stack( + children: [ + buttonBuilder(resume, null, null), + IgnorePointer( + child: ClipRect( + child: Align( + alignment: Alignment.centerLeft, + widthFactor: (item?.progress ?? 0) / 100, + child: buttonBuilder( + resume, + ButtonStyle( + backgroundColor: WidgetStatePropertyAll(Theme.of(context).colorScheme.primary), + foregroundColor: WidgetStatePropertyAll(Theme.of(context).colorScheme.onPrimary), + ), + Theme.of(context).colorScheme.onPrimary, + ), + ), + ), + ), + ], + ) + : Container( + key: UniqueKey(), + ), + ); + } +} diff --git a/lib/screens/shared/media/components/next_up_episode.dart b/lib/screens/shared/media/components/next_up_episode.dart new file mode 100644 index 0000000..2a2adf8 --- /dev/null +++ b/lib/screens/shared/media/components/next_up_episode.dart @@ -0,0 +1,103 @@ +import 'package:fladder/models/items/episode_model.dart'; +import 'package:fladder/providers/sync_provider.dart'; +import 'package:fladder/screens/details_screens/components/media_stream_information.dart'; +import 'package:fladder/screens/shared/media/episode_posters.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/sticky_header_text.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_widget_from_html/flutter_widget_from_html.dart'; + +class NextUpEpisode extends ConsumerWidget { + final EpisodeModel nextEpisode; + final Function(EpisodeModel episode)? onChanged; + const NextUpEpisode({required this.nextEpisode, this.onChanged, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final alreadyPlayed = nextEpisode.userData.played; + return Column( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + StickyHeaderText( + label: alreadyPlayed ? context.localized.reWatch : context.localized.nextUp, + ), + Opacity( + opacity: 0.75, + child: SelectableText( + "${context.localized.season(1)} ${nextEpisode.season} - ${context.localized.episode(1)} ${nextEpisode.episode}", + style: Theme.of(context).textTheme.titleMedium, + ), + ), + SelectableText( + nextEpisode.name, + style: Theme.of(context).textTheme.titleMedium, + ), + const SizedBox(height: 16), + LayoutBuilder( + builder: (context, constraints) { + final syncedItem = ref.read(syncProvider.notifier).getSyncedItem(nextEpisode); + if (constraints.maxWidth < 550) { + return Column( + children: [ + EpisodePoster( + episode: nextEpisode, + syncedItem: syncedItem, + showLabel: false, + onTap: () => nextEpisode.navigateTo(context), + actions: const [], + isCurrentEpisode: false, + ), + const SizedBox(height: 16), + if (nextEpisode.overview.summary.isNotEmpty) + HtmlWidget( + nextEpisode.overview.summary, + textStyle: Theme.of(context).textTheme.titleMedium, + ), + ], + ); + } else { + return Row( + children: [ + ConstrainedBox( + constraints: BoxConstraints( + maxHeight: AdaptiveLayout.poster(context).gridRatio, + maxWidth: MediaQuery.of(context).size.width / 2), + child: EpisodePoster( + episode: nextEpisode, + syncedItem: syncedItem, + showLabel: false, + onTap: () => nextEpisode.navigateTo(context), + actions: const [], + isCurrentEpisode: false, + ), + ), + const SizedBox(width: 32), + Flexible( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + MediaStreamInformation( + mediaStream: nextEpisode.mediaStreams, + onAudioIndexChanged: (index) => onChanged?.call(nextEpisode.copyWith( + mediaStreams: nextEpisode.mediaStreams.copyWith(defaultAudioStreamIndex: index))), + onSubIndexChanged: (index) => onChanged?.call(nextEpisode.copyWith( + mediaStreams: nextEpisode.mediaStreams.copyWith(defaultSubStreamIndex: index))), + ), + if (nextEpisode.overview.summary.isNotEmpty) + HtmlWidget(nextEpisode.overview.summary, textStyle: Theme.of(context).textTheme.titleMedium), + ], + ), + ), + ], + ); + } + }, + ), + ], + ); + } +} diff --git a/lib/screens/shared/media/components/poster_image.dart b/lib/screens/shared/media/components/poster_image.dart new file mode 100644 index 0000000..233e8f5 --- /dev/null +++ b/lib/screens/shared/media/components/poster_image.dart @@ -0,0 +1,428 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/book_model.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/models/items/photos_model.dart'; +import 'package:fladder/models/items/series_model.dart'; +import 'package:fladder/screens/shared/flat_button.dart'; +import 'package:fladder/theme.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/disable_keypad_focus.dart'; +import 'package:fladder/util/fladder_image.dart'; +import 'package:fladder/util/humanize_duration.dart'; +import 'package:fladder/util/item_base_model/item_base_model_extensions.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/refresh_state.dart'; +import 'package:fladder/util/string_extensions.dart'; +import 'package:fladder/widgets/shared/item_actions.dart'; +import 'package:fladder/widgets/shared/modal_bottom_sheet.dart'; +import 'package:fladder/widgets/shared/status_card.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class PosterImage extends ConsumerStatefulWidget { + final ItemBaseModel poster; + final bool heroTag; + final bool? selected; + final ValueChanged? playVideo; + final bool inlineTitle; + final Set excludeActions; + final List otherActions; + final Function(UserData? newData)? onUserDataChanged; + final Function(ItemBaseModel newItem)? onItemUpdated; + final Function(ItemBaseModel oldItem)? onItemRemoved; + final Function(Function() action, ItemBaseModel item)? onPressed; + const PosterImage({ + required this.poster, + this.heroTag = false, + this.selected, + this.playVideo, + this.inlineTitle = false, + this.onItemUpdated, + this.onItemRemoved, + this.excludeActions = const {}, + this.otherActions = const [], + this.onPressed, + this.onUserDataChanged, + super.key, + }); + + @override + ConsumerState createState() => _PosterImageState(); +} + +class _PosterImageState extends ConsumerState { + late String currentTag = widget.heroTag == true ? widget.poster.id : UniqueKey().toString(); + bool hover = false; + + Widget get placeHolder { + return Center( + child: Icon(widget.poster.type.icon), + ); + } + + void pressedWidget() async { + if (widget.heroTag == false) { + setState(() { + currentTag = widget.poster.id; + }); + } + if (widget.onPressed != null) { + widget.onPressed?.call(() async { + await navigateToDetails(); + if (context.mounted) { + context.refreshData(); + } + }, widget.poster); + } else { + await navigateToDetails(); + if (context.mounted) { + context.refreshData(); + } + } + } + + Future navigateToDetails() async { + await widget.poster.navigateTo(context); + } + + @override + Widget build(BuildContext context) { + final poster = widget.poster; + final padding = EdgeInsets.all(5); + return Hero( + tag: currentTag, + child: MouseRegion( + cursor: SystemMouseCursors.click, + onEnter: (event) => setState(() => hover = true), + onExit: (event) => setState(() => hover = false), + child: Card( + elevation: 8, + color: Theme.of(context).colorScheme.secondaryContainer.withOpacity(0.2), + shape: RoundedRectangleBorder( + side: BorderSide( + width: 1.0, + color: Colors.white.withOpacity(0.10), + ), + borderRadius: FladderTheme.defaultShape.borderRadius, + ), + child: Stack( + fit: StackFit.expand, + children: [ + FladderImage( + image: widget.poster.getPosters?.primary ?? widget.poster.getPosters?.backDrop?.lastOrNull, + placeHolder: placeHolder, + ), + if (poster.userData.progress > 0 && widget.poster.type == FladderItemType.book) + Align( + alignment: Alignment.topLeft, + child: Padding( + padding: padding, + child: Card( + child: Padding( + padding: const EdgeInsets.all(5.5), + child: Text( + context.localized.page((widget.poster as BookModel).currentPage), + style: Theme.of(context).textTheme.labelLarge?.copyWith( + fontWeight: FontWeight.bold, + color: Theme.of(context).colorScheme.primary, + fontSize: 12, + ), + ), + ), + ), + ), + ), + if (widget.selected == true) + Container( + decoration: BoxDecoration( + color: Colors.black.withOpacity(0.15), + border: Border.all(width: 3, color: Theme.of(context).colorScheme.primary), + borderRadius: FladderTheme.defaultShape.borderRadius, + ), + clipBehavior: Clip.antiAlias, + child: Stack( + alignment: Alignment.topCenter, + children: [ + Container( + color: Theme.of(context).colorScheme.primary, + width: double.infinity, + child: Padding( + padding: const EdgeInsets.all(2), + child: Text( + widget.poster.name, + maxLines: 2, + textAlign: TextAlign.center, + style: Theme.of(context) + .textTheme + .labelMedium + ?.copyWith(color: Theme.of(context).colorScheme.onPrimary, fontWeight: FontWeight.bold), + ), + ), + ) + ], + ), + ), + Align( + alignment: Alignment.bottomCenter, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + if (widget.poster.userData.isFavourite) + Row( + children: [ + StatusCard( + color: Colors.red, + child: Icon( + IconsaxBold.heart, + size: 21, + color: Colors.red, + ), + ), + ], + ), + if ((poster.userData.progress > 0 && poster.userData.progress < 100) && + widget.poster.type != FladderItemType.book) ...{ + const SizedBox( + height: 4, + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 3).copyWith(bottom: 3).add(padding), + child: Card( + color: Colors.transparent, + elevation: 3, + child: LinearProgressIndicator( + minHeight: 7.5, + backgroundColor: Theme.of(context).colorScheme.onPrimary.withOpacity(0.5), + value: poster.userData.progress / 100, + borderRadius: BorderRadius.circular(2), + ), + ), + ), + }, + ], + ), + ), + //Desktop overlay + if (AdaptiveLayout.of(context).inputDevice != InputDevice.touch && + widget.poster.type != FladderItemType.person) + AnimatedOpacity( + opacity: hover ? 1 : 0, + duration: const Duration(milliseconds: 125), + child: Stack( + fit: StackFit.expand, + children: [ + //Hover color overlay + Container( + decoration: BoxDecoration( + color: Colors.black.withOpacity(0.55), + border: Border.all(width: 3, color: Theme.of(context).colorScheme.primary), + borderRadius: FladderTheme.defaultShape.borderRadius, + )), + //Poster Button + Focus( + onFocusChange: (value) => setState(() => hover = value), + child: FlatButton( + onTap: pressedWidget, + onSecondaryTapDown: (details) async { + Offset localPosition = details.globalPosition; + RelativeRect position = RelativeRect.fromLTRB( + localPosition.dx - 320, localPosition.dy, localPosition.dx, localPosition.dy); + await showMenu( + context: context, + position: position, + items: widget.poster + .generateActions( + context, + ref, + exclude: widget.excludeActions, + otherActions: widget.otherActions, + onUserDataChanged: widget.onUserDataChanged, + onDeleteSuccesFully: widget.onItemRemoved, + onItemUpdated: widget.onItemUpdated, + ) + .popupMenuItems(useIcons: true), + ); + }, + ), + ), + //Play Button + if (widget.poster.playAble) + DisableFocus( + child: Align( + alignment: Alignment.center, + child: IconButton.filledTonal( + onPressed: () => widget.playVideo?.call(false), + icon: const Icon( + IconsaxBold.play, + size: 32, + ), + ), + ), + ), + DisableFocus( + child: Align( + alignment: Alignment.bottomRight, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + PopupMenuButton( + tooltip: "Options", + icon: const Icon( + Icons.more_vert, + color: Colors.white, + ), + itemBuilder: (context) => widget.poster + .generateActions( + context, + ref, + exclude: widget.excludeActions, + otherActions: widget.otherActions, + onUserDataChanged: widget.onUserDataChanged, + onDeleteSuccesFully: widget.onItemRemoved, + onItemUpdated: widget.onItemUpdated, + ) + .popupMenuItems(useIcons: true), + ), + ], + ), + ), + ), + ], + ), + ) + else + Material( + color: Colors.transparent, + child: InkWell( + onTap: pressedWidget, + onLongPress: () { + showBottomSheetPill( + context: context, + item: widget.poster, + content: (scrollContext, scrollController) => ListView( + shrinkWrap: true, + controller: scrollController, + children: widget.poster + .generateActions( + context, + ref, + exclude: widget.excludeActions, + otherActions: widget.otherActions, + onUserDataChanged: widget.onUserDataChanged, + onDeleteSuccesFully: widget.onItemRemoved, + onItemUpdated: widget.onItemUpdated, + ) + .listTileItems(scrollContext, useIcons: true), + ), + ); + }, + ), + ), + if (widget.poster.unWatched) + Align( + alignment: Alignment.topLeft, + child: StatusCard( + color: Colors.amber, + child: Padding( + padding: const EdgeInsets.all(10), + child: Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.amber, + ), + ), + ), + ), + ), + if (widget.inlineTitle) + IgnorePointer( + child: Align( + alignment: Alignment.topLeft, + child: Padding( + padding: const EdgeInsets.all(8), + child: Text( + widget.poster.title.maxLength(limitTo: 25), + style: Theme.of(context) + .textTheme + .labelLarge + ?.copyWith(fontSize: 20, fontWeight: FontWeight.bold, shadows: [ + BoxShadow(blurRadius: 8, spreadRadius: 16), + BoxShadow(blurRadius: 2, spreadRadius: 16), + ]), + ), + ), + ), + ), + if (widget.poster.unPlayedItemCount != null && widget.poster is SeriesModel) + IgnorePointer( + child: Align( + alignment: Alignment.topRight, + child: StatusCard( + color: Theme.of(context).colorScheme.primary, + child: Padding( + padding: const EdgeInsets.all(6), + child: widget.poster.unPlayedItemCount != 0 + ? Container( + constraints: const BoxConstraints(minWidth: 18), + child: Text( + widget.poster.userData.unPlayedItemCount.toString(), + textAlign: TextAlign.center, + style: TextStyle( + color: Theme.of(context).colorScheme.primary, + fontWeight: FontWeight.bold, + overflow: TextOverflow.visible, + fontSize: 14, + ), + ), + ) + : Icon( + Icons.check_rounded, + size: 20, + color: Theme.of(context).colorScheme.primary, + ), + ), + ), + ), + ), + if (widget.poster.overview.runTime != null && + ((widget.poster is PhotoModel) && + (widget.poster as PhotoModel).internalType == FladderItemType.video)) ...{ + Align( + alignment: Alignment.topRight, + child: Padding( + padding: padding, + child: Card( + elevation: 5, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 3), + child: Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + widget.poster.overview.runTime.humanizeSmall ?? "", + style: Theme.of(context).textTheme.bodyLarge?.copyWith( + fontWeight: FontWeight.bold, + color: Theme.of(context).colorScheme.onSurface, + ), + ), + const SizedBox(width: 2), + Icon( + Icons.play_arrow_rounded, + color: Theme.of(context).colorScheme.onSurface, + ), + ], + ), + ), + ), + ), + ) + } + ], + ), + ), + ), + ); + } +} diff --git a/lib/screens/shared/media/components/small_detail_widgets.dart b/lib/screens/shared/media/components/small_detail_widgets.dart new file mode 100644 index 0000000..ecdb4e9 --- /dev/null +++ b/lib/screens/shared/media/components/small_detail_widgets.dart @@ -0,0 +1,95 @@ +import 'package:flutter/material.dart'; + +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/models/items/movie_model.dart'; +import 'package:fladder/screens/shared/media/components/chip_button.dart'; +import 'package:fladder/util/string_extensions.dart'; + +class Ratings extends StatelessWidget { + final double? communityRating; + final String? officialRating; + const Ratings({ + super.key, + this.communityRating, + this.officialRating, + }); + + @override + Widget build(BuildContext context) { + return Row( + children: [ + if (communityRating != null) ...{ + const Icon( + Icons.star_rounded, + color: Colors.yellow, + ), + Text( + communityRating?.toStringAsFixed(1) ?? "", + style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold), + ), + }, + if (officialRating != null) ...{ + Card( + elevation: 0, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: Text( + officialRating ?? "", + style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold), + ), + ), + ), + }, + ], + ); + } +} + +class Tags extends StatelessWidget { + final List tags; + const Tags({ + super.key, + required this.tags, + }); + + @override + Widget build(BuildContext context) { + return Wrap( + runSpacing: 8, + spacing: 8, + children: tags + .map((tag) => ChipButton( + onPressed: () {}, + label: tag.capitalize(), + )) + .toList(), + ); + } +} + +class Genres extends StatelessWidget { + final List genres; + const Genres({ + super.key, + required this.genres, + this.details, + }); + + final MovieModel? details; + + @override + Widget build(BuildContext context) { + return Wrap( + runSpacing: 8, + spacing: 8, + children: genres + .map( + (genre) => ChipButton( + onPressed: null, + label: genre.name.capitalize(), + ), + ) + .toList(), + ); + } +} diff --git a/lib/screens/shared/media/episode_details_list.dart b/lib/screens/shared/media/episode_details_list.dart new file mode 100644 index 0000000..77f8427 --- /dev/null +++ b/lib/screens/shared/media/episode_details_list.dart @@ -0,0 +1,159 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/providers/settings/client_settings_provider.dart'; +import 'package:fladder/providers/sync_provider.dart'; +import 'package:fladder/screens/shared/media/episode_posters.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/item_base_model/item_base_model_extensions.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/models/items/episode_model.dart'; +import 'package:fladder/util/humanize_duration.dart'; + +enum EpisodeDetailsViewType { + list(icon: IconsaxBold.grid_6), + grid(icon: IconsaxBold.grid_2); + + const EpisodeDetailsViewType({required this.icon}); + + String label(BuildContext context) => switch (this) { + EpisodeDetailsViewType.list => context.localized.list, + EpisodeDetailsViewType.grid => context.localized.grid, + }; + + final IconData icon; +} + +class EpisodeDetailsList extends ConsumerWidget { + final EpisodeDetailsViewType viewType; + final List episodes; + final EdgeInsets? padding; + const EpisodeDetailsList({required this.viewType, required this.episodes, this.padding, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final size = MediaQuery.sizeOf(context).width / + ((AdaptiveLayout.poster(context).gridRatio * 2) * + ref.watch(clientSettingsProvider.select((value) => value.posterSize))); + final decimals = size - size.toInt(); + return AnimatedSwitcher( + duration: Duration(milliseconds: 250), + child: switch (viewType) { + EpisodeDetailsViewType.list => ListView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + padding: padding, + itemCount: episodes.length, + itemBuilder: (context, index) { + final episode = episodes[index]; + final syncedItem = ref.watch(syncProvider.notifier).getSyncedItem(episode); + List children = [ + Flexible( + flex: 1, + child: EpisodePoster( + episode: episode, + showLabel: false, + syncedItem: syncedItem, + actions: episode.generateActions(context, ref), + onTap: () => episode.navigateTo(context), + isCurrentEpisode: false, + ), + ), + const SizedBox(width: 16, height: 16), + Flexible( + flex: 3, + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Flexible( + child: Column( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Opacity( + opacity: 0.65, + child: SelectableText( + episode.seasonEpisodeLabel(context), + style: Theme.of(context).textTheme.titleMedium, + ), + ), + if (episode.overview.runTime != null) + Opacity( + opacity: 0.65, + child: SelectableText( + " - ${episode.overview.runTime!.humanize!}", + style: Theme.of(context).textTheme.titleMedium, + ), + ), + ], + ), + SelectableText( + episode.name, + style: Theme.of(context).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.bold), + ), + SelectableText( + episode.overview.summary, + style: Theme.of(context).textTheme.bodyMedium, + ), + ].addPadding(const EdgeInsets.symmetric(vertical: 4)), + ), + ), + ], + ), + ), + const SizedBox(height: 16), + ]; + return LayoutBuilder( + builder: (context, constraints) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: Card( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: constraints.maxWidth > 800 + ? Row( + mainAxisSize: MainAxisSize.min, + children: children, + ) + : Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: children, + ), + ), + ), + ); + }, + ); + }, + ), + EpisodeDetailsViewType.grid => GridView.builder( + shrinkWrap: true, + padding: padding, + physics: const NeverScrollableScrollPhysics(), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: size.toInt(), + mainAxisSpacing: (8 * decimals) + 8, + crossAxisSpacing: (8 * decimals) + 8, + childAspectRatio: 1.67), + itemCount: episodes.length, + itemBuilder: (context, index) { + final episode = episodes[index]; + return EpisodePoster( + episode: episode, + actions: episode.generateActions(context, ref), + onTap: () => episode.navigateTo(context), + isCurrentEpisode: false, + ); + }, + ) + }, + ); + } +} diff --git a/lib/screens/shared/media/episode_posters.dart b/lib/screens/shared/media/episode_posters.dart new file mode 100644 index 0000000..8f3d5ae --- /dev/null +++ b/lib/screens/shared/media/episode_posters.dart @@ -0,0 +1,306 @@ +import 'package:fladder/models/items/episode_model.dart'; +import 'package:fladder/models/syncing/sync_item.dart'; +import 'package:fladder/providers/settings/client_settings_provider.dart'; +import 'package:fladder/providers/sync/sync_provider_helpers.dart'; +import 'package:fladder/providers/sync_provider.dart'; +import 'package:fladder/screens/shared/flat_button.dart'; +import 'package:fladder/screens/syncing/sync_button.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/disable_keypad_focus.dart'; +import 'package:fladder/util/fladder_image.dart'; +import 'package:fladder/util/item_base_model/item_base_model_extensions.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/widgets/shared/clickable_text.dart'; +import 'package:fladder/widgets/shared/enum_selection.dart'; +import 'package:fladder/widgets/shared/horizontal_list.dart'; +import 'package:fladder/widgets/shared/item_actions.dart'; +import 'package:fladder/widgets/shared/modal_bottom_sheet.dart'; +import 'package:fladder/widgets/shared/status_card.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class EpisodePosters extends ConsumerStatefulWidget { + final List episodes; + final String? label; + final ValueChanged playEpisode; + final EdgeInsets contentPadding; + final Function(VoidCallback action, EpisodeModel episodeModel)? onEpisodeTap; + const EpisodePosters({ + this.label, + required this.contentPadding, + required this.playEpisode, + required this.episodes, + this.onEpisodeTap, + super.key, + }); + + @override + ConsumerState createState() => _EpisodePosterState(); +} + +class _EpisodePosterState extends ConsumerState { + late int? selectedSeason = widget.episodes.nextUp?.season; + + List get episodes { + if (selectedSeason == null) { + return widget.episodes; + } else { + return widget.episodes.where((element) => element.season == selectedSeason).toList(); + } + } + + @override + Widget build(BuildContext context) { + final indexOfCurrent = (episodes.nextUp != null ? episodes.indexOf(episodes.nextUp!) : 0).clamp(0, episodes.length); + final episodesBySeason = widget.episodes.episodesBySeason; + final allPlayed = episodes.allPlayed; + + return HorizontalList( + label: widget.label, + titleActions: [ + if (episodesBySeason.isNotEmpty && episodesBySeason.length > 1) ...{ + SizedBox(width: 12), + EnumBox( + current: selectedSeason != null ? "${context.localized.season(1)} $selectedSeason" : context.localized.all, + itemBuilder: (context) => [ + PopupMenuItem( + child: Text(context.localized.all), + onTap: () => setState(() => selectedSeason = null), + ), + ...episodesBySeason.entries.map( + (e) => PopupMenuItem( + child: Text("${context.localized.season(1)} ${e.key}"), + onTap: () { + setState(() => selectedSeason = e.key); + }, + ), + ) + ], + ) + }, + ], + height: AdaptiveLayout.poster(context).gridRatio, + contentPadding: widget.contentPadding, + startIndex: indexOfCurrent, + items: episodes, + itemBuilder: (context, index) { + final episode = episodes[index]; + final isCurrentEpisode = index == indexOfCurrent; + final syncedItem = ref.watch(syncProvider.notifier).getSyncedItem(episode); + return EpisodePoster( + episode: episode, + blur: allPlayed ? false : indexOfCurrent < index, + syncedItem: syncedItem, + onTap: widget.onEpisodeTap != null + ? () { + widget.onEpisodeTap?.call( + () { + episode.navigateTo(context); + }, + episode, + ); + } + : () { + episode.navigateTo(context); + }, + onLongPress: () { + showBottomSheetPill( + context: context, + item: episode, + content: (context, scrollController) { + return ListView( + shrinkWrap: true, + controller: scrollController, + children: [ + ...episode.generateActions(context, ref).listTileItems(context, useIcons: true), + ], + ); + }, + ); + }, + actions: episode.generateActions(context, ref), + isCurrentEpisode: isCurrentEpisode, + ); + }, + ); + } +} + +class EpisodePoster extends ConsumerWidget { + final EpisodeModel episode; + final SyncedItem? syncedItem; + final bool showLabel; + final Function()? onTap; + final Function()? onLongPress; + final bool blur; + final List actions; + final bool isCurrentEpisode; + + const EpisodePoster({ + super.key, + required this.episode, + this.syncedItem, + this.showLabel = true, + this.onTap, + this.onLongPress, + this.blur = false, + required this.actions, + required this.isCurrentEpisode, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + Widget placeHolder = Container( + color: Theme.of(context).colorScheme.surfaceContainerHighest, + child: const Icon(Icons.local_movies_outlined), + ); + final SyncedItem? iSyncedItem = syncedItem; + bool episodeAvailable = episode.status == EpisodeStatus.available; + return AspectRatio( + aspectRatio: 1.76, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Flexible( + child: Card( + child: Stack( + fit: StackFit.expand, + children: [ + FladderImage( + image: switch (episode.status) { + EpisodeStatus.unaired || EpisodeStatus.missing => episode.parentImages?.primary, + _ => episode.images?.primary + }, + placeHolder: placeHolder, + blurOnly: + ref.watch(clientSettingsProvider.select((value) => value.blurUpcomingEpisodes)) ? blur : false, + ), + if (!episodeAvailable) + Align( + alignment: Alignment.bottomLeft, + child: Padding( + padding: const EdgeInsets.all(8), + child: Card( + color: Theme.of(context).colorScheme.errorContainer, + elevation: 3, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + episode.status.name, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: Theme.of(context).colorScheme.onErrorContainer, fontWeight: FontWeight.bold), + ), + ), + ), + ), + ), + Align( + alignment: Alignment.topRight, + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + if (iSyncedItem != null) + Consumer(builder: (context, ref, child) { + final SyncStatus syncStatus = + ref.watch(syncStatusesProvider(iSyncedItem)).value ?? SyncStatus.partially; + return StatusCard( + color: syncStatus.color, + child: SyncButton(item: episode, syncedItem: syncedItem), + ); + }), + if (episode.userData.isFavourite) + StatusCard( + color: Colors.red, + child: Icon( + Icons.favorite_rounded, + ), + ), + if (episode.userData.played) + StatusCard( + color: Theme.of(context).colorScheme.primary, + child: Icon( + Icons.check_rounded, + ), + ), + ], + ), + ), + if ((episode.userData.progress) > 0) + Align( + alignment: Alignment.bottomCenter, + child: LinearProgressIndicator( + minHeight: 6, + backgroundColor: Colors.black.withOpacity(0.75), + value: episode.userData.progress / 100, + ), + ), + LayoutBuilder( + builder: (context, constraints) { + return FlatButton( + onSecondaryTapDown: (details) { + Offset localPosition = details.globalPosition; + RelativeRect position = RelativeRect.fromLTRB( + localPosition.dx - 260, localPosition.dy, localPosition.dx, localPosition.dy); + + showMenu(context: context, position: position, items: actions.popupMenuItems(useIcons: true)); + }, + onTap: onTap, + onLongPress: onLongPress, + ); + }, + ), + if (AdaptiveLayout.of(context).inputDevice == InputDevice.pointer && actions.isNotEmpty) + DisableFocus( + child: Align( + alignment: Alignment.bottomRight, + child: PopupMenuButton( + tooltip: "Options", + icon: Icon( + Icons.more_vert, + color: Colors.white, + shadows: [ + Shadow(color: Colors.black.withOpacity(0.45), blurRadius: 8.0), + const Shadow(color: Colors.black, blurRadius: 16.0), + const Shadow(color: Colors.black, blurRadius: 32.0), + const Shadow(color: Colors.black, blurRadius: 64.0), + ], + ), + itemBuilder: (context) => actions.popupMenuItems(useIcons: true), + ), + ), + ), + ], + ), + ), + ), + if (showLabel) ...{ + const SizedBox(height: 4), + Row( + children: [ + if (isCurrentEpisode) + Padding( + padding: const EdgeInsets.only(right: 4), + child: Container( + height: 12, + width: 12, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Theme.of(context).colorScheme.primary, + ), + ), + ), + Flexible( + child: ClickableText( + text: episode.episodeLabel(context), + maxLines: 1, + ), + ), + ], + ), + } + ], + ), + ); + } +} diff --git a/lib/screens/shared/media/expanding_overview.dart b/lib/screens/shared/media/expanding_overview.dart new file mode 100644 index 0000000..1567e02 --- /dev/null +++ b/lib/screens/shared/media/expanding_overview.dart @@ -0,0 +1,84 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/sticky_header_text.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_widget_from_html/flutter_widget_from_html.dart'; + +class ExpandingOverview extends ConsumerStatefulWidget { + final String text; + const ExpandingOverview({required this.text, super.key}); + + @override + ConsumerState createState() => _ExpandingOverviewState(); +} + +class _ExpandingOverviewState extends ConsumerState { + bool expanded = false; + + void toggleState() { + setState(() { + expanded = !expanded; + }); + } + + @override + Widget build(BuildContext context) { + final color = Theme.of(context).colorScheme.onSurface; + const int maxLength = 200; + final bool canExpand = widget.text.length > maxLength; + return AnimatedSize( + duration: const Duration(milliseconds: 250), + alignment: Alignment.topCenter, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + StickyHeaderText( + label: context.localized.overview, + ), + ShaderMask( + shaderCallback: (bounds) => LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + stops: const [0, 1], + colors: [ + color, + color.withOpacity(!canExpand + ? 1 + : expanded + ? 1 + : 0), + ], + ).createShader(bounds), + child: HtmlWidget( + widget.text.substring(0, !expanded ? maxLength.clamp(0, widget.text.length) : widget.text.length - 1), + textStyle: Theme.of(context).textTheme.bodyLarge, + ), + ), + if (canExpand) ...{ + const SizedBox(height: 16), + Align( + alignment: Alignment.center, + child: Transform.translate( + offset: Offset(0, expanded ? 0 : -15), + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 250), + child: expanded + ? IconButton.filledTonal( + onPressed: toggleState, + icon: const Icon(IconsaxOutline.arrow_up_2), + ) + : IconButton.filledTonal( + onPressed: toggleState, + icon: const Icon(IconsaxOutline.arrow_down_1), + ), + ), + ), + ), + }, + ], + ), + ); + } +} diff --git a/lib/screens/shared/media/external_urls.dart b/lib/screens/shared/media/external_urls.dart new file mode 100644 index 0000000..719921b --- /dev/null +++ b/lib/screens/shared/media/external_urls.dart @@ -0,0 +1,68 @@ +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_custom_tabs/flutter_custom_tabs.dart' as customtab; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:url_launcher/url_launcher.dart' as urllauncher; +import 'package:url_launcher/url_launcher_string.dart'; + +class ExternalUrlsRow extends ConsumerWidget { + final List? urls; + const ExternalUrlsRow({ + this.urls, + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Wrap( + children: urls + ?.map( + (url) => TextButton( + onPressed: () => launchUrl(context, url.url), + child: Text(url.name), + ), + ) + .toList() ?? + [], + ); + } +} + +Future launchUrl(BuildContext context, String link) async { + final Uri url = Uri.parse(link); + + if (AdaptiveLayout.of(context).isDesktop) { + if (!await urllauncher.launchUrl(url, mode: LaunchMode.externalApplication)) { + throw Exception('Could not launch $url'); + } + } else { + try { + await customtab.launch( + link, + customTabsOption: customtab.CustomTabsOption( + toolbarColor: Theme.of(context).primaryColor, + enableDefaultShare: true, + enableUrlBarHiding: true, + showPageTitle: true, + extraCustomTabs: const [ + // ref. https://play.google.com/store/apps/details?id=org.mozilla.firefox + 'org.mozilla.firefox', + // ref. https://play.google.com/store/apps/details?id=com.microsoft.emmx + 'com.microsoft.emmx', + ], + ), + safariVCOption: customtab.SafariViewControllerOption( + preferredBarTintColor: Theme.of(context).primaryColor, + preferredControlTintColor: Colors.white, + barCollapsingEnabled: true, + entersReaderIfAvailable: false, + dismissButtonStyle: customtab.SafariViewControllerDismissButtonStyle.close, + ), + ); + } catch (e) { + // An exception is thrown if browser app is not installed on Android device. + debugPrint(e.toString()); + } + } +} diff --git a/lib/screens/shared/media/item_detail_list_widget.dart b/lib/screens/shared/media/item_detail_list_widget.dart new file mode 100644 index 0000000..9b5e4f6 --- /dev/null +++ b/lib/screens/shared/media/item_detail_list_widget.dart @@ -0,0 +1,110 @@ +import 'package:fladder/util/fladder_image.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/screens/shared/flat_button.dart'; +import 'package:fladder/util/duration_extensions.dart'; + +class ItemDetailListWidget extends ConsumerStatefulWidget { + final ItemBaseModel item; + final Widget? iconOverlay; + final double elevation; + final List actions; + const ItemDetailListWidget( + {super.key, required this.item, this.iconOverlay, this.elevation = 1, this.actions = const []}); + + @override + ConsumerState createState() => _ItemDetailListWidgetState(); +} + +class _ItemDetailListWidgetState extends ConsumerState { + bool showImageOverlay = false; + @override + Widget build(BuildContext context) { + return Card( + elevation: widget.elevation, + margin: EdgeInsets.zero, + clipBehavior: Clip.antiAlias, + child: Stack( + children: [ + FlatButton( + onTap: () {}, + ), + Padding( + padding: const EdgeInsets.only(right: 32), + child: Row( + children: [ + MouseRegion( + onEnter: (event) => setState(() => showImageOverlay = true), + onExit: (event) => setState(() => showImageOverlay = false), + child: Stack( + children: [ + FladderImage(image: widget.item.images?.primary), + if (widget.item.subTextShort(context) != null) + Card( + child: Padding( + padding: const EdgeInsets.all(7), + child: Text( + widget.item.subTextShort(context) ?? "", + style: Theme.of(context).textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.bold), + ), + ), + ), + if (widget.iconOverlay != null) + Positioned.fill( + child: AnimatedOpacity( + opacity: showImageOverlay ? 1 : 0, + duration: const Duration(milliseconds: 250), + child: widget.iconOverlay!, + ), + ), + ], + ), + ), + Expanded( + child: IgnorePointer( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.max, + children: [ + Column( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.item.name, + style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold), + ), + ], + ), + const SizedBox(height: 8), + Expanded( + child: Opacity( + opacity: 0.65, + child: Text( + widget.item.overview.summary, + overflow: TextOverflow.fade, + ), + ), + ), + ], + ), + ), + ), + ), + ...widget.actions, + if (widget.item.overview.runTime != null) + Opacity(opacity: 0.65, child: Text(widget.item.overview.runTime?.readAbleDuration ?? "")), + const VerticalDivider(), + ], + ), + ), + ], + ), + ); + } +} diff --git a/lib/screens/shared/media/people_row.dart b/lib/screens/shared/media/people_row.dart new file mode 100644 index 0000000..60870d7 --- /dev/null +++ b/lib/screens/shared/media/people_row.dart @@ -0,0 +1,99 @@ +import 'package:animations/animations.dart'; +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/screens/details_screens/person_detail_screen.dart'; +import 'package:fladder/screens/shared/flat_button.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/fladder_image.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/string_extensions.dart'; +import 'package:fladder/widgets/shared/clickable_text.dart'; +import 'package:fladder/widgets/shared/horizontal_list.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class PeopleRow extends ConsumerWidget { + final List people; + final EdgeInsets contentPadding; + const PeopleRow({required this.people, required this.contentPadding, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + Widget placeHolder(String name) { + return Card( + child: FractionallySizedBox( + widthFactor: 0.4, + child: Card( + elevation: 5, + shape: const CircleBorder(), + child: Center( + child: Text( + name.getInitials(), + style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold), + )), + ), + ), + ); + } + + return HorizontalList( + label: context.localized.actor(people.length), + height: AdaptiveLayout.poster(context).size * 0.9, + contentPadding: contentPadding, + items: people, + itemBuilder: (context, index) { + final person = people[index]; + return AspectRatio( + aspectRatio: 0.6, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Flexible( + child: OpenContainer( + closedColor: Colors.transparent, + closedElevation: 5, + openElevation: 0, + closedShape: const RoundedRectangleBorder(), + transitionType: ContainerTransitionType.fadeThrough, + openColor: Colors.transparent, + tappable: false, + closedBuilder: (context, action) => Stack( + children: [ + Positioned.fill( + child: Card( + child: FladderImage( + image: person.image, + placeHolder: placeHolder(person.name), + fit: BoxFit.cover, + ), + ), + ), + FlatButton(onTap: () => action()), + ], + ), + openBuilder: (context, action) => PersonDetailScreen( + person: person, + ), + ), + ), + const SizedBox(height: 4), + ClickableText( + text: person.name, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.titleSmall?.copyWith(fontWeight: FontWeight.bold), + ), + const SizedBox(height: 4), + ClickableText( + opacity: 0.45, + text: person.role, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.titleSmall?.copyWith(fontSize: 13, fontWeight: FontWeight.bold), + ), + ], + ), + ); + }, + ); + } +} diff --git a/lib/screens/shared/media/person_list_.dart b/lib/screens/shared/media/person_list_.dart new file mode 100644 index 0000000..30d9788 --- /dev/null +++ b/lib/screens/shared/media/person_list_.dart @@ -0,0 +1,38 @@ +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/screens/details_screens/details_screens.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class PersonList extends ConsumerWidget { + final String label; + final List people; + final ValueChanged? onPersonTap; + const PersonList({required this.label, required this.people, this.onPersonTap, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Wrap( + crossAxisAlignment: WrapCrossAlignment.center, + spacing: 16, + runSpacing: 16, + children: [ + Text( + label, + style: Theme.of(context).textTheme.titleMedium, + ), + ...people + .map((person) => TextButton( + onPressed: + onPersonTap != null ? () => onPersonTap?.call(person) : () => openPersonDetailPage(context, person), + child: Text(person.name))) + + ], + ); + } + + void openPersonDetailPage(BuildContext context, Person person) { + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => PersonDetailScreen(person: person), + )); + } +} diff --git a/lib/screens/shared/media/poster_grid.dart b/lib/screens/shared/media/poster_grid.dart new file mode 100644 index 0000000..cce4cd1 --- /dev/null +++ b/lib/screens/shared/media/poster_grid.dart @@ -0,0 +1,71 @@ +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/providers/settings/client_settings_provider.dart'; +import 'package:fladder/screens/shared/media/poster_widget.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/sticky_header_text.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:sticky_headers/sticky_headers.dart'; + +class PosterGrid extends ConsumerWidget { + final String? name; + final List posters; + final Widget? Function(BuildContext context, int index)? itemBuilder; + final bool stickyHeader; + final Function(VoidCallback action, ItemBaseModel item)? onPressed; + const PosterGrid( + {this.stickyHeader = true, this.itemBuilder, this.name, required this.posters, this.onPressed, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final size = MediaQuery.sizeOf(context).width / + (AdaptiveLayout.poster(context).gridRatio * + ref.watch(clientSettingsProvider.select((value) => value.posterSize))); + final decimals = size - size.toInt(); + var posterBuilder = GridView.builder( + shrinkWrap: true, + padding: EdgeInsets.zero, + physics: const NeverScrollableScrollPhysics(), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: size.toInt(), + mainAxisSpacing: (8 * decimals) + 8, + crossAxisSpacing: (8 * decimals) + 8, + childAspectRatio: AdaptiveLayout.poster(context).ratio, + ), + itemCount: posters.length, + itemBuilder: itemBuilder ?? + (context, index) { + return PosterWidget( + poster: posters[index], + onPressed: onPressed, + ); + }, + ); + + if (stickyHeader) { + //Translate fixes small peaking pixel line + return StickyHeader( + header: name != null + ? StickyHeaderText(label: name ?? "") + : const SizedBox( + height: 16, + ), + content: posterBuilder, + ); + } else { + return Column( + children: [ + Container( + width: double.infinity, + padding: const EdgeInsets.symmetric(vertical: 16), + child: Text( + name ?? "", + style: Theme.of(context).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.bold), + ), + ), + posterBuilder, + ], + ); + } + } +} diff --git a/lib/screens/shared/media/poster_list_item.dart b/lib/screens/shared/media/poster_list_item.dart new file mode 100644 index 0000000..b82ac6f --- /dev/null +++ b/lib/screens/shared/media/poster_list_item.dart @@ -0,0 +1,218 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/book_model.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/providers/settings/client_settings_provider.dart'; +import 'package:fladder/screens/shared/flat_button.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/fladder_image.dart'; +import 'package:fladder/util/item_base_model/item_base_model_extensions.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/widgets/shared/clickable_text.dart'; +import 'package:fladder/widgets/shared/item_actions.dart'; +import 'package:fladder/widgets/shared/modal_bottom_sheet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class PosterListItem extends ConsumerWidget { + final ItemBaseModel poster; + final bool? selected; + final Widget? subTitle; + final Set excludeActions; + final List otherActions; + + // Useful for intercepting button press + final Function(VoidCallback action, ItemBaseModel item)? onPressed; + final Function(String id, UserData? newData)? onUserDataChanged; + final Function(ItemBaseModel newItem)? onItemUpdated; + final Function(ItemBaseModel oldItem)? onItemRemoved; + + const PosterListItem({ + super.key, + this.selected, + this.subTitle, + this.excludeActions = const {}, + this.otherActions = const [], + required this.poster, + this.onPressed, + this.onItemUpdated, + this.onItemRemoved, + this.onUserDataChanged, + }); + + void pressedWidget(BuildContext context) { + if (onPressed != null) { + onPressed?.call(() { + poster.navigateTo(context); + }, poster); + } else { + poster.navigateTo(context); + } + } + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Padding( + padding: EdgeInsets.symmetric(vertical: 2), + child: Card( + color: Theme.of(context).colorScheme.surface, + child: SizedBox( + height: 75 * ref.read(clientSettingsProvider.select((value) => value.posterSize)), + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.primary.withOpacity(selected == true ? 0.25 : 0), + borderRadius: BorderRadius.circular(6), + ), + child: FlatButton( + onTap: () => pressedWidget(context), + onSecondaryTapDown: (details) async { + Offset localPosition = details.globalPosition; + RelativeRect position = + RelativeRect.fromLTRB(localPosition.dx - 320, localPosition.dy, localPosition.dx, localPosition.dy); + await showMenu( + context: context, + position: position, + items: poster + .generateActions( + context, + ref, + exclude: excludeActions, + otherActions: otherActions, + onUserDataChanged: (newData) => onUserDataChanged?.call(poster.id, newData), + onDeleteSuccesFully: onItemRemoved, + onItemUpdated: onItemUpdated, + ) + .popupMenuItems(useIcons: true), + ); + }, + onLongPress: () { + showBottomSheetPill( + context: context, + item: poster, + content: (scrollContext, scrollController) => ListView( + shrinkWrap: true, + controller: scrollController, + children: poster + .generateActions( + context, + ref, + exclude: excludeActions, + otherActions: otherActions, + onUserDataChanged: (newData) => onUserDataChanged?.call(poster.id, newData), + onDeleteSuccesFully: onItemRemoved, + onItemUpdated: onItemUpdated, + ) + .listTileItems(scrollContext, useIcons: true), + ), + ); + }, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 6), + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: AspectRatio( + aspectRatio: 1.0, + child: Hero( + tag: poster.id, + child: Card( + margin: EdgeInsets.zero, + child: FladderImage( + image: poster.getPosters?.primary ?? poster.getPosters?.backDrop?.lastOrNull, + ), + ), + ), + ), + ), + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + poster.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + if ((poster.subText ?? poster.subTextShort(context))?.isNotEmpty == true) + Opacity( + opacity: 0.45, + child: Text( + poster.subText ?? poster.subTextShort(context) ?? "", + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ), + Row( + children: [ + if (subTitle != null) ...[ + subTitle!, + Spacer(), + ], + if (poster.subText != null && poster.subText != poster.name) + ClickableText( + opacity: 0.45, + text: poster.subText!, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.titleSmall?.copyWith(fontWeight: FontWeight.bold), + ), + ], + ), + ], + ), + ), + if (poster.type == FladderItemType.book) + if (poster.userData.progress > 0) + Card( + color: Theme.of(context).colorScheme.primary, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + child: Text( + context.localized.page((poster as BookModel).currentPage), + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + fontWeight: FontWeight.bold, color: Theme.of(context).colorScheme.onPrimary), + ), + ), + ), + if (poster.userData.isFavourite) + Icon( + IconsaxBold.heart, + color: Colors.red, + ), + if (AdaptiveLayout.of(context).isDesktop) + Tooltip( + message: context.localized.options, + child: PopupMenuButton( + tooltip: context.localized.options, + icon: const Icon( + Icons.more_vert, + color: Colors.white, + ), + itemBuilder: (context) => poster + .generateActions( + context, + ref, + exclude: excludeActions, + otherActions: otherActions, + onUserDataChanged: (newData) => onUserDataChanged?.call(poster.id, newData), + onDeleteSuccesFully: onItemRemoved, + onItemUpdated: onItemUpdated, + ) + .popupMenuItems(useIcons: true), + ), + ) + ].addInBetween(SizedBox(width: 8)), + ), + ), + ), + ), + ), + ), + ); + } +} diff --git a/lib/screens/shared/media/poster_row.dart b/lib/screens/shared/media/poster_row.dart new file mode 100644 index 0000000..41a907e --- /dev/null +++ b/lib/screens/shared/media/poster_row.dart @@ -0,0 +1,49 @@ +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/screens/shared/media/poster_widget.dart'; +import 'package:fladder/widgets/shared/horizontal_list.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class PosterRow extends ConsumerStatefulWidget { + final List posters; + final String label; + final Function()? onLabelClick; + final EdgeInsets contentPadding; + const PosterRow({ + required this.posters, + this.contentPadding = const EdgeInsets.symmetric(horizontal: 16), + required this.label, + this.onLabelClick, + super.key, + }); + + @override + ConsumerState createState() => _PosterRowState(); +} + +class _PosterRowState extends ConsumerState { + late final controller = ScrollController(); + + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return HorizontalList( + contentPadding: widget.contentPadding, + label: widget.label, + onLabelClick: widget.onLabelClick, + items: widget.posters, + itemBuilder: (context, index) { + final poster = widget.posters[index]; + return PosterWidget( + poster: poster, + key: Key(poster.id), + ); + }, + ); + } +} diff --git a/lib/screens/shared/media/poster_widget.dart b/lib/screens/shared/media/poster_widget.dart new file mode 100644 index 0000000..da484e6 --- /dev/null +++ b/lib/screens/shared/media/poster_widget.dart @@ -0,0 +1,127 @@ +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/screens/shared/media/components/poster_image.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/item_base_model/item_base_model_extensions.dart'; +import 'package:fladder/util/item_base_model/play_item_helpers.dart'; +import 'package:fladder/widgets/shared/clickable_text.dart'; +import 'package:fladder/widgets/shared/item_actions.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class PosterWidget extends ConsumerWidget { + final ItemBaseModel poster; + final Widget? subTitle; + final bool? selected; + final bool? heroTag; + final int maxLines; + final double? aspectRatio; + final bool inlineTitle; + final Set excludeActions; + final List otherActions; + final Function(String id, UserData? newData)? onUserDataChanged; + final Function(ItemBaseModel newItem)? onItemUpdated; + final Function(ItemBaseModel oldItem)? onItemRemoved; + final Function(VoidCallback action, ItemBaseModel item)? onPressed; + const PosterWidget( + {required this.poster, + this.subTitle, + this.maxLines = 3, + this.selected, + this.heroTag, + this.aspectRatio, + this.inlineTitle = false, + this.excludeActions = const {}, + this.otherActions = const [], + this.onUserDataChanged, + this.onItemUpdated, + this.onItemRemoved, + this.onPressed, + super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final opacity = 0.65; + return AspectRatio( + aspectRatio: aspectRatio ?? AdaptiveLayout.poster(context).ratio, + child: Column( + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: PosterImage( + poster: poster, + heroTag: heroTag ?? false, + selected: selected, + playVideo: (value) async => await poster.play(context, ref), + inlineTitle: inlineTitle, + excludeActions: excludeActions, + otherActions: otherActions, + onUserDataChanged: (newData) => onUserDataChanged?.call(poster.id, newData), + onItemRemoved: onItemRemoved, + onItemUpdated: onItemUpdated, + onPressed: onPressed, + ), + ), + if (!inlineTitle) + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Flexible( + child: ClickableText( + onTap: AdaptiveLayout.of(context).layout != LayoutState.phone + ? () => poster.parentBaseModel.navigateTo(context) + : null, + text: poster.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold), + ), + ), + Row( + children: [ + if (subTitle != null) ...[ + Opacity( + opacity: opacity, + child: subTitle!, + ), + Spacer() + ], + if (poster.subText?.isNotEmpty ?? false) + Flexible( + child: ClickableText( + opacity: opacity, + text: poster.subText ?? "", + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.titleSmall?.copyWith(fontWeight: FontWeight.bold), + ), + ) + else + Flexible( + child: ClickableText( + opacity: opacity, + text: poster.subTextShort(context) ?? "", + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.titleSmall?.copyWith(fontWeight: FontWeight.bold), + ), + ), + ], + ), + Flexible( + child: ClickableText( + opacity: opacity, + text: poster.subText?.isNotEmpty ?? false ? poster.subTextShort(context) ?? "" : "", + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.titleSmall?.copyWith(fontWeight: FontWeight.bold), + ), + ), + ].take(maxLines).toList(), + ), + ], + ), + ); + } +} diff --git a/lib/screens/shared/media/season_row.dart b/lib/screens/shared/media/season_row.dart new file mode 100644 index 0000000..566b786 --- /dev/null +++ b/lib/screens/shared/media/season_row.dart @@ -0,0 +1,186 @@ +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/disable_keypad_focus.dart'; +import 'package:fladder/util/fladder_image.dart'; +import 'package:fladder/util/item_base_model/item_base_model_extensions.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/widgets/shared/item_actions.dart'; +import 'package:fladder/widgets/shared/modal_bottom_sheet.dart'; +import 'package:fladder/widgets/shared/status_card.dart'; +import 'package:flutter/material.dart'; + +import 'package:fladder/models/items/season_model.dart'; +import 'package:fladder/screens/shared/flat_button.dart'; +import 'package:fladder/widgets/shared/clickable_text.dart'; +import 'package:fladder/widgets/shared/horizontal_list.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class SeasonsRow extends ConsumerWidget { + final EdgeInsets contentPadding; + final ValueChanged? onSeasonPressed; + final List? seasons; + + const SeasonsRow({ + super.key, + this.onSeasonPressed, + required this.seasons, + this.contentPadding = const EdgeInsets.symmetric(horizontal: 16), + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return HorizontalList( + label: context.localized.season(seasons?.length ?? 1), + items: seasons ?? [], + height: AdaptiveLayout.poster(context).size, + contentPadding: contentPadding, + itemBuilder: ( + context, + index, + ) { + final season = (seasons ?? [])[index]; + return SeasonPoster( + season: season, + onSeasonPressed: onSeasonPressed, + ); + }, + ); + } +} + +class SeasonPoster extends ConsumerWidget { + final SeasonModel season; + final ValueChanged? onSeasonPressed; + + const SeasonPoster({required this.season, this.onSeasonPressed, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + placeHolder(String title) { + return Padding( + padding: const EdgeInsets.all(4), + child: Container( + child: Card( + color: Theme.of(context).colorScheme.surface.withOpacity(0.65), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12), + child: Text( + title, + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.titleMedium, + ), + ), + ), + ), + ); + } + + return AspectRatio( + aspectRatio: 0.6, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + child: Card( + child: Stack( + children: [ + Positioned.fill( + child: FladderImage( + image: season.getPosters?.primary ?? + season.parentImages?.backDrop?.firstOrNull ?? + season.parentImages?.primary, + placeHolder: placeHolder(season.name), + ), + ), + if (season.images?.primary == null) + Align( + alignment: Alignment.topLeft, + child: placeHolder(season.name), + ), + if (season.userData.unPlayedItemCount != 0) + Align( + alignment: Alignment.topRight, + child: StatusCard( + color: Theme.of(context).colorScheme.primary, + child: Center( + child: Text( + season.userData.unPlayedItemCount.toString(), + style: TextStyle(fontWeight: FontWeight.w700, fontSize: 14), + ), + ), + ), + ) + else + Align( + alignment: Alignment.topRight, + child: StatusCard( + color: Theme.of(context).colorScheme.primary, + child: Icon( + Icons.check_rounded, + ), + ), + ), + LayoutBuilder( + builder: (context, constraints) { + return FlatButton( + onSecondaryTapDown: (details) { + Offset localPosition = details.globalPosition; + RelativeRect position = RelativeRect.fromLTRB( + localPosition.dx - 260, localPosition.dy, localPosition.dx, localPosition.dy); + showMenu( + context: context, + position: position, + items: season.generateActions(context, ref).popupMenuItems(useIcons: true)); + }, + onTap: () => onSeasonPressed?.call(season), + onLongPress: AdaptiveLayout.of(context).inputDevice != InputDevice.touch + ? () { + showBottomSheetPill( + context: context, + content: (context, scrollController) => ListView( + shrinkWrap: true, + controller: scrollController, + children: + season.generateActions(context, ref).listTileItems(context, useIcons: true), + ), + ); + } + : null, + ); + }, + ), + if (AdaptiveLayout.of(context).inputDevice == InputDevice.pointer) + DisableFocus( + child: Align( + alignment: Alignment.bottomRight, + child: PopupMenuButton( + tooltip: context.localized.options, + icon: Icon( + Icons.more_vert, + color: Colors.white, + shadows: [ + Shadow(color: Colors.black.withOpacity(0.45), blurRadius: 8.0), + const Shadow(color: Colors.black, blurRadius: 16.0), + const Shadow(color: Colors.black, blurRadius: 32.0), + const Shadow(color: Colors.black, blurRadius: 64.0), + ], + ), + itemBuilder: (context) => season.generateActions(context, ref).popupMenuItems(useIcons: true), + ), + ), + ), + ], + ), + ), + ), + const SizedBox(height: 4), + ClickableText( + text: season.localizedName(context), + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.titleSmall?.copyWith(fontWeight: FontWeight.bold), + ), + ], + ), + ); + } +} diff --git a/lib/screens/shared/nested_bottom_appbar.dart b/lib/screens/shared/nested_bottom_appbar.dart new file mode 100644 index 0000000..15c7cbf --- /dev/null +++ b/lib/screens/shared/nested_bottom_appbar.dart @@ -0,0 +1,38 @@ +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/widgets/shared/shapes.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class NestedBottomAppBar extends ConsumerWidget { + final Widget child; + const NestedBottomAppBar({required this.child, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final double bottomPadding = + (AdaptiveLayout.of(context).isDesktop || kIsWeb) ? 12 : MediaQuery.of(context).padding.bottom; + return Card( + color: Theme.of(context).colorScheme.surface, + shape: BottomBarShape(), + elevation: 0, + child: Padding( + padding: const EdgeInsets.only(top: 8), + child: SizedBox( + height: kBottomNavigationBarHeight + 12 + bottomPadding, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12) + .copyWith( + bottom: bottomPadding, + ) + .add(EdgeInsets.only( + left: MediaQuery.of(context).padding.left, + right: MediaQuery.of(context).padding.right, + )), + child: child, + ), + ), + ), + ); + } +} diff --git a/lib/screens/shared/nested_scaffold.dart b/lib/screens/shared/nested_scaffold.dart new file mode 100644 index 0000000..259a857 --- /dev/null +++ b/lib/screens/shared/nested_scaffold.dart @@ -0,0 +1,34 @@ +import 'package:fladder/models/media_playback_model.dart'; +import 'package:fladder/providers/video_player_provider.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/widgets/navigation_scaffold/components/floating_player_bar.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class NestedScaffold extends ConsumerWidget { + final Widget body; + const NestedScaffold({required this.body, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final playerState = ref.watch(mediaPlaybackProvider.select((value) => value.state)); + + return Card( + child: Scaffold( + backgroundColor: Colors.transparent, + floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, + floatingActionButton: switch (AdaptiveLayout.layoutOf(context)) { + LayoutState.phone => null, + _ => switch (playerState) { + VideoPlayerState.minimized => Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: FloatingPlayerBar(), + ), + _ => null, + }, + }, + body: body, + ), + ); + } +} diff --git a/lib/screens/shared/nested_sliver_appbar.dart b/lib/screens/shared/nested_sliver_appbar.dart new file mode 100644 index 0000000..46f4996 --- /dev/null +++ b/lib/screens/shared/nested_sliver_appbar.dart @@ -0,0 +1,83 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/routes/build_routes/route_builder.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/widgets/navigation_scaffold/components/settings_user_icon.dart'; +import 'package:fladder/widgets/shared/shapes.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class NestedSliverAppBar extends ConsumerWidget { + final BuildContext parent; + final String? searchTitle; + final CustomRoute? route; + const NestedSliverAppBar({required this.parent, this.route, this.searchTitle, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return SliverAppBar( + automaticallyImplyLeading: false, + elevation: 16, + forceElevated: true, + surfaceTintColor: Colors.transparent, + shadowColor: Colors.transparent, + backgroundColor: Theme.of(context).colorScheme.surface, + shape: AppBarShape(), + title: SizedBox( + height: 65, + child: Padding( + padding: const EdgeInsets.only(bottom: 24), + child: Row( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + IconButton.filledTonal( + style: ButtonStyle( + backgroundColor: WidgetStatePropertyAll(Theme.of(context).colorScheme.surface), + ), + onPressed: () => Scaffold.of(parent).openDrawer(), + icon: Icon( + IconsaxBold.menu, + size: 28, + ), + ), + Expanded( + child: Hero( + tag: "PrimarySearch", + child: Card( + elevation: 3, + shadowColor: Colors.transparent, + child: InkWell( + onTap: route != null + ? () { + context.routePushOrGo(route!); + } + : null, + child: Padding( + padding: const EdgeInsets.all(10), + child: Opacity( + opacity: 0.65, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Icon(IconsaxOutline.search_normal), + const SizedBox(width: 16), + Transform.translate( + offset: Offset(0, 2.5), child: Text(searchTitle ?? "${context.localized.search}...")), + ], + ), + ), + ), + ), + ), + ), + ), + SettingsUserIcon() + ].addInBetween(const SizedBox(width: 16)), + ), + ), + ), + toolbarHeight: 80, + floating: true, + ); + } +} diff --git a/lib/screens/shared/outlined_text_field.dart b/lib/screens/shared/outlined_text_field.dart new file mode 100644 index 0000000..27eed00 --- /dev/null +++ b/lib/screens/shared/outlined_text_field.dart @@ -0,0 +1,177 @@ +import 'package:fladder/screens/shared/animated_fade_size.dart'; +import 'package:fladder/theme.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class OutlinedTextField extends ConsumerStatefulWidget { + final String? label; + final FocusNode? focusNode; + final bool autoFocus; + final TextEditingController? controller; + final int maxLines; + final Function()? onTap; + final Function(String value)? onChanged; + final Function(String value)? onSubmitted; + final List? autoFillHints; + final List? inputFormatters; + final bool autocorrect; + final TextStyle? style; + final double borderWidth; + final Color? fillColor; + final TextAlign textAlign; + final TextInputType? keyboardType; + final TextInputAction? textInputAction; + final String? errorText; + final bool? enabled; + + const OutlinedTextField({ + this.label, + this.focusNode, + this.autoFocus = false, + this.controller, + this.maxLines = 1, + this.onTap, + this.onChanged, + this.onSubmitted, + this.fillColor, + this.style, + this.borderWidth = 1, + this.textAlign = TextAlign.start, + this.autoFillHints, + this.inputFormatters, + this.autocorrect = true, + this.keyboardType, + this.textInputAction, + this.errorText, + this.enabled, + super.key, + }); + + @override + ConsumerState createState() => _OutlinedTextFieldState(); +} + +class _OutlinedTextFieldState extends ConsumerState { + late FocusNode focusNode = widget.focusNode ?? FocusNode(); + bool _obscureText = true; + void _toggle() { + setState(() { + _obscureText = !_obscureText; + }); + } + + Color getColor() { + if (widget.errorText != null) return Theme.of(context).colorScheme.errorContainer; + return Theme.of(context).colorScheme.secondaryContainer.withOpacity(0.25); + } + + @override + Widget build(BuildContext context) { + final isPasswordField = widget.keyboardType == TextInputType.visiblePassword; + if (widget.autoFocus) { + focusNode.requestFocus(); + } + focusNode.addListener( + () {}, + ); + return Column( + children: [ + Stack( + clipBehavior: Clip.none, + children: [ + Positioned.fill( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 6), + child: AnimatedContainer( + duration: Duration(milliseconds: 250), + decoration: BoxDecoration( + color: widget.fillColor ?? getColor(), + borderRadius: FladderTheme.defaultShape.borderRadius, + ), + ), + ), + ), + IgnorePointer( + ignoring: widget.enabled == false, + child: TextField( + controller: widget.controller, + onChanged: widget.onChanged, + focusNode: focusNode, + onTap: widget.onTap, + autofillHints: widget.autoFillHints, + keyboardType: widget.keyboardType, + autocorrect: widget.autocorrect, + onSubmitted: widget.onSubmitted, + textInputAction: widget.textInputAction, + obscureText: isPasswordField ? _obscureText : false, + style: widget.style, + maxLines: widget.maxLines, + inputFormatters: widget.inputFormatters, + textAlign: widget.textAlign, + decoration: InputDecoration( + border: OutlineInputBorder( + borderSide: BorderSide( + color: Theme.of(context).colorScheme.primary.withOpacity(0), + width: widget.borderWidth, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Theme.of(context).colorScheme.primary.withOpacity(0), + width: widget.borderWidth, + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Theme.of(context).colorScheme.primary.withOpacity(0), + width: widget.borderWidth, + ), + ), + errorBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Theme.of(context).colorScheme.primary.withOpacity(0), + width: widget.borderWidth, + ), + ), + focusedErrorBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Theme.of(context).colorScheme.primary.withOpacity(0), + width: widget.borderWidth, + ), + ), + filled: widget.fillColor != null, + fillColor: widget.fillColor, + labelText: widget.label, + // errorText: widget.errorText, + suffixIcon: isPasswordField + ? InkWell( + onTap: _toggle, + borderRadius: BorderRadius.circular(5), + child: Icon( + _obscureText ? Icons.visibility : Icons.visibility_off, + size: 16.0, + ), + ) + : null, + ), + ), + ), + ], + ), + AnimatedFadeSize( + child: widget.errorText != null + ? Align( + alignment: Alignment.centerLeft, + child: Text( + widget.errorText ?? "", + style: + Theme.of(context).textTheme.labelMedium?.copyWith(color: Theme.of(context).colorScheme.error), + ), + ) + : Container(), + ), + ], + ); + } +} diff --git a/lib/screens/shared/passcode_input.dart b/lib/screens/shared/passcode_input.dart new file mode 100644 index 0000000..d621e00 --- /dev/null +++ b/lib/screens/shared/passcode_input.dart @@ -0,0 +1,173 @@ +import 'package:fladder/screens/shared/animated_fade_size.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class PassCodeInput extends ConsumerStatefulWidget { + final ValueChanged passCode; + const PassCodeInput({required this.passCode, super.key}); + + @override + ConsumerState createState() => _PassCodeInputState(); +} + +class _PassCodeInputState extends ConsumerState { + final iconSize = 45.0; + final passCodeLength = 4; + var currentPasscode = ""; + final focusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + focusNode.requestFocus(); + return KeyboardListener( + focusNode: focusNode, + autofocus: true, + onKeyEvent: (value) { + if (value is KeyDownEvent) { + final keyInt = int.tryParse(value.logicalKey.keyLabel); + if (keyInt != null) { + addToPassCode(value.logicalKey.keyLabel); + } + if (value.logicalKey == LogicalKeyboardKey.backspace) { + backSpace(); + } + } + }, + child: AlertDialog.adaptive( + scrollable: true, + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: List.generate( + passCodeLength, + (index) => Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 4), + child: SizedBox( + height: iconSize * 1.2, + width: iconSize * 1.2, + child: Card( + child: Transform.translate( + offset: const Offset(0, 5), + child: AnimatedFadeSize( + child: Text( + currentPasscode.length > index ? "*" : "", + style: Theme.of(context).textTheme.displayLarge?.copyWith(fontSize: 60), + ), + ), + ), + ), + ), + ), + ), + ).toList(), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: List.of([1, 2, 3]).map((e) => passCodeNumber(e)).toList(), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: List.of([4, 5, 6]).map((e) => passCodeNumber(e)).toList(), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: List.of([7, 8, 9]).map((e) => passCodeNumber(e)).toList(), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + backSpaceButton, + passCodeNumber(0), + clearAllButton, + ], + ) + ].addPadding(const EdgeInsets.symmetric(vertical: 8)), + ), + ), + ); + } + + Widget passCodeNumber(int value) { + return IconButton.filledTonal( + onPressed: () async { + addToPassCode(value.toString()); + }, + icon: Container( + width: iconSize, + height: iconSize, + alignment: Alignment.center, + child: Text( + value.toString(), + style: Theme.of(context).textTheme.displaySmall?.copyWith(fontWeight: FontWeight.bold), + ), + ), + ); + } + + void addToPassCode(String value) async { + String newPasscode = currentPasscode + value.toString(); + if (newPasscode.length == passCodeLength) { + Navigator.of(context).pop(); + await Future.delayed(const Duration(milliseconds: 250)); + widget.passCode(newPasscode); + } else { + setState(() { + currentPasscode = newPasscode; + }); + } + } + + void backSpace() { + setState(() { + if (currentPasscode.isNotEmpty) { + currentPasscode = currentPasscode.substring(0, currentPasscode.length - 1); + } + }); + } + + Widget get clearAllButton { + return IconButton.filled( + style: ButtonStyle( + backgroundColor: WidgetStatePropertyAll(Theme.of(context).colorScheme.errorContainer), + iconColor: WidgetStatePropertyAll(Theme.of(context).colorScheme.onErrorContainer), + ), + onPressed: () { + setState(() { + currentPasscode = ""; + }); + }, + icon: Icon( + Icons.clear_rounded, + size: iconSize, + ), + ); + } + + Widget get backSpaceButton { + return IconButton.filled( + onPressed: () => backSpace(), + icon: Icon( + Icons.backspace_rounded, + size: iconSize, + ), + ); + } +} + +void showPassCodeDialog(BuildContext context, ValueChanged newPin) { + showDialog( + context: context, + builder: (context) => PassCodeInput( + passCode: (value) { + newPin.call(value); + }, + ), + ); +} diff --git a/lib/screens/shared/user_icon.dart b/lib/screens/shared/user_icon.dart new file mode 100644 index 0000000..1679e21 --- /dev/null +++ b/lib/screens/shared/user_icon.dart @@ -0,0 +1,72 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fladder/models/account_model.dart'; +import 'package:fladder/screens/shared/flat_button.dart'; +import 'package:fladder/util/string_extensions.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class UserIcon extends ConsumerWidget { + final AccountModel? user; + final Size size; + final TextStyle? labelStyle; + final VoidCallback? onTap; + final VoidCallback? onLongPress; + final double cornerRadius; + const UserIcon({ + this.size = const Size(50, 50), + this.labelStyle, + this.cornerRadius = 5, + this.onTap, + this.onLongPress, + required this.user, + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + Widget placeHolder() { + return Container( + color: Theme.of(context).colorScheme.primaryContainer, + child: Center( + child: Text( + user?.name.getInitials() ?? "", + style: (labelStyle ?? Theme.of(context).textTheme.titleMedium)?.copyWith( + fontWeight: FontWeight.bold, + color: Theme.of(context).colorScheme.onPrimaryContainer, + ), + ), + ), + ); + } + + return Hero( + tag: Key(user?.id ?? "empty-user-avatar"), + child: AspectRatio( + aspectRatio: 1, + child: Card( + elevation: 0, + surfaceTintColor: Colors.transparent, + color: Colors.transparent, + clipBehavior: Clip.antiAlias, + child: SizedBox.fromSize( + size: size, + child: Stack( + alignment: Alignment.center, + children: [ + CachedNetworkImage( + imageUrl: user?.avatar ?? "", + progressIndicatorBuilder: (context, url, progress) => placeHolder(), + errorWidget: (context, url, error) => placeHolder(), + ), + FlatButton( + onTap: onTap, + onLongPress: onLongPress, + ) + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/screens/splash_screen.dart b/lib/screens/splash_screen.dart new file mode 100644 index 0000000..ac05eae --- /dev/null +++ b/lib/screens/splash_screen.dart @@ -0,0 +1,56 @@ +import 'package:fladder/models/account_model.dart'; +import 'package:fladder/providers/shared_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/routes/build_routes/home_routes.dart'; +import 'package:fladder/routes/build_routes/route_builder.dart'; +import 'package:fladder/screens/shared/fladder_logo.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class SplashScreen extends ConsumerStatefulWidget { + const SplashScreen({super.key}); + + @override + ConsumerState createState() => _SplashScreenState(); +} + +class _SplashScreenState extends ConsumerState { + @override + void initState() { + super.initState(); + Future.microtask(() async { + await Future.delayed(const Duration(milliseconds: 500)); + final AccountModel? lastUsedAccount = ref.read(sharedUtilityProvider).getActiveAccount(); + ref.read(userProvider.notifier).updateUser(lastUsedAccount); + + if (context.mounted) { + if (lastUsedAccount == null) { + context.routeGo(LoginRoute()); + } else { + switch (lastUsedAccount.authMethod) { + case Authentication.autoLogin: + context.routeGo(DashboardRoute()); + break; + case Authentication.biometrics: + case Authentication.none: + case Authentication.passcode: + context.routeReplace(LoginRoute()); + break; + } + } + } + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: FractionallySizedBox( + heightFactor: 0.4, + child: const FladderLogo(), + ), + ), + ); + } +} diff --git a/lib/screens/syncing/sync_button.dart b/lib/screens/syncing/sync_button.dart new file mode 100644 index 0000000..0cc8b09 --- /dev/null +++ b/lib/screens/syncing/sync_button.dart @@ -0,0 +1,71 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/syncing/sync_item.dart'; +import 'package:fladder/providers/sync/sync_provider_helpers.dart'; +import 'package:fladder/providers/sync_provider.dart'; +import 'package:fladder/screens/shared/default_alert_dialog.dart'; +import 'package:fladder/screens/syncing/sync_item_details.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class SyncButton extends ConsumerStatefulWidget { + final ItemBaseModel item; + final SyncedItem? syncedItem; + const SyncButton({required this.item, required this.syncedItem, super.key}); + + @override + ConsumerState createState() => _SyncButtonState(); +} + +class _SyncButtonState extends ConsumerState { + @override + Widget build(BuildContext context) { + final syncedItem = widget.syncedItem; + final status = syncedItem != null ? ref.watch(syncStatusesProvider(syncedItem)).value : null; + final progress = syncedItem != null ? ref.watch(syncDownloadStatusProvider(syncedItem)) : null; + return Stack( + alignment: Alignment.center, + children: [ + InkWell( + onTap: syncedItem != null + ? () => showSyncItemDetails(context, syncedItem, ref) + : () => showDefaultActionDialog( + context, + 'Sync ${widget.item.detailedName}?', + null, + (context) async { + await ref.read(syncProvider.notifier).addSyncItem(context, widget.item); + Navigator.of(context).pop(); + }, + "Sync", + (context) => Navigator.of(context).pop(), + "Cancel", + ), + child: Icon( + syncedItem != null + ? status == SyncStatus.partially + ? (progress?.progress ?? 0) > 0 + ? IconsaxOutline.arrow_down + : IconsaxOutline.more_circle + : IconsaxOutline.tick_circle + : IconsaxOutline.arrow_down_2, + color: status?.color, + size: (progress?.progress ?? 0) > 0 ? 16 : null, + ), + ), + if ((progress?.progress ?? 0) > 0) + IgnorePointer( + child: SizedBox.fromSize( + size: Size.fromRadius(10), + child: CircularProgressIndicator( + strokeCap: StrokeCap.round, + strokeWidth: 2, + color: status?.color, + value: progress?.progress, + ), + ), + ) + ], + ); + } +} diff --git a/lib/screens/syncing/sync_child_item.dart b/lib/screens/syncing/sync_child_item.dart new file mode 100644 index 0000000..342bb11 --- /dev/null +++ b/lib/screens/syncing/sync_child_item.dart @@ -0,0 +1,66 @@ +import 'package:fladder/models/items/season_model.dart'; +import 'package:fladder/models/syncing/sync_item.dart'; +import 'package:fladder/screens/syncing/widgets/synced_season_poster.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/models/items/episode_model.dart'; +import 'package:fladder/providers/sync_provider.dart'; + +import 'widgets/synced_episode_item.dart'; + +class ChildSyncWidget extends ConsumerStatefulWidget { + final SyncedItem syncedChild; + const ChildSyncWidget({ + required this.syncedChild, + super.key, + }); + + @override + ConsumerState createState() => _ChildSyncWidgetState(); +} + +class _ChildSyncWidgetState extends ConsumerState { + late SyncedItem syncedItem = widget.syncedChild; + + @override + Widget build(BuildContext context) { + final baseItem = ref.read(syncProvider.notifier).getItem(syncedItem); + final hasFile = syncedItem.videoFile.existsSync(); + if (baseItem == null) { + return Container(); + } + return Padding( + padding: const EdgeInsets.symmetric(vertical: 6), + child: Card( + child: InkWell( + onTap: () { + Navigator.of(context).pop(); + baseItem.navigateTo(context); + }, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + Flexible( + child: switch (baseItem) { + SeasonModel season => SyncedSeasonPoster( + syncedItem: syncedItem, + season: season, + ), + EpisodeModel episode => SyncedEpisodeItem( + episode: episode, + syncedItem: syncedItem, + hasFile: hasFile, + ), + _ => Container(), + }, + ), + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/screens/syncing/sync_item_details.dart b/lib/screens/syncing/sync_item_details.dart new file mode 100644 index 0000000..f2dae8b --- /dev/null +++ b/lib/screens/syncing/sync_item_details.dart @@ -0,0 +1,256 @@ +import 'package:background_downloader/background_downloader.dart'; +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/items/episode_model.dart'; +import 'package:fladder/models/syncing/sync_item.dart'; +import 'package:fladder/providers/settings/client_settings_provider.dart'; +import 'package:fladder/providers/sync/background_download_provider.dart'; +import 'package:fladder/providers/sync/sync_provider_helpers.dart'; +import 'package:fladder/providers/sync_provider.dart'; +import 'package:fladder/screens/shared/adaptive_dialog.dart'; +import 'package:fladder/screens/shared/default_alert_dialog.dart'; +import 'package:fladder/screens/shared/media/poster_widget.dart'; +import 'package:fladder/screens/syncing/sync_child_item.dart'; +import 'package:fladder/screens/syncing/sync_widgets.dart'; +import 'package:fladder/screens/syncing/widgets/sync_markedfordelete.dart'; +import 'package:fladder/screens/syncing/widgets/sync_progress_builder.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/size_formatting.dart'; +import 'package:fladder/widgets/shared/icon_button_await.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +Future showSyncItemDetails( + BuildContext context, + SyncedItem syncItem, + WidgetRef ref, +) { + return showDialogAdaptive( + context: context, + useSafeArea: false, + builder: (context) => SyncItemDetails( + syncItem: syncItem, + ), + ); +} + +class SyncItemDetails extends ConsumerStatefulWidget { + final SyncedItem syncItem; + const SyncItemDetails({required this.syncItem, super.key}); + + @override + ConsumerState createState() => _SyncItemDetailsState(); +} + +class _SyncItemDetailsState extends ConsumerState { + late SyncedItem syncedItem = widget.syncItem; + + @override + Widget build(BuildContext context) { + final baseItem = ref.read(syncProvider.notifier).getItem(syncedItem); + final hasFile = syncedItem.videoFile.existsSync(); + final syncChildren = ref.read(syncProvider.notifier).getChildren(syncedItem); + final downloadTask = ref.read(downloadTasksProvider(syncedItem.id)); + + return SyncMarkedForDelete( + syncedItem: syncedItem, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Card( + elevation: 1, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text(baseItem?.type.label(context) ?? ""), + )), + Text( + context.localized.navigationSync, + style: Theme.of(context).textTheme.titleMedium, + ), + IconButton( + onPressed: () => Navigator.pop(context), + icon: Icon(IconsaxBold.close_circle), + ) + ], + ), + if (baseItem != null) ...{ + Divider(), + Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox( + height: (AdaptiveLayout.poster(context).size * + ref.watch(clientSettingsProvider.select((value) => value.posterSize))) * + 0.6, + child: IgnorePointer( + child: PosterWidget( + aspectRatio: 0.7, + poster: baseItem, + inlineTitle: true, + ), + ), + ), + Expanded( + child: SyncProgressBuilder( + item: syncedItem, + builder: (context, combinedStream) { + return Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + baseItem.detailedName(context) ?? "", + style: Theme.of(context).textTheme.titleMedium, + ), + SyncSubtitle(syncItem: syncedItem), + SyncLabel( + label: context.localized + .totalSize(ref.watch(syncSizeProvider(syncedItem)).byteFormat ?? '--'), + status: ref.watch(syncStatusesProvider(syncedItem)).value ?? SyncStatus.partially, + ), + ].addInBetween(const SizedBox(height: 8)), + ), + ), + if (combinedStream?.task != null) ...{ + if (combinedStream?.status != TaskStatus.paused) + IconButton( + onPressed: () => + ref.read(backgroundDownloaderProvider).pause(combinedStream!.task!), + icon: Icon(IconsaxBold.pause), + ), + if (combinedStream?.status == TaskStatus.paused) ...[ + IconButton( + onPressed: () => + ref.read(backgroundDownloaderProvider).resume(combinedStream!.task!), + icon: Icon(IconsaxBold.play), + ), + IconButton( + onPressed: () => ref.read(syncProvider.notifier).deleteFullSyncFiles(syncedItem), + icon: Icon(IconsaxBold.stop), + ), + ], + const SizedBox(width: 16) + }, + if (combinedStream != null && combinedStream.hasDownload) + SizedBox.fromSize( + size: Size.fromRadius(35), + child: Stack( + fit: StackFit.expand, + alignment: Alignment.center, + children: [ + CircularProgressIndicator( + value: combinedStream.progress, + strokeWidth: 8, + backgroundColor: Theme.of(context).colorScheme.surface.withOpacity(0.5), + strokeCap: StrokeCap.round, + color: combinedStream.status.color(context), + ), + Center(child: Text("${((combinedStream.progress) * 100).toStringAsFixed(0)}%")) + ], + )), + ], + ); + }, + ), + ), + if (!hasFile && !downloadTask.hasDownload && syncedItem.hasVideoFile) + IconButtonAwait( + onPressed: () async => await ref.read(syncProvider.notifier).syncVideoFile(syncedItem, false), + icon: Icon(IconsaxOutline.cloud_change), + ) + else if (hasFile) + IconButtonAwait( + color: Theme.of(context).colorScheme.error, + onPressed: () { + showDefaultAlertDialog( + context, + context.localized.syncRemoveDataTitle, + context.localized.syncRemoveDataDesc, + (context) { + ref.read(syncProvider.notifier).deleteFullSyncFiles(syncedItem); + Navigator.of(context).pop(); + }, + context.localized.delete, + (context) => Navigator.of(context).pop(), + context.localized.cancel, + ); + }, + icon: Icon(IconsaxOutline.trash), + ), + ].addInBetween(const SizedBox(width: 16)), + ), + ), + }, + Divider(), + if (syncChildren.isNotEmpty == true) + Flexible( + child: ListView( + shrinkWrap: true, + children: [ + ...syncChildren.map( + (e) => ChildSyncWidget(syncedChild: e), + ), + ], + ), + ), + Padding( + padding: const EdgeInsets.only(top: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + if (baseItem is! EpisodeModel) + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Theme.of(context).colorScheme.errorContainer, + foregroundColor: Theme.of(context).colorScheme.onErrorContainer, + ), + onPressed: () { + showDefaultAlertDialog( + context, + context.localized.syncDeleteItemTitle, + context.localized.syncDeleteItemDesc(baseItem?.detailedName(context) ?? ""), + (context) async { + await ref.read(syncProvider.notifier).removeSync(syncedItem); + Navigator.pop(context); + Navigator.pop(context); + }, + context.localized.delete, + (context) => Navigator.pop(context), + context.localized.cancel, + ); + }, + child: Text(context.localized.delete), + ) + else if (syncedItem.parentId != null) + ElevatedButton( + onPressed: () { + final parentItem = ref.read(syncProvider.notifier).getParentItem(syncedItem.parentId!); + setState(() { + if (parentItem != null) { + syncedItem = parentItem; + } + }); + }, + child: Text(context.localized.syncOpenParent), + ) + ], + ), + ) + ], + ), + ), + ); + } +} diff --git a/lib/screens/syncing/sync_list_item.dart b/lib/screens/syncing/sync_list_item.dart new file mode 100644 index 0000000..dd9defd --- /dev/null +++ b/lib/screens/syncing/sync_list_item.dart @@ -0,0 +1,148 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/syncing/sync_item.dart'; +import 'package:fladder/providers/sync/sync_provider_helpers.dart'; +import 'package:fladder/providers/sync_provider.dart'; +import 'package:fladder/screens/shared/default_alert_dialog.dart'; +import 'package:fladder/screens/syncing/sync_item_details.dart'; +import 'package:fladder/screens/syncing/sync_widgets.dart'; +import 'package:fladder/screens/syncing/widgets/sync_markedfordelete.dart'; +import 'package:fladder/screens/syncing/widgets/sync_progress_builder.dart'; +import 'package:fladder/util/fladder_image.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/size_formatting.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class SyncListItem extends ConsumerStatefulWidget { + final SyncedItem syncedItem; + const SyncListItem({required this.syncedItem, super.key}); + + @override + ConsumerState createState() => SyncListItemState(); +} + +class SyncListItemState extends ConsumerState { + @override + Widget build(BuildContext context) { + final syncedItem = widget.syncedItem; + final baseItem = ref.read(syncProvider.notifier).getItem(syncedItem); + return Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: SyncMarkedForDelete( + syncedItem: syncedItem, + child: Card( + elevation: 1, + color: Theme.of(context).colorScheme.secondaryContainer.withOpacity(0.2), + shadowColor: Colors.transparent, + child: Dismissible( + background: Container( + color: Theme.of(context).colorScheme.errorContainer, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [Icon(IconsaxBold.trash)], + ), + ), + ), + key: Key(syncedItem.id), + direction: DismissDirection.startToEnd, + confirmDismiss: (direction) async { + await showDefaultAlertDialog( + context, + context.localized.deleteItem(baseItem?.detailedName(context) ?? ""), + context.localized.syncDeletePopupPermanent, + (context) async { + ref.read(syncProvider.notifier).removeSync(syncedItem); + Navigator.of(context).pop(); + return true; + }, + context.localized.delete, + (context) async { + Navigator.of(context).pop(); + }, + context.localized.cancel); + return false; + }, + child: LayoutBuilder(builder: (context, constraints) { + return IntrinsicHeight( + child: InkWell( + onTap: () => baseItem?.navigateTo(context), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + ConstrainedBox( + constraints: BoxConstraints(maxHeight: 125, maxWidth: constraints.maxWidth * 0.2), + child: Card( + child: AspectRatio( + aspectRatio: baseItem?.primaryRatio ?? 1.0, + child: FladderImage( + image: baseItem?.getPosters?.primary, + fit: BoxFit.cover, + )), + ), + ), + Expanded( + child: SyncProgressBuilder( + item: syncedItem, + builder: (context, combinedStream) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Flexible( + child: Text( + baseItem?.detailedName(context) ?? "", + maxLines: 3, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.titleMedium, + ), + ), + Flexible( + child: SyncSubtitle(syncItem: syncedItem), + ), + Flexible( + child: SyncLabel( + label: context.localized + .totalSize(ref.watch(syncSizeProvider(syncedItem)).byteFormat ?? '--'), + status: ref.watch(syncStatusesProvider(syncedItem)).value ?? SyncStatus.partially, + ), + ), + if (combinedStream != null && combinedStream.hasDownload == true) + SyncProgressBar(item: syncedItem, task: combinedStream) + ].addInBetween(const SizedBox(height: 4)), + ); + }, + ), + ), + Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Card( + elevation: 0, + shadowColor: Colors.transparent, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 4), + child: Text(baseItem != null ? baseItem.type.label(context) : ""), + )), + IconButton( + onPressed: () => showSyncItemDetails(context, syncedItem, ref), + icon: Icon(IconsaxOutline.more_square), + ), + ], + ), + ].addInBetween(SizedBox(width: 16)), + ), + ), + ), + ); + }), + ), + ), + ), + ); + } +} diff --git a/lib/screens/syncing/sync_widgets.dart b/lib/screens/syncing/sync_widgets.dart new file mode 100644 index 0000000..1764b13 --- /dev/null +++ b/lib/screens/syncing/sync_widgets.dart @@ -0,0 +1,138 @@ +import 'package:background_downloader/background_downloader.dart'; +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/items/episode_model.dart'; +import 'package:fladder/models/items/season_model.dart'; +import 'package:fladder/models/items/series_model.dart'; +import 'package:fladder/models/syncing/download_stream.dart'; +import 'package:fladder/models/syncing/sync_item.dart'; +import 'package:fladder/providers/sync/background_download_provider.dart'; +import 'package:fladder/providers/sync/sync_provider_helpers.dart'; +import 'package:fladder/providers/sync_provider.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class SyncLabel extends ConsumerWidget { + final String? label; + final SyncStatus status; + const SyncLabel({this.label, required this.status, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Container( + decoration: BoxDecoration( + color: status.color.withOpacity(0.15), + borderRadius: BorderRadius.circular(10), + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), + child: Text( + label ?? status.label, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + fontWeight: FontWeight.bold, + color: status.color, + ), + ), + ), + ); + } +} + +class SyncProgressBar extends ConsumerWidget { + final SyncedItem item; + final DownloadStream task; + const SyncProgressBar({required this.item, required this.task, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final downloadStatus = task.status; + final downloadProgress = task.progress; + final downloadTask = task.task; + if (!task.hasDownload) { + return SizedBox.shrink(); + } + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(downloadStatus.name), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Flexible( + child: LinearProgressIndicator( + minHeight: 8, + value: downloadProgress, + color: downloadStatus.color(context), + borderRadius: BorderRadius.circular(8), + ), + ), + Opacity(opacity: 0.75, child: Text("${(downloadProgress * 100).toStringAsFixed(0)}%")), + if (downloadTask != null) ...{ + if (downloadStatus != TaskStatus.paused) + IconButton( + onPressed: () => ref.read(backgroundDownloaderProvider).pause(downloadTask), + icon: Icon(IconsaxBold.pause), + ) + }, + if (downloadStatus == TaskStatus.paused && downloadTask != null) ...[ + IconButton( + onPressed: () => ref.read(backgroundDownloaderProvider).resume(downloadTask), + icon: Icon(IconsaxBold.play), + ), + IconButton( + onPressed: () => ref.read(syncProvider.notifier).deleteFullSyncFiles(item), + icon: Icon(IconsaxBold.stop), + ) + ], + ].addInBetween(SizedBox(width: 8)), + ), + const SizedBox(width: 6), + ], + ); + } +} + +class SyncSubtitle extends ConsumerWidget { + final SyncedItem syncItem; + const SyncSubtitle({ + required this.syncItem, + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final baseItem = ref.read(syncProvider.notifier).getItem(syncItem); + final children = syncItem.nestedChildren(ref); + final syncStatus = ref.watch(syncStatusesProvider(syncItem)).value ?? SyncStatus.partially; + return Container( + decoration: BoxDecoration(color: syncStatus.color.withOpacity(0.15), borderRadius: BorderRadius.circular(10)), + child: Material( + color: const Color.fromARGB(0, 208, 130, 130), + textStyle: + Theme.of(context).textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.bold, color: syncStatus.color), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), + child: switch (baseItem) { + SeriesModel _ => Builder( + builder: (context) { + final itemBaseModels = children.map((e) => ref.read(syncProvider.notifier).getItem(e)); + final seriesItemsSyncLeft = children.where((element) => element.taskId != null).length; + final seasons = itemBaseModels.whereType().length; + final episodes = itemBaseModels.whereType().length; + return Text( + [ + "${context.localized.season(seasons)}: $seasons", + "${context.localized.episode(seasons)}: $episodes | ${context.localized.sync}: ${children.where((element) => element.videoFile.existsSync()).length}${seriesItemsSyncLeft > 0 ? " | Syncing: $seriesItemsSyncLeft" : ""}" + ].join('\n'), + ); + }, + ), + _ => Text(syncStatus.label), + }, + ), + ), + ); + } +} diff --git a/lib/screens/syncing/synced_screen.dart b/lib/screens/syncing/synced_screen.dart new file mode 100644 index 0000000..64b7bdf --- /dev/null +++ b/lib/screens/syncing/synced_screen.dart @@ -0,0 +1,91 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/providers/sync_provider.dart'; +import 'package:fladder/providers/settings/client_settings_provider.dart'; +import 'package:fladder/routes/build_routes/home_routes.dart'; +import 'package:fladder/screens/shared/nested_scaffold.dart'; +import 'package:fladder/screens/shared/nested_sliver_appbar.dart'; +import 'package:fladder/screens/syncing/sync_list_item.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/widgets/shared/pinch_poster_zoom.dart'; +import 'package:fladder/widgets/shared/pull_to_refresh.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/util/sliver_list_padding.dart'; + +class SyncedScreen extends ConsumerStatefulWidget { + final ScrollController navigationScrollController; + + const SyncedScreen({required this.navigationScrollController, super.key}); + + @override + ConsumerState createState() => _SyncedScreenState(); +} + +class _SyncedScreenState extends ConsumerState { + @override + Widget build(BuildContext context) { + final items = ref.watch(syncProvider.select((value) => value.items)); + return PullToRefresh( + refreshOnStart: true, + onRefresh: () => ref.read(syncProvider.notifier).refresh(), + child: NestedScaffold( + body: PinchPosterZoom( + scaleDifference: (difference) => ref.read(clientSettingsProvider.notifier).addPosterSize(difference / 2), + child: items.isNotEmpty + ? CustomScrollView( + physics: const AlwaysScrollableScrollPhysics(), + controller: widget.navigationScrollController, + slivers: [ + if (AdaptiveLayout.of(context).layout == LayoutState.phone) + NestedSliverAppBar( + searchTitle: "${context.localized.search} ...", + parent: context, + route: LibrarySearchRoute(), + ) + else + const DefaultSliverTopBadding(), + SliverToBoxAdapter( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 16), + child: Text( + context.localized.syncedItems, + style: Theme.of(context).textTheme.titleLarge, + ), + ), + ), + SliverPadding( + padding: EdgeInsets.symmetric(horizontal: 16), + sliver: SliverList.builder( + itemBuilder: (context, index) { + final item = items[index]; + return SyncListItem(syncedItem: item); + }, + itemCount: items.length, + ), + ), + const DefautlSliverBottomPadding(), + ], + ) + : Center( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.localized.noItemsSynced, + style: Theme.of(context).textTheme.titleMedium, + ), + const SizedBox(width: 16), + Icon( + IconsaxOutline.cloud_cross, + ) + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/screens/syncing/widgets/sync_markedfordelete.dart b/lib/screens/syncing/widgets/sync_markedfordelete.dart new file mode 100644 index 0000000..871a669 --- /dev/null +++ b/lib/screens/syncing/widgets/sync_markedfordelete.dart @@ -0,0 +1,41 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/syncing/sync_item.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class SyncMarkedForDelete extends ConsumerWidget { + final SyncedItem syncedItem; + final Widget child; + const SyncMarkedForDelete({required this.syncedItem, required this.child, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Stack( + children: [ + child, + if (syncedItem.markedForDelete) + Positioned.fill( + child: Card( + elevation: 0, + semanticContainer: false, + color: Colors.black.withOpacity(0.6), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + CircularProgressIndicator.adaptive( + strokeCap: StrokeCap.round, + valueColor: AlwaysStoppedAnimation(Theme.of(context).colorScheme.error), + ), + Text("Deleting"), + Icon(IconsaxOutline.trash) + ].addPadding(EdgeInsets.symmetric(horizontal: 16)), + ), + ), + ) + ], + ); + } +} diff --git a/lib/screens/syncing/widgets/sync_progress_builder.dart b/lib/screens/syncing/widgets/sync_progress_builder.dart new file mode 100644 index 0000000..56e7616 --- /dev/null +++ b/lib/screens/syncing/widgets/sync_progress_builder.dart @@ -0,0 +1,17 @@ +import 'package:fladder/models/syncing/download_stream.dart'; +import 'package:fladder/models/syncing/sync_item.dart'; +import 'package:fladder/providers/sync/sync_provider_helpers.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class SyncProgressBuilder extends ConsumerWidget { + final SyncedItem item; + final Widget Function(BuildContext context, DownloadStream? combinedStream) builder; + const SyncProgressBuilder({required this.item, required this.builder, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final syncStatus = ref.watch(syncDownloadStatusProvider(item)); + return builder(context, syncStatus); + } +} diff --git a/lib/screens/syncing/widgets/synced_episode_item.dart b/lib/screens/syncing/widgets/synced_episode_item.dart new file mode 100644 index 0000000..5cf7eb3 --- /dev/null +++ b/lib/screens/syncing/widgets/synced_episode_item.dart @@ -0,0 +1,122 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/items/episode_model.dart'; +import 'package:fladder/models/syncing/sync_item.dart'; +import 'package:fladder/providers/sync/sync_provider_helpers.dart'; +import 'package:fladder/providers/sync_provider.dart'; +import 'package:fladder/screens/shared/default_alert_dialog.dart'; +import 'package:fladder/screens/shared/media/episode_posters.dart'; +import 'package:fladder/screens/syncing/sync_widgets.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/size_formatting.dart'; +import 'package:fladder/widgets/shared/icon_button_await.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class SyncedEpisodeItem extends ConsumerStatefulWidget { + const SyncedEpisodeItem({ + super.key, + required this.episode, + required this.syncedItem, + required this.hasFile, + }); + + final EpisodeModel episode; + final SyncedItem syncedItem; + final bool hasFile; + + @override + ConsumerState createState() => _SyncedEpisodeItemState(); +} + +class _SyncedEpisodeItemState extends ConsumerState { + late SyncedItem syncedItem = widget.syncedItem; + @override + Widget build(BuildContext context) { + final downloadTask = ref.watch(downloadTasksProvider(syncedItem.id)); + final hasFile = widget.syncedItem.videoFile.existsSync(); + + return Row( + children: [ + IgnorePointer( + child: ConstrainedBox( + constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * 0.3), + child: SizedBox( + width: 250, + child: EpisodePoster( + episode: widget.episode, + syncedItem: syncedItem, + actions: [], + showLabel: false, + isCurrentEpisode: false, + ), + ), + ), + ), + Expanded( + child: Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.episode.name, + style: Theme.of(context).textTheme.titleMedium, + ), + Opacity( + opacity: 0.75, + child: Text( + widget.episode.seasonEpisodeLabel(context), + style: Theme.of(context).textTheme.bodyLarge, + ), + ), + ], + ), + ), + if (!widget.hasFile && downloadTask.hasDownload) + Flexible( + child: SyncProgressBar(item: syncedItem, task: downloadTask), + ) + else + Flexible( + child: SyncLabel( + label: context.localized.totalSize(ref.watch(syncSizeProvider(syncedItem)).byteFormat ?? '--'), + status: ref.watch(syncStatusesProvider(syncedItem)).value ?? SyncStatus.partially, + ), + ) + ], + ), + ), + if (!hasFile && !downloadTask.hasDownload) + IconButtonAwait( + onPressed: () async => await ref.read(syncProvider.notifier).syncVideoFile(syncedItem, false), + icon: Icon(IconsaxOutline.cloud_change), + ) + else if (hasFile) + IconButtonAwait( + color: Theme.of(context).colorScheme.error, + onPressed: () async { + await showDefaultAlertDialog( + context, + context.localized.syncRemoveDataTitle, + context.localized.syncRemoveDataDesc, + (context) async { + await ref.read(syncProvider.notifier).deleteFullSyncFiles(syncedItem); + Navigator.pop(context); + }, + context.localized.delete, + (context) => Navigator.pop(context), + context.localized.cancel, + ); + }, + icon: Icon(IconsaxOutline.trash), + ) + ].addInBetween(const SizedBox(width: 16)), + ); + } +} diff --git a/lib/screens/syncing/widgets/synced_season_poster.dart b/lib/screens/syncing/widgets/synced_season_poster.dart new file mode 100644 index 0000000..1a87054 --- /dev/null +++ b/lib/screens/syncing/widgets/synced_season_poster.dart @@ -0,0 +1,95 @@ +import 'package:fladder/models/items/episode_model.dart'; +import 'package:fladder/models/items/season_model.dart'; +import 'package:fladder/models/syncing/sync_item.dart'; +import 'package:fladder/providers/sync_provider.dart'; +import 'package:fladder/screens/shared/animated_fade_size.dart'; +import 'package:fladder/screens/syncing/widgets/synced_episode_item.dart'; +import 'package:fladder/util/fladder_image.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class SyncedSeasonPoster extends ConsumerStatefulWidget { + const SyncedSeasonPoster({ + super.key, + required this.syncedItem, + required this.season, + }); + + final SyncedItem syncedItem; + final SeasonModel season; + + @override + ConsumerState createState() => _SyncedSeasonPosterState(); +} + +class _SyncedSeasonPosterState extends ConsumerState { + bool expanded = false; + @override + Widget build(BuildContext context) { + final season = widget.season; + final children = ref.read(syncProvider.notifier).getChildren(widget.syncedItem); + return Column( + children: [ + Row( + children: [ + SizedBox( + width: 125, + child: AspectRatio( + aspectRatio: 0.65, + child: Card( + child: FladderImage( + image: season.getPosters?.primary ?? + season.parentImages?.backDrop?.firstOrNull ?? + season.parentImages?.primary, + ), + ), + ), + ), + Column( + children: [ + Text( + season.name, + style: Theme.of(context).textTheme.titleMedium, + ) + ], + ), + Spacer(), + IconButton( + onPressed: () { + setState(() { + expanded = !expanded; + }); + }, + icon: Icon(!expanded ? Icons.keyboard_arrow_down_rounded : Icons.keyboard_arrow_up_rounded), + ) + ].addPadding(EdgeInsets.symmetric(horizontal: 6)), + ), + AnimatedFadeSize( + duration: const Duration(milliseconds: 250), + child: expanded && children.isNotEmpty + ? ListView( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + children: [ + Divider(), + ...children.map( + (item) { + final baseItem = ref.read(syncProvider.notifier).getItem(item); + return IntrinsicHeight( + child: SyncedEpisodeItem( + episode: baseItem as EpisodeModel, + syncedItem: item, + hasFile: item.videoFile.existsSync(), + ), + ); + }, + ) + ].addPadding(EdgeInsets.symmetric(vertical: 10)), + ) + : Container(), + ) + ].addPadding(EdgeInsets.only(top: 10, bottom: expanded ? 10 : 0)), + ); + } +} diff --git a/lib/screens/video_player/components/video_playback_information.dart b/lib/screens/video_player/components/video_playback_information.dart new file mode 100644 index 0000000..a7a87d4 --- /dev/null +++ b/lib/screens/video_player/components/video_playback_information.dart @@ -0,0 +1,77 @@ +import 'package:fladder/models/playback/playback_model.dart'; +import 'package:fladder/providers/session_info_provider.dart'; +import 'package:fladder/providers/video_player_provider.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +Future showVideoPlaybackInformation(BuildContext context) { + return showDialog( + context: context, + builder: (context) => _VideoPlaybackInformation(), + ); +} + +class _VideoPlaybackInformation extends ConsumerWidget { + const _VideoPlaybackInformation(); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final playbackModel = ref.watch(playBackModel); + final sessionInfo = ref.watch(sessionInfoProvider); + return Dialog( + child: Padding( + padding: const EdgeInsets.all(12.0), + child: IntrinsicWidth( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("Playback information", style: Theme.of(context).textTheme.titleMedium), + Divider(), + ...[ + Row( + mainAxisSize: MainAxisSize.min, + children: [Text('type: '), Text(playbackModel.label ?? "")], + ), + if (sessionInfo.transCodeInfo != null) ...[ + const SizedBox(height: 6), + Text("Transcoding", style: Theme.of(context).textTheme.titleMedium), + if (sessionInfo.transCodeInfo?.transcodeReasons?.isNotEmpty == true) + Row( + mainAxisSize: MainAxisSize.min, + children: [Text('reason: '), Text(sessionInfo.transCodeInfo?.transcodeReasons.toString() ?? "")], + ), + if (sessionInfo.transCodeInfo?.completionPercentage != null) + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text('transcode progress: '), + Text("${sessionInfo.transCodeInfo?.completionPercentage?.toStringAsFixed(2)} %") + ], + ), + if (sessionInfo.transCodeInfo?.container != null) + Row( + mainAxisSize: MainAxisSize.min, + children: [Text('container: '), Text(sessionInfo.transCodeInfo!.container.toString())], + ), + ], + Row( + mainAxisSize: MainAxisSize.min, + children: [Text('resolution: '), Text(playbackModel?.item.streamModel?.resolutionText ?? "")], + ), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text('container: '), + Text(playbackModel?.playbackInfo?.mediaSources?.firstOrNull?.container ?? "") + ], + ), + ].addPadding(EdgeInsets.symmetric(vertical: 3)) + ], + ), + ), + ), + ); + } +} diff --git a/lib/screens/video_player/components/video_player_chapters.dart b/lib/screens/video_player/components/video_player_chapters.dart new file mode 100644 index 0000000..0fa999b --- /dev/null +++ b/lib/screens/video_player/components/video_player_chapters.dart @@ -0,0 +1,92 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fladder/models/items/chapters_model.dart'; +import 'package:fladder/screens/shared/flat_button.dart'; +import 'package:fladder/widgets/shared/horizontal_list.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +showPlayerChapterDialogue( + BuildContext context, { + required List chapters, + required Function(Chapter chapter) onChapterTapped, + required Duration currentPosition, +}) { + showDialog( + context: context, + builder: (context) => Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + ), + child: VideoPlayerChapters( + chapters: chapters, + onChapterTapped: onChapterTapped, + currentPosition: currentPosition, + ), + ), + ); +} + +class VideoPlayerChapters extends ConsumerWidget { + final List chapters; + final Function(Chapter chapter) onChapterTapped; + final Duration currentPosition; + const VideoPlayerChapters( + {required this.chapters, required this.onChapterTapped, required this.currentPosition, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final currentChapter = chapters.getChapterFromDuration(currentPosition); + return SizedBox( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: HorizontalList( + label: "Chapters", + height: 200, + startIndex: chapters.indexOf(currentChapter ?? chapters.first), + contentPadding: const EdgeInsets.symmetric(horizontal: 32), + items: chapters.toList(), + itemBuilder: (context, index) { + final chapter = chapters[index]; + final isCurrent = chapter == currentChapter; + return Card( + color: Colors.black, + clipBehavior: Clip.antiAlias, + child: Stack( + children: [ + Center( + child: CachedNetworkImage( + imageUrl: chapter.imageUrl, + fit: BoxFit.fitWidth, + ), + ), + Align( + alignment: Alignment.bottomRight, + child: Card( + color: isCurrent ? Theme.of(context).colorScheme.onPrimary : null, + margin: const EdgeInsets.all(8), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + chapter.name, + style: Theme.of(context).textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.bold), + ), + ), + ), + ), + Positioned.fill( + child: FlatButton( + onTap: () { + Navigator.of(context).pop(); + onChapterTapped(chapter); + }, + ), + ), + ], + ), + ); + }, + ), + ), + ); + } +} diff --git a/lib/screens/video_player/components/video_player_controls_extras.dart b/lib/screens/video_player/components/video_player_controls_extras.dart new file mode 100644 index 0000000..aaa8eff --- /dev/null +++ b/lib/screens/video_player/components/video_player_controls_extras.dart @@ -0,0 +1,111 @@ +import 'package:fladder/providers/video_player_provider.dart'; +import 'package:flutter/material.dart'; + +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:media_kit/media_kit.dart'; + +import 'package:fladder/screens/video_player/components/video_player_chapters.dart'; +import 'package:fladder/screens/video_player/components/video_player_queue.dart'; + +class ChapterButton extends ConsumerWidget { + final Duration position; + final Player player; + const ChapterButton({super.key, required this.position, required this.player}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final currentChapters = ref.watch(playBackModel.select((value) => value?.chapters)); + if (currentChapters != null) { + return IconButton( + onPressed: () { + showPlayerChapterDialogue( + context, + chapters: currentChapters, + currentPosition: position, + onChapterTapped: (chapter) => player.seek( + chapter.startPosition, + ), + ); + }, + icon: const Icon( + Icons.video_collection_rounded, + ), + ); + } else { + return Container(); + } + } +} + +class OpenQueueButton extends ConsumerWidget { + const OpenQueueButton({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final state = ref.watch(playBackModel); + return IconButton( + onPressed: state?.queue.isNotEmpty == true + ? () { + ref.read(videoPlayerProvider).pause(); + showFullScreenItemQueue( + context, + items: state?.queue ?? [], + currentItem: state?.item, + playSelected: (itemStreamModel) { + throw UnimplementedError(); + }, + ); + } + : null, + icon: const Icon(Icons.view_list_rounded), + ); + } +} + +class IntroSkipButton extends ConsumerWidget { + final bool isOverlayVisible; + + final Function()? skipIntro; + const IntroSkipButton({this.skipIntro, required this.isOverlayVisible, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return ElevatedButton( + onPressed: () => skipIntro?.call(), + style: ElevatedButton.styleFrom(shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5))), + child: const Padding( + padding: EdgeInsets.all(8), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [Text("(S)kip Intro"), Icon(Icons.skip_next_rounded)], + ), + ), + ); + } +} + +class CreditsSkipButton extends ConsumerWidget { + final bool isOverlayVisible; + final Function()? skipCredits; + const CreditsSkipButton({this.skipCredits, required this.isOverlayVisible, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + // final semiHideSkip = skipCredits. + return AnimatedOpacity( + opacity: 1, + duration: const Duration(milliseconds: 250), + child: ElevatedButton( + onPressed: () => skipCredits?.call(), + style: ElevatedButton.styleFrom(shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5))), + child: const Padding( + padding: EdgeInsets.all(8), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [Text("(S)kip Credits"), Icon(Icons.skip_next_rounded)], + ), + ), + ), + ); + } +} diff --git a/lib/screens/video_player/components/video_player_options_sheet.dart b/lib/screens/video_player/components/video_player_options_sheet.dart new file mode 100644 index 0000000..e00e160 --- /dev/null +++ b/lib/screens/video_player/components/video_player_options_sheet.dart @@ -0,0 +1,430 @@ +import 'package:collection/collection.dart'; +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/episode_model.dart'; +import 'package:fladder/models/playback/direct_playback_model.dart'; +import 'package:fladder/models/playback/offline_playback_model.dart'; +import 'package:fladder/models/playback/playback_model.dart'; +import 'package:fladder/models/playback/transcode_playback_model.dart'; +import 'package:fladder/providers/settings/video_player_settings_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/providers/video_player_provider.dart'; +import 'package:fladder/screens/collections/add_to_collection.dart'; +import 'package:fladder/screens/metadata/info_screen.dart'; +import 'package:fladder/screens/playlists/add_to_playlists.dart'; +import 'package:fladder/screens/video_player/components/video_player_queue.dart'; +import 'package:fladder/screens/video_player/components/video_subtitle_controls.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/refresh_state.dart'; +import 'package:fladder/util/string_extensions.dart'; +import 'package:fladder/widgets/shared/enum_selection.dart'; +import 'package:fladder/widgets/shared/modal_bottom_sheet.dart'; +import 'package:fladder/widgets/shared/spaced_list_tile.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +Future showVideoPlayerOptions(BuildContext context) { + return showBottomSheetPill( + context: context, + content: (context, scrollController) { + return VideoOptions( + controller: scrollController, + ); + }, + ); +} + +class VideoOptions extends ConsumerStatefulWidget { + final ScrollController controller; + const VideoOptions({required this.controller, super.key}); + + @override + ConsumerState createState() => _VideoOptionsMobileState(); +} + +class _VideoOptionsMobileState extends ConsumerState { + late int page = 0; + + @override + Widget build(BuildContext context) { + final currentItem = ref.watch(playBackModel.select((value) => value?.item)); + final videoSettings = ref.watch(videoPlayerSettingsProvider); + final currentMediaStreams = ref.watch(playBackModel.select((value) => value?.mediaStreams)); + + Widget mainPage() { + return ListView( + key: const Key("mainPage"), + shrinkWrap: true, + controller: widget.controller, + children: [ + InkWell( + onTap: () => setState(() => page = 2), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: Row( + children: [ + Column( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (currentItem?.title.isNotEmpty == true) + Text( + currentItem?.title ?? "", + style: Theme.of(context).textTheme.titleLarge, + ), + if (currentItem?.detailedName(context)?.isNotEmpty == true) + Text( + currentItem?.detailedName(context) ?? "", + style: Theme.of(context).textTheme.titleSmall, + ) + ], + ), + const Spacer(), + Opacity(opacity: 0.1, child: Icon(Icons.info_outline_rounded)) + ], + ), + ), + ), + const SizedBox(height: 12), + const Divider(height: 1), + const SizedBox(height: 12), + if (!AdaptiveLayout.of(context).isDesktop) + ListTile( + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible(flex: 1, child: const Text("Screen Brightness")), + Flexible( + child: Row( + children: [ + Flexible( + child: Opacity( + opacity: videoSettings.screenBrightness == null ? 0.5 : 1, + child: Slider( + value: videoSettings.screenBrightness ?? 1.0, + min: 0, + max: 1, + onChanged: (value) => + ref.read(videoPlayerSettingsProvider.notifier).setScreenBrightness(value), + ), + ), + ), + IconButton( + onPressed: () => ref.read(videoPlayerSettingsProvider.notifier).setScreenBrightness(null), + icon: Opacity( + opacity: videoSettings.screenBrightness != null ? 0.5 : 1, + child: Icon( + IconsaxBold.autobrightness, + color: Theme.of(context).colorScheme.primary, + ), + ), + ) + ], + ), + ), + ], + ), + ), + SpacedListTile( + title: const Text("Subtitles"), + content: Text(currentMediaStreams?.currentSubStream?.displayTitle ?? "Off"), + onTap: currentMediaStreams?.subStreams.isNotEmpty == true ? () => showSubSelection(context) : null, + ), + SpacedListTile( + title: const Text("Audio"), + content: Text(currentMediaStreams?.currentAudioStream?.displayTitle ?? "Off"), + onTap: currentMediaStreams?.audioStreams.isNotEmpty == true ? () => showAudioSelection(context) : null, + ), + ListTile( + title: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Flexible( + child: EnumSelection( + label: const Text("Scale"), + current: videoSettings.videoFit.name.toUpperCaseSplit(), + itemBuilder: (context) => BoxFit.values + .map((value) => PopupMenuItem( + value: value, + child: Text(value.name.toUpperCaseSplit()), + onTap: () => ref.read(videoPlayerSettingsProvider.notifier).setFitType(value), + )) + .toList(), + ), + ), + ], + ), + ), + if (!AdaptiveLayout.of(context).isDesktop) + ListTile( + onTap: () => ref.read(videoPlayerSettingsProvider.notifier).setFillScreen(!videoSettings.fillScreen), + title: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Expanded( + flex: 3, + child: Text("Fill-screen"), + ), + const Spacer(), + Switch.adaptive( + value: videoSettings.fillScreen, + onChanged: (value) => ref.read(videoPlayerSettingsProvider.notifier).setFillScreen(value), + ) + ], + ), + ), + // ListTile( + // title: const Text("Playback settings"), + // onTap: () => setState(() => page = 1), + // ), + ], + ); + } + + Widget itemOptions() { + final currentItem = ref.watch(playBackModel.select((value) => value?.item)); + return ListView( + shrinkWrap: true, + children: [ + navTitle("${currentItem?.title} \n${currentItem?.detailedName}"), + if (currentItem != null) ...{ + if (currentItem.type == FladderItemType.episode) + ListTile( + onTap: () { + //Pop twice once for sheet once for player + Navigator.of(context).pop(); + Navigator.of(context).pop(); + (this as EpisodeModel).parentBaseModel.navigateTo(context); + }, + title: const Text("Open show"), + ), + ListTile( + onTap: () async { + //Pop twice once for sheet once for player + Navigator.of(context).pop(); + Navigator.of(context).pop(); + await currentItem.navigateTo(context); + }, + title: const Text("Show details"), + ), + if (currentItem.type != FladderItemType.boxset) + ListTile( + onTap: () async { + await addItemToCollection(context, [currentItem]); + if (context.mounted) { + context.refreshData(); + } + }, + title: const Text("Add to collection"), + ), + if (currentItem.type != FladderItemType.playlist) + ListTile( + onTap: () async { + await addItemToPlaylist(context, [currentItem]); + if (context.mounted) { + context.refreshData(); + } + }, + title: const Text("Add to playlist"), + ), + ListTile( + onTap: () { + final favourite = !(currentItem.userData.isFavourite == true); + ref.read(userProvider.notifier).setAsFavorite(favourite, currentItem.id); + final newUserData = currentItem.userData; + final playbackModel = switch (ref.read(playBackModel)) { + DirectPlaybackModel value => value.copyWith(item: currentItem.copyWith(userData: newUserData)), + TranscodePlaybackModel value => value.copyWith(item: currentItem.copyWith(userData: newUserData)), + OfflinePlaybackModel value => value.copyWith(item: currentItem.copyWith(userData: newUserData)), + _ => null + }; + if (playbackModel != null) { + ref.read(playBackModel.notifier).update((state) => playbackModel); + } + Navigator.of(context).pop(); + }, + title: Text(currentItem.userData.isFavourite == true ? "Remove from favorites" : "Add to favourites"), + ), + ListTile( + onTap: () { + Navigator.of(context).pop(); + showInfoScreen(context, currentItem); + }, + title: Text('Media info'), + ), + } + ], + ); + } + + Widget playbackSettings() { + final playbackState = ref.watch(playBackModel); + return ListView( + key: const Key("PlaybackSettings"), + shrinkWrap: true, + controller: widget.controller, + children: [ + navTitle("Playback Settings"), + if (playbackState?.queue.isNotEmpty == true) + ListTile( + leading: const Icon(Icons.video_collection_rounded), + title: const Text("Show queue"), + onTap: () { + Navigator.of(context).pop(); + ref.read(videoPlayerProvider).pause(); + showFullScreenItemQueue( + context, + items: playbackState?.queue ?? [], + currentItem: playbackState?.item, + playSelected: (item) { + throw UnimplementedError(); + }, + ); + }, + ) + ], + ); + } + + return Column( + children: [ + AnimatedSize( + duration: const Duration(milliseconds: 250), + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 250), + child: switch (page) { + 1 => playbackSettings(), + 2 => itemOptions(), + _ => mainPage(), + }, + ), + ), + const SizedBox(height: 16), + ], + ); + } + + Widget navTitle(String title) { + return Column( + children: [ + Row( + children: [ + const SizedBox(width: 8), + BackButton( + onPressed: () => setState(() => page = 0), + ), + const SizedBox(width: 16), + Text( + title, + style: Theme.of(context).textTheme.titleLarge, + ) + ], + ), + const SizedBox(height: 12), + const Divider(height: 1), + const SizedBox(height: 12), + ], + ); + } +} + +Future showSubSelection(BuildContext context) { + return showDialog( + context: context, + builder: (context) { + return Consumer( + builder: (context, ref, child) { + final playbackModel = ref.watch(playBackModel); + final player = ref.watch(videoPlayerProvider); + return SimpleDialog( + contentPadding: EdgeInsets.only(top: 8, bottom: 24), + title: Row( + children: [ + const Text("Subtitle"), + const Spacer(), + IconButton.outlined( + onPressed: () { + Navigator.pop(context); + showSubtitleControls( + context: context, + label: 'Subtitle configuration', + ); + }, + icon: const Icon(Icons.display_settings_rounded)) + ], + ), + children: playbackModel?.subStreams?.mapIndexed( + (index, subModel) { + final selected = playbackModel.mediaStreams?.defaultSubStreamIndex == subModel.index; + return ListTile( + title: Text(subModel.displayTitle), + tileColor: selected ? Theme.of(context).colorScheme.primary.withOpacity(0.3) : null, + subtitle: subModel.language.isNotEmpty + ? Opacity(opacity: 0.6, child: Text(subModel.language.capitalize())) + : null, + onTap: () async { + final newModel = await playbackModel.setSubtitle(subModel, player); + ref.read(playBackModel.notifier).update((state) => newModel); + if (newModel != null) { + await ref.read(playbackModelHelper).shouldReload(newModel); + } + }, + ); + }, + ).toList(), + ); + }, + ); + }, + ); +} + +Future showAudioSelection(BuildContext context) { + return showDialog( + context: context, + builder: (context) { + return Consumer( + builder: (context, ref, child) { + final playbackModel = ref.watch(playBackModel); + final player = ref.watch(videoPlayerProvider); + return SimpleDialog( + contentPadding: EdgeInsets.only(top: 8, bottom: 24), + title: Row( + children: [ + const Text("Subtitle"), + const Spacer(), + IconButton.outlined( + onPressed: () { + Navigator.pop(context); + showSubtitleControls( + context: context, + label: 'Subtitle configuration', + ); + }, + icon: const Icon(Icons.display_settings_rounded)) + ], + ), + children: playbackModel?.audioStreams?.mapIndexed( + (index, audioStream) { + final selected = playbackModel.mediaStreams?.defaultAudioStreamIndex == audioStream.index; + return ListTile( + title: Text(audioStream.displayTitle), + tileColor: selected ? Theme.of(context).colorScheme.primary.withOpacity(0.3) : null, + subtitle: audioStream.language.isNotEmpty + ? Opacity(opacity: 0.6, child: Text(audioStream.language.capitalize())) + : null, + onTap: () async { + final newModel = await playbackModel.setAudio(audioStream, player); + ref.read(playBackModel.notifier).update((state) => newModel); + if (newModel != null) { + await ref.read(playbackModelHelper).shouldReload(newModel); + } + }); + }, + ).toList(), + ); + }, + ); + }, + ); +} diff --git a/lib/screens/video_player/components/video_player_queue.dart b/lib/screens/video_player/components/video_player_queue.dart new file mode 100644 index 0000000..54f8a91 --- /dev/null +++ b/lib/screens/video_player/components/video_player_queue.dart @@ -0,0 +1,153 @@ +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/screens/shared/media/item_detail_list_widget.dart'; +import 'package:fladder/util/widget_extensions.dart'; +import 'package:fladder/widgets/navigation_scaffold/components/fladder_appbar.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +showFullScreenItemQueue( + BuildContext context, { + required List items, + ValueChanged>? onListChanged, + Function(ItemBaseModel itemStreamModel)? playSelected, + ItemBaseModel? currentItem, +}) { + showDialog( + useSafeArea: false, + useRootNavigator: true, + context: context, + builder: (context) { + return Dialog.fullscreen( + child: VideoPlayerQueue( + items: items, + currentItem: currentItem, + playSelected: playSelected, + ), + ); + }, + ); +} + +class VideoPlayerQueue extends ConsumerStatefulWidget { + final List items; + final ItemBaseModel? currentItem; + final Function(ItemBaseModel)? playSelected; + final ValueChanged>? onListChanged; + + const VideoPlayerQueue({super.key, required this.items, this.currentItem, this.playSelected, this.onListChanged}); + + @override + ConsumerState createState() => _VideoPlayerQueueState(); +} + +class _VideoPlayerQueueState extends ConsumerState { + late final List items = widget.items; + final controller = ScrollController(); + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: const FladderAppbar( + label: "", + automaticallyImplyLeading: true, + ), + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 64), + child: Row( + children: [ + const BackButton(), + Column( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Queue", + style: Theme.of(context).textTheme.headlineLarge?.copyWith(fontWeight: FontWeight.bold), + ), + Opacity( + opacity: 0.5, + child: Text( + "${items.length} items", + style: Theme.of(context).textTheme.titleMedium, + ), + ), + ], + ), + ], + ), + ), + const Divider(), + Flexible( + child: ReorderableListView.builder( + shrinkWrap: true, + padding: const EdgeInsets.symmetric(horizontal: 64).copyWith(bottom: 64), + scrollController: controller, + itemCount: items.length, + proxyDecorator: (child, index, animation) { + return child; + }, + onReorder: (int oldIndex, int newIndex) { + setState(() { + if (oldIndex < newIndex) { + newIndex -= 1; + } + final ItemBaseModel item = items.removeAt(oldIndex); + items.insert(newIndex, item); + }); + // ref.read(videoPlaybackProvider.notifier).setQueue(items); + }, + itemBuilder: (context, index) { + final item = items[index]; + final isCurrentItem = item.id == (widget.currentItem?.id ?? ""); + return Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: SizedBox( + height: 125, + child: ItemDetailListWidget( + item: item, + elevation: isCurrentItem ? 50 : 1, + iconOverlay: !isCurrentItem + ? IconButton( + onPressed: () { + widget.playSelected?.call(item); + Navigator.of(context).pop(); + }, + iconSize: 80, + icon: const Icon( + Icons.play_arrow_rounded, + ), + ) + : const IconButton( + onPressed: null, + iconSize: 80, + icon: Icon(Icons.play_arrow_rounded), + ), + actions: [ + if (!isCurrentItem) + IconButton( + onPressed: () { + setState(() { + items.remove(item); + }); + // ref.read(videoPlaybackProvider.notifier).setQueue(items); + }, + icon: const Icon( + Icons.delete_rounded, + ), + ) + ], + ), + ), + ).setKey( + Key('$index'), + ); + }, + ), + ), + ], + ), + ); + } +} diff --git a/lib/screens/video_player/components/video_progress_bar.dart b/lib/screens/video_player/components/video_progress_bar.dart new file mode 100644 index 0000000..8a60d93 --- /dev/null +++ b/lib/screens/video_player/components/video_progress_bar.dart @@ -0,0 +1,414 @@ +import 'dart:math' as math; + +import 'package:collection/collection.dart'; +import 'package:fladder/models/items/chapters_model.dart'; +import 'package:fladder/models/items/intro_skip_model.dart'; +import 'package:fladder/providers/video_player_provider.dart'; +import 'package:fladder/util/duration_extensions.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/string_extensions.dart'; +import 'package:fladder/widgets/gapped_container_shape.dart'; +import 'package:fladder/widgets/shared/fladder_slider.dart'; +import 'package:fladder/widgets/shared/trickplay_image.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class ChapterProgressSlider extends ConsumerStatefulWidget { + final Function(bool value) wasPlayingChanged; + final bool wasPlaying; + final VoidCallback timerReset; + final Duration duration; + final Duration position; + final bool buffering; + final Duration buffer; + final Function(Duration duration) onPositionChanged; + const ChapterProgressSlider({ + required this.wasPlayingChanged, + required this.wasPlaying, + required this.timerReset, + required this.onPositionChanged, + required this.duration, + required this.position, + required this.buffering, + required this.buffer, + super.key, + }); + + @override + ConsumerState createState() => _ChapterProgressSliderState(); +} + +class _ChapterProgressSliderState extends ConsumerState { + bool onHoverStart = false; + bool onDragStart = false; + double _chapterPosition = 0.0; + double imageBottomOffset = 0.0; + double chapterCardWidth = 250; + Duration currentDuration = Duration.zero; + + @override + Widget build(BuildContext context) { + final List chapters = ref.read(playBackModel.select((value) => value?.chapters ?? [])); + final isVisible = (onDragStart ? true : onHoverStart); + final player = ref.watch(videoPlayerProvider); + final position = onDragStart ? currentDuration : widget.position; + final IntroOutSkipModel? introOutro = ref.read(playBackModel.select((value) => value?.introSkipModel)); + final relativeFraction = position.inMilliseconds / widget.duration.inMilliseconds; + return LayoutBuilder( + builder: (context, constraints) { + final sliderHeight = SliderTheme.of(context).trackHeight ?? (constraints.maxHeight / 3); + final bufferWidth = calculateFracionWidth(constraints, widget.buffer); + final bufferFraction = relativeFraction / (bufferWidth / constraints.maxWidth); + return Stack( + clipBehavior: Clip.none, + children: [ + Align( + alignment: Alignment.center, + child: MouseRegion( + opaque: !widget.buffering, + onHover: (event) { + setState(() { + onHoverStart = true; + _updateSliderPosition(event.localPosition.dx, constraints.maxWidth); + }); + }, + onExit: (event) { + setState(() { + onHoverStart = false; + }); + }, + child: Listener( + onPointerDown: (event) { + setState(() { + onDragStart = true; + _updateSliderPosition(event.localPosition.dx, constraints.maxWidth); + }); + }, + onPointerMove: (event) { + _updateSliderPosition(event.localPosition.dx, constraints.maxWidth); + }, + onPointerUp: (_) { + setState(() { + onDragStart = false; + }); + }, + child: Opacity( + opacity: widget.buffering ? 0 : 1.0, + child: FladderSlider( + min: 0.0, + max: widget.duration.inMilliseconds.toDouble(), + animation: Duration.zero, + thumbWidth: 10.0, + showThumb: false, + value: (position.inMilliseconds).toDouble().clamp( + 0, + widget.duration.inMilliseconds.toDouble(), + ), + onChangeEnd: (e) async { + currentDuration = Duration(milliseconds: e.toInt()); + await player.seek(Duration(milliseconds: e ~/ 1)); + await Future.delayed(const Duration(milliseconds: 250)); + if (widget.wasPlaying) { + player.play(); + } + widget.timerReset.call(); + setState(() { + onHoverStart = false; + }); + }, + onChangeStart: (value) { + setState(() { + onHoverStart = true; + }); + widget.wasPlayingChanged.call(player.player?.state.playing ?? false); + player.pause(); + }, + onChanged: (e) { + currentDuration = Duration(milliseconds: e.toInt()); + widget.timerReset.call(); + }, + ), + ), + ), + ), + ), + IgnorePointer( + child: Stack( + alignment: Alignment.center, + children: [ + if (introOutro?.intro?.start != null && introOutro?.intro?.end != null) + Positioned( + left: calculateStartOffset(constraints, introOutro!.intro!.start), + right: calculateRightOffset(constraints, introOutro.intro!.end), + bottom: 0, + child: Container( + height: 6, + decoration: BoxDecoration( + color: Colors.greenAccent.withOpacity(0.8), + borderRadius: BorderRadius.circular( + 100, + ), + ), + ), + ), + if (introOutro?.credits?.start != null && introOutro?.credits?.end != null) + Positioned( + left: calculateStartOffset(constraints, introOutro!.credits!.start), + right: calculateRightOffset(constraints, introOutro.credits!.end), + bottom: 0, + child: Container( + height: 6, + decoration: BoxDecoration( + color: Colors.orangeAccent.withOpacity(0.8), + borderRadius: BorderRadius.circular( + 100, + ), + ), + ), + ), + if (!widget.buffering) ...{ + //VideoBufferBar + Positioned( + left: 0, + child: SizedBox( + width: (constraints.maxWidth / (widget.duration.inMilliseconds / widget.buffer.inMilliseconds)), + height: sliderHeight, + child: GappedContainerShape( + activeColor: Theme.of(context).colorScheme.primary.withOpacity(0.5), + inActiveColor: Theme.of(context).colorScheme.primary.withOpacity(0.5), + thumbPosition: bufferFraction, + ), + ), + ), + } else + Align( + alignment: Alignment.center, + child: ClipRRect( + borderRadius: BorderRadius.circular(100), + child: LinearProgressIndicator( + backgroundColor: Colors.transparent, + minHeight: sliderHeight, + ), + ), + ), + if (chapters.isNotEmpty && !widget.buffering) ...{ + ...chapters.map( + (chapter) { + final offset = constraints.maxWidth / + (widget.duration.inMilliseconds / chapter.startPosition.inMilliseconds) + .clamp(1, constraints.maxWidth); + final activePosition = chapter.startPosition < widget.position; + if (chapter.startPosition.inSeconds == 0) return null; + return Positioned( + left: offset, + child: IgnorePointer( + child: Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: activePosition + ? Theme.of(context).colorScheme.onPrimary + : Theme.of(context).colorScheme.onSurface.withOpacity(0.5), + ), + height: constraints.maxHeight, + width: sliderHeight - (activePosition ? 2 : 4), + ), + ), + ); + }, + ).whereNotNull(), + }, + ], + ), + ), + if (!widget.buffering) ...[ + chapterCard(context, position, isVisible), + Positioned( + left: (constraints.maxWidth / (widget.duration.inMilliseconds / position.inMilliseconds)), + child: Transform.translate( + offset: Offset(-(constraints.maxHeight / 2), 0), + child: IgnorePointer( + child: SizedBox( + height: constraints.maxHeight, + width: constraints.maxHeight, + child: Center( + child: AnimatedContainer( + duration: const Duration(milliseconds: 125), + height: isVisible ? sliderHeight * 3.5 : sliderHeight, + width: sliderHeight, + alignment: Alignment.center, + decoration: BoxDecoration( + color: isVisible + ? Theme.of(context).colorScheme.onSurface + : Theme.of(context).colorScheme.primary, + borderRadius: BorderRadius.circular(8), + ), + ), + ), + ), + ), + ), + ), + ], + ], + ); + }, + ); + } + + double calculateFracionWidth(BoxConstraints constraints, Duration incoming) { + return (constraints.maxWidth * (incoming.inSeconds / widget.duration.inSeconds)).clamp(0, constraints.maxWidth); + } + + double calculateStartOffset(BoxConstraints constraints, Duration start) { + return (constraints.maxWidth * (start.inSeconds / widget.duration.inSeconds)).clamp(0, constraints.maxWidth); + } + + double calculateEndOffset(BoxConstraints constraints, Duration end) { + return (constraints.maxWidth * (end.inSeconds / widget.duration.inSeconds)).clamp(0, constraints.maxWidth); + } + + double calculateRightOffset(BoxConstraints constraints, Duration end) { + double endOffset = calculateEndOffset(constraints, end); + return constraints.maxWidth - endOffset; + } + + Widget chapterCard(BuildContext context, Duration duration, bool visible) { + const double height = 350; + final currentStream = ref.watch(playBackModel.select((value) => value)); + final chapter = (currentStream?.chapters ?? []).getChapterFromDuration(currentDuration); + final trickPlay = currentStream?.trickPlay; + final screenWidth = MediaQuery.of(context).size.width; + final calculatedPosition = _chapterPosition.clamp(-50, screenWidth - (chapterCardWidth + 45)).toDouble(); + final offsetDifference = _chapterPosition - calculatedPosition; + return Positioned( + left: calculatedPosition, + child: IgnorePointer( + child: AnimatedOpacity( + opacity: visible ? 1 : 0, + duration: const Duration(milliseconds: 250), + child: ConstrainedBox( + constraints: BoxConstraints(maxHeight: height, maxWidth: chapterCardWidth), + child: Transform.translate( + offset: const Offset(0, -height - 10), + child: Align( + alignment: Alignment.bottomCenter, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: AnimatedSize( + duration: const Duration(milliseconds: 250), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + AnimatedContainer( + duration: const Duration(milliseconds: 250), + child: ConstrainedBox( + constraints: BoxConstraints(maxHeight: 250), + child: ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(8)), + child: trickPlay == null || trickPlay.images.isEmpty + ? chapter != null + ? Image( + image: chapter.imageProvider, + fit: BoxFit.contain, + ) + : SizedBox.shrink() + : AspectRatio( + aspectRatio: trickPlay.width.toDouble() / trickPlay.height.toDouble(), + child: TrickplayImage( + trickPlay, + position: currentDuration, + ), + ), + ), + ), + ), + Stack( + alignment: Alignment.bottomCenter, + children: [ + Transform.translate( + offset: Offset(offsetDifference, 10), + child: Transform.rotate( + angle: -math.pi / 4, + child: Container( + height: 30, + width: 30, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: BorderRadius.circular(8), + ), + ), + ), + ), + Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: BorderRadius.circular(8), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + if (chapter?.name.isNotEmpty ?? false) + Flexible( + child: Text( + chapter?.name.capitalize() ?? "", + style: Theme.of(context) + .textTheme + .titleSmall + ?.copyWith(fontWeight: FontWeight.bold), + ), + ), + Text( + currentDuration.readAbleDuration, + textAlign: TextAlign.center, + style: + Theme.of(context).textTheme.titleSmall?.copyWith(fontWeight: FontWeight.bold), + ) + ], + ), + ), + ), + ], + ), + ].addPadding(const EdgeInsets.symmetric(vertical: 4)), + ), + ), + ), + ), + ), + ), + ), + ), + ); + } + + void _updateSliderPosition(double xPosition, double maxWidth) { + if (widget.buffering) return; + setState(() { + _chapterPosition = xPosition - chapterCardWidth / 2; + final value = ((maxWidth - xPosition) / maxWidth - 1).abs(); + currentDuration = Duration(milliseconds: (widget.duration.inMilliseconds * value).toInt()); + }); + } +} + +class CustomTrackShape extends RoundedRectSliderTrackShape { + @override + Rect getPreferredRect({ + required RenderBox parentBox, + Offset offset = Offset.zero, + required SliderThemeData sliderTheme, + bool isEnabled = false, + bool isDiscrete = false, + }) { + final trackHeight = sliderTheme.trackHeight; + final trackLeft = offset.dx; + final trackTop = offset.dy + (parentBox.size.height - trackHeight!) / 2; + final trackWidth = parentBox.size.width; + return Rect.fromLTWH(trackLeft, trackTop, trackWidth, trackHeight); + } +} diff --git a/lib/screens/video_player/components/video_subtitle_controls.dart b/lib/screens/video_player/components/video_subtitle_controls.dart new file mode 100644 index 0000000..f2dfb56 --- /dev/null +++ b/lib/screens/video_player/components/video_subtitle_controls.dart @@ -0,0 +1,341 @@ +import 'package:fladder/providers/settings/subtitle_settings_provider.dart'; +import 'package:fladder/screens/shared/flat_button.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/widget_extensions.dart'; +import 'package:fladder/widgets/shared/fladder_slider.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +Future showSubtitleControls({ + required BuildContext context, + String? label, +}) async { + await showDialog( + context: context, + barrierColor: Colors.black.withOpacity(0.1), + builder: (context) => AlertDialog.adaptive( + backgroundColor: Colors.transparent, + elevation: 0, + content: ConstrainedBox( + constraints: BoxConstraints(minWidth: MediaQuery.sizeOf(context).width * 0.75), + child: VideoSubtitleControls(label: label)), + ), + ); + return; +} + +class VideoSubtitleControls extends ConsumerStatefulWidget { + final String? label; + const VideoSubtitleControls({this.label, super.key}); + + @override + ConsumerState createState() => _VideoSubtitleControlsState(); +} + +class _VideoSubtitleControlsState extends ConsumerState { + late final lastSettings = ref.read(subtitleSettingsProvider); + final controller = ScrollController(); + + Key? activeKey; + + bool showPartial = true; + bool hideControls = false; + + void setOpacity(Key? key) => setState(() { + activeKey = key; + showPartial = !(activeKey != null); + }); + + @override + Widget build(BuildContext context) { + final subSettings = ref.watch(subtitleSettingsProvider); + final provider = ref.read(subtitleSettingsProvider.notifier); + final controlsHidden = hideControls ? false : showPartial; + return AnimatedContainer( + duration: const Duration(milliseconds: 250), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(16), + color: controlsHidden ? Theme.of(context).dialogBackgroundColor.withOpacity(0.75) : Colors.transparent, + ), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + if (widget.label?.isNotEmpty == true) + Text( + widget.label!, + style: Theme.of(context).textTheme.headlineMedium, + ), + IconButton.filledTonal( + isSelected: !hideControls, + onPressed: () => setState(() => hideControls = !hideControls), + icon: Icon(hideControls ? Icons.visibility_rounded : Icons.visibility_off_rounded), + ), + Flexible( + child: IgnorePointer( + ignoring: !controlsHidden, + child: Scrollbar( + thumbVisibility: controlsHidden, + controller: controller, + child: SingleChildScrollView( + controller: controller, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + ElevatedButton( + onPressed: subSettings != lastSettings + ? () => provider.resetSettings(value: lastSettings) + : null, + child: Text(context.localized.clearChanges), + ), + const SizedBox(width: 32), + ElevatedButton( + onPressed: () => provider.resetSettings(), + child: Text(context.localized.useDefaults), + ), + ], + ).addVisiblity(controlsHidden), + SegmentedButton( + showSelectedIcon: false, + multiSelectionEnabled: false, + segments: [ + ButtonSegment( + label: Text(context.localized.light, style: TextStyle(fontWeight: FontWeight.w100)), + value: FontWeight.w100, + ), + ButtonSegment( + label: Text(context.localized.normal, style: TextStyle(fontWeight: FontWeight.w500)), + value: FontWeight.normal, + ), + ButtonSegment( + label: Text(context.localized.bold, style: TextStyle(fontWeight: FontWeight.w900)), + value: FontWeight.bold, + ), + ], + selected: {subSettings.fontWeight}, + onSelectionChanged: (p0) { + provider.setFontWeight(p0.first); + }, + ).addVisiblity(controlsHidden), + Column( + children: [ + Row( + children: [ + const Icon(Icons.format_size_rounded), + Flexible( + child: FladderSlider( + min: 8.0, + max: 160.0, + onChangeStart: (value) => setOpacity(const Key('fontSize')), + onChangeEnd: (value) => setOpacity(null), + value: subSettings.fontSize.clamp(8.0, 160.0), + onChanged: (value) => provider.setFontSize(value.ceilToDouble()), + ), + ), + ConstrainedBox( + constraints: const BoxConstraints(minWidth: 35), + child: Text( + subSettings.fontSize.toStringAsFixed(0), + textAlign: TextAlign.center, + ), + ), + ], + ), + Text(context.localized.fontSize), + ], + ).addVisiblity(activeKey == null ? controlsHidden : activeKey == const Key('fontSize')), + Column( + children: [ + Row( + children: [ + const Icon(Icons.height_rounded), + Flexible( + child: FladderSlider( + min: 0.0, + max: 1.0, + divisions: 80, + onChangeStart: (value) => setOpacity(const Key('verticalOffset')), + onChangeEnd: (value) => setOpacity(null), + value: subSettings.verticalOffset.clamp(0, 1), + onChanged: (value) => provider.setVerticalOffset(value), + ), + ), + ConstrainedBox( + constraints: const BoxConstraints( + minWidth: 35, + ), + child: Text( + subSettings.verticalOffset.toStringAsFixed(2), + textAlign: TextAlign.center, + ), + ), + ], + ), + Text(context.localized.heightOffset), + ], + ).addVisiblity(activeKey == null ? controlsHidden : activeKey == const Key('verticalOffset')), + Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Icon(Icons.color_lens_rounded), + ...[Colors.white, Colors.yellow, Colors.black, Colors.grey].map( + (e) => FlatButton( + onTap: () => provider.setSubColor(e), + borderRadiusGeometry: BorderRadius.circular(5), + clipBehavior: Clip.antiAlias, + child: Container( + height: 25, + width: 25, + color: e, + ), + ), + ), + ], + ), + Text(context.localized.fontColor), + ], + ).addVisiblity(controlsHidden), + Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Icon(Icons.border_color_rounded), + ...[Colors.white, Colors.yellow, Colors.black, Colors.grey, Colors.transparent].map( + (e) => FlatButton( + onTap: () => + provider.setOutlineColor(e == Colors.transparent ? e : e.withOpacity(0.85)), + borderRadiusGeometry: BorderRadius.circular(5), + clipBehavior: Clip.antiAlias, + child: Container( + height: 25, + width: 25, + color: e == Colors.transparent ? Colors.white : e, + child: e == Colors.transparent + ? const Icon( + Icons.disabled_by_default_outlined, + color: Colors.red, + ) + : null, + ), + ), + ), + ], + ), + Text(context.localized.outlineColor), + ], + ).addVisiblity(controlsHidden), + Column( + children: [ + Row( + children: [ + const Icon(Icons.border_style), + Flexible( + child: FladderSlider( + min: 1, + max: 25, + divisions: 24, + onChangeStart: (value) => setOpacity(const Key('outlineSize')), + onChangeEnd: (value) => setOpacity(null), + value: subSettings.outlineSize.clamp(1, 24), + onChanged: (value) => provider.setOutlineThickness(value), + ), + ), + ConstrainedBox( + constraints: const BoxConstraints( + minWidth: 35, + ), + child: Text( + subSettings.outlineSize.toStringAsFixed(2), + textAlign: TextAlign.center, + ), + ), + ], + ), + Text(context.localized.outlineSize), + ], + ).addVisiblity(activeKey == null ? controlsHidden : activeKey == const Key('outlineSize')), + Column( + children: [ + Row( + children: [ + const Icon(Icons.square_rounded), + Flexible( + child: FladderSlider( + min: 0, + max: 1, + divisions: 20, + onChangeStart: (value) => setOpacity(const Key('backGroundOpacity')), + onChangeEnd: (value) => setOpacity(null), + value: subSettings.backGroundColor.opacity.clamp(0, 1), + onChanged: (value) => provider.setBackGroundOpacity(value), + ), + ), + ConstrainedBox( + constraints: const BoxConstraints( + minWidth: 35, + ), + child: Text( + subSettings.backGroundColor.opacity.toStringAsFixed(2), + textAlign: TextAlign.center, + ), + ), + ], + ), + Text(context.localized.backgroundOpacity), + ], + ).addVisiblity( + activeKey == null ? controlsHidden : activeKey == const Key('backGroundOpacity')), + Column( + children: [ + Row( + children: [ + const Icon(Icons.blur_circular_rounded), + Flexible( + child: FladderSlider( + min: 0, + max: 1, + divisions: 20, + value: subSettings.shadow.clamp(0, 1), + onChangeStart: (value) => setOpacity(const Key('shadowSlider')), + onChangeEnd: (value) => setOpacity(null), + onChanged: (value) => provider.setShadowIntensity(value), + ), + ), + ConstrainedBox( + constraints: const BoxConstraints( + minWidth: 35, + ), + child: Text( + subSettings.shadow.toStringAsFixed(2), + textAlign: TextAlign.center, + ), + ), + ], + ), + Text(context.localized.shadow) + ], + ).addVisiblity(activeKey == null ? controlsHidden : activeKey == const Key('shadowSlider')), + ].addPadding(const EdgeInsets.symmetric(vertical: 12)), + ), + ), + ), + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/screens/video_player/components/video_subtitles.dart b/lib/screens/video_player/components/video_subtitles.dart new file mode 100644 index 0000000..8a56d84 --- /dev/null +++ b/lib/screens/video_player/components/video_subtitles.dart @@ -0,0 +1,64 @@ +import 'dart:async'; + +import 'package:fladder/providers/settings/subtitle_settings_provider.dart'; +import 'package:flutter/material.dart'; + +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:media_kit_video/media_kit_video.dart'; + +import 'package:fladder/models/settings/subtitle_settings_model.dart'; + +class VideoSubtitles extends ConsumerStatefulWidget { + final VideoController controller; + final bool overlayed; + const VideoSubtitles({ + required this.controller, + this.overlayed = false, + super.key, + }); + + @override + ConsumerState createState() => _VideoSubtitlesState(); +} + +class _VideoSubtitlesState extends ConsumerState { + late List subtitle = widget.controller.player.state.subtitle; + StreamSubscription>? subscription; + + @override + void initState() { + subscription = widget.controller.player.stream.subtitle.listen((value) { + setState(() { + subtitle = value; + }); + }); + super.initState(); + } + + @override + void dispose() { + subscription?.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final settings = ref.watch(subtitleSettingsProvider); + final padding = MediaQuery.of(context).padding; + final text = [ + for (final line in subtitle) + if (line.trim().isNotEmpty) line.trim(), + ].join('\n'); + + if (widget.controller.player.platform?.configuration.libass ?? false) { + return const IgnorePointer(child: SizedBox()); + } else { + return SubtitleText( + subModel: settings, + padding: padding, + offset: (widget.overlayed ? 0.5 : settings.verticalOffset), + text: text, + ); + } + } +} diff --git a/lib/screens/video_player/components/video_volume_slider.dart b/lib/screens/video_player/components/video_volume_slider.dart new file mode 100644 index 0000000..910f2d5 --- /dev/null +++ b/lib/screens/video_player/components/video_volume_slider.dart @@ -0,0 +1,76 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/providers/settings/video_player_settings_provider.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/widgets/shared/fladder_slider.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class VideoVolumeSlider extends ConsumerStatefulWidget { + final double? width; + final Function()? onChanged; + const VideoVolumeSlider({this.width, this.onChanged, super.key}); + + @override + ConsumerState createState() => _VideoVolumeSliderState(); +} + +class _VideoVolumeSliderState extends ConsumerState { + bool sliderActive = false; + + @override + Widget build(BuildContext context) { + final volume = ref.watch(videoPlayerSettingsProvider.select((value) => value.volume)); + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + icon: Icon(volumeIcon(volume)), + onPressed: () => ref.read(videoPlayerSettingsProvider.notifier).setVolume(0), + ), + AnimatedSize( + duration: const Duration(milliseconds: 250), + child: SizedBox( + height: 30, + width: 75, + child: FladderSlider( + min: 0, + max: 100, + value: volume, + onChangeStart: (value) { + setState(() { + sliderActive = true; + }); + }, + onChangeEnd: (value) { + setState(() { + sliderActive = false; + }); + }, + onChanged: (value) { + widget.onChanged?.call(); + ref.read(videoPlayerSettingsProvider.notifier).setVolume(value); + }, + ), + ), + ), + SizedBox( + width: 40, + child: Text( + (volume).toStringAsFixed(0), + textAlign: TextAlign.center, + ), + ), + ].addInBetween(SizedBox(width: 6)), + ); + } +} + +IconData volumeIcon(double value) { + if (value <= 0) { + return IconsaxOutline.volume_mute; + } + if (value < 50) { + return IconsaxOutline.volume_low; + } + return IconsaxOutline.volume_high; +} diff --git a/lib/screens/video_player/video_player.dart b/lib/screens/video_player/video_player.dart new file mode 100644 index 0000000..d43058a --- /dev/null +++ b/lib/screens/video_player/video_player.dart @@ -0,0 +1,153 @@ +import 'dart:async'; + +import 'package:fladder/models/media_playback_model.dart'; +import 'package:fladder/providers/settings/video_player_settings_provider.dart'; +import 'package:fladder/screens/video_player/video_player_controls.dart'; +import 'package:flutter/material.dart'; + +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:media_kit_video/media_kit_video.dart'; + +import 'package:fladder/providers/video_player_provider.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/themes_data.dart'; + +class VideoPlayer extends ConsumerStatefulWidget { + const VideoPlayer({super.key}); + + @override + ConsumerState createState() => _VideoPlayerState(); +} + +class _VideoPlayerState extends ConsumerState with WidgetsBindingObserver { + double lastScale = 0.0; + + bool errorPlaying = false; + bool playing = false; + + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + //Don't pause on desktop focus loss + if (!AdaptiveLayout.of(context).isDesktop) { + switch (state) { + case AppLifecycleState.resumed: + if (playing) ref.read(videoPlayerProvider).play(); + break; + case AppLifecycleState.hidden: + case AppLifecycleState.paused: + case AppLifecycleState.detached: + if (playing) ref.read(videoPlayerProvider).pause(); + break; + default: + break; + } + } + } + + @override + void dispose() { + WidgetsBinding.instance.removeObserver(this); + super.dispose(); + } + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addObserver(this); + Future.microtask(() { + ref.read(mediaPlaybackProvider.notifier).update((state) => state.copyWith(state: VideoPlayerState.fullScreen)); + return ref.read(videoPlayerSettingsProvider.notifier).setSavedBrightness(); + }); + } + + @override + Widget build(BuildContext context) { + final playerProvider = ref.watch(videoPlayerProvider); + ref.listen(videoPlayerSettingsProvider.select((value) => value.volume), (previous, next) { + playerProvider.setVolume(next); + }); + final videoPlayerSettings = ref.watch(videoPlayerSettingsProvider); + final padding = MediaQuery.of(context).padding; + + final playerController = playerProvider.controller; + + return Material( + color: Colors.black, + child: Theme( + data: ThemesData.of(context).dark, + child: Container( + color: Colors.black, + child: GestureDetector( + onScaleUpdate: (details) { + lastScale = details.scale; + }, + onScaleEnd: (details) { + if (lastScale < 1.0) { + ref.read(videoPlayerSettingsProvider.notifier).setFillScreen(false, context: context); + } else if (lastScale > 1.0) { + ref.read(videoPlayerSettingsProvider.notifier).setFillScreen(true, context: context); + } + lastScale = 0.0; + }, + child: Hero( + tag: "HeroPlayer", + child: Stack( + children: [ + if (playerController != null) + Padding( + padding: videoPlayerSettings.fillScreen + ? EdgeInsets.zero + : EdgeInsets.only(left: padding.left, right: padding.right), + child: OrientationBuilder(builder: (context, orientation) { + return Video( + key: Key("$videoPlayerSettings|$orientation"), + controller: playerController, + fill: Colors.transparent, + wakelock: true, + fit: videoPlayerSettings.fillScreen + ? (MediaQuery.of(context).orientation == Orientation.portrait + ? videoPlayerSettings.videoFit + : BoxFit.cover) + : videoPlayerSettings.videoFit, + subtitleViewConfiguration: const SubtitleViewConfiguration(visible: false), + controls: NoVideoControls, + ); + }), + ), + DesktopControls(), + if (errorPlaying) const _VideoErrorWidget(), + ], + ), + ), + ), + ), + ), + ); + } +} + +class _VideoErrorWidget extends StatelessWidget { + const _VideoErrorWidget(); + + @override + Widget build(BuildContext context) { + return Center( + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.error_rounded, + size: 46, + color: Theme.of(context).colorScheme.error, + ), + const SizedBox(width: 8), + Text( + "Error playing file", + style: Theme.of(context).textTheme.headlineMedium, + ), + ], + ), + ); + } +} diff --git a/lib/screens/video_player/video_player_controls.dart b/lib/screens/video_player/video_player_controls.dart new file mode 100644 index 0000000..913415a --- /dev/null +++ b/lib/screens/video_player/video_player_controls.dart @@ -0,0 +1,625 @@ +import 'dart:async'; +import 'dart:developer'; + +import 'package:async/async.dart'; +import 'package:collection/collection.dart'; +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/items/intro_skip_model.dart'; +import 'package:fladder/models/media_playback_model.dart'; +import 'package:fladder/models/playback/playback_model.dart'; +import 'package:fladder/providers/settings/video_player_settings_provider.dart'; +import 'package:fladder/providers/video_player_provider.dart'; +import 'package:fladder/screens/shared/default_titlebar.dart'; +import 'package:fladder/screens/video_player/components/video_playback_information.dart'; +import 'package:fladder/screens/video_player/components/video_player_controls_extras.dart'; +import 'package:fladder/screens/video_player/components/video_player_options_sheet.dart'; +import 'package:fladder/screens/video_player/components/video_progress_bar.dart'; +import 'package:fladder/screens/video_player/components/video_subtitles.dart'; +import 'package:fladder/screens/video_player/components/video_volume_slider.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/duration_extensions.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/string_extensions.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:intl/intl.dart'; +import 'package:screen_brightness/screen_brightness.dart'; +import 'package:window_manager/window_manager.dart'; + +class DesktopControls extends ConsumerStatefulWidget { + const DesktopControls({super.key}); + + @override + ConsumerState createState() => _DesktopControlsState(); +} + +class _DesktopControlsState extends ConsumerState { + final fadeDuration = const Duration(milliseconds: 350); + final focusNode = FocusNode(); + bool showOverlay = true; + bool wasPlaying = false; + + late final double topPadding = MediaQuery.of(context).viewPadding.top; + late final double bottomPadding = MediaQuery.of(context).viewPadding.bottom; + + Future clear() async { + toggleOverlay(value: true); + if (!AdaptiveLayout.of(context).isDesktop) { + ScreenBrightness().resetScreenBrightness(); + } else { + disableFullscreen(); + } + timer.cancel(); + } + + void resetTimer() => timer.reset(); + + Future closePlayer() async { + clear(); + ref.read(videoPlayerProvider).stop(); + Navigator.of(context).pop(); + } + + @override + Widget build(BuildContext context) { + final mediaPlayback = ref.watch(mediaPlaybackProvider); + final introSkipModel = ref.watch(playBackModel.select((value) => value?.introSkipModel)); + final player = ref.watch(videoPlayerProvider); + bool showIntroSkipButton = introSkipModel?.introInRange(mediaPlayback.position) ?? false; + bool showCreditSkipButton = introSkipModel?.creditsInRange(mediaPlayback.position) ?? false; + if (AdaptiveLayout.of(context).isDesktop) { + focusNode.requestFocus(); + } + + return Listener( + onPointerSignal: (event) { + log('Timer reset'); + resetTimer(); + }, + child: PopScope( + canPop: false, + onPopInvoked: (didPop) { + if (!didPop) { + closePlayer(); + } + }, + child: KeyboardListener( + focusNode: focusNode, + autofocus: AdaptiveLayout.of(context).inputDevice == InputDevice.pointer, + onKeyEvent: (value) { + if (value is KeyRepeatEvent) {} + if (value is KeyDownEvent) { + if (value.logicalKey == LogicalKeyboardKey.keyS) { + if (showIntroSkipButton) { + skipIntro(introSkipModel); + } else if (showCreditSkipButton) { + skipCredits(introSkipModel); + } + focusNode.requestFocus(); + } + if (value.logicalKey == LogicalKeyboardKey.escape) { + disableFullscreen(); + } + if (value.logicalKey == LogicalKeyboardKey.space) { + ref.read(videoPlayerProvider).playOrPause(); + } + if (value.logicalKey == LogicalKeyboardKey.arrowLeft) { + seekBack(mediaPlayback); + } + if (value.logicalKey == LogicalKeyboardKey.arrowRight) { + seekForward(mediaPlayback); + } + if (value.logicalKey == LogicalKeyboardKey.keyF) { + toggleFullScreen(); + } + if (AdaptiveLayout.of(context).isDesktop || kIsWeb) { + if (value.logicalKey == LogicalKeyboardKey.arrowUp) { + resetTimer(); + ref.read(videoPlayerSettingsProvider.notifier).steppedVolume(5); + } + if (value.logicalKey == LogicalKeyboardKey.arrowDown) { + resetTimer(); + ref.read(videoPlayerSettingsProvider.notifier).steppedVolume(-5); + } + } + focusNode.requestFocus(); + } + }, + child: GestureDetector( + onTap: () => toggleOverlay(), + child: MouseRegion( + cursor: showOverlay ? SystemMouseCursors.basic : SystemMouseCursors.none, + onEnter: (event) => toggleOverlay(value: true), + onExit: (event) => toggleOverlay(value: false), + onHover: AdaptiveLayout.of(context).isDesktop || kIsWeb ? (event) => toggleOverlay(value: true) : null, + child: Stack( + children: [ + if (player.controller != null) + VideoSubtitles( + key: const Key('subtitles'), + controller: player.controller!, + overlayed: showOverlay, + ), + if (AdaptiveLayout.of(context).isDesktop) playButton(mediaPlayback), + IgnorePointer( + ignoring: !showOverlay, + child: AnimatedOpacity( + duration: fadeDuration, + opacity: showOverlay ? 1 : 0, + child: Column( + children: [ + topButtons(context), + const Spacer(), + bottomButtons(context, mediaPlayback), + ], + ), + ), + ), + if (showIntroSkipButton) + Align( + alignment: Alignment.centerRight, + child: Padding( + padding: const EdgeInsets.all(32), + child: IntroSkipButton( + isOverlayVisible: showOverlay, + skipIntro: () => skipIntro(introSkipModel), + ), + ), + ), + if (showCreditSkipButton) + Align( + alignment: Alignment.centerRight, + child: Padding( + padding: const EdgeInsets.all(32), + child: CreditsSkipButton( + isOverlayVisible: showOverlay, + skipCredits: () => skipCredits(introSkipModel), + ), + ), + ) + ], + ), + ), + ), + ), + ), + ); + } + + Widget playButton(MediaPlaybackModel mediaPlayback) { + return Align( + alignment: Alignment.center, + child: AnimatedScale( + curve: Curves.easeInOutCubicEmphasized, + scale: mediaPlayback.playing + ? 0 + : mediaPlayback.buffering + ? 0 + : 1, + duration: const Duration(milliseconds: 250), + child: IconButton.outlined( + onPressed: () => ref.read(videoPlayerProvider).play(), + isSelected: true, + iconSize: 65, + tooltip: "Resume video", + icon: const Icon(IconsaxBold.play), + ), + ), + ); + } + + Widget topButtons(BuildContext context) { + final currentItem = ref.watch(playBackModel.select((value) => value?.item)); + return Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Colors.black.withOpacity(0.8), + Colors.black.withOpacity(0), + ], + )), + child: Padding( + padding: + EdgeInsets.only(top: topPadding + (AdaptiveLayout.of(context).platform == TargetPlatform.macOS ? 28 : 0.0)), + child: Container( + alignment: Alignment.topCenter, + height: 80, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + IconButton( + onPressed: () { + clear(); + ref + .read(mediaPlaybackProvider.notifier) + .update((state) => state.copyWith(state: VideoPlayerState.minimized)); + Navigator.of(context).pop(); + }, + icon: Icon( + IconsaxOutline.arrow_down_1, + size: 24, + ), + ), + const SizedBox(width: 16), + if (!AdaptiveLayout.of(context).isDesktop) + Flexible( + child: Text( + currentItem?.title ?? "", + style: Theme.of(context).textTheme.titleLarge, + ), + ) + else + Flexible(child: Align(alignment: Alignment.topRight, child: DefaultTitleBar())) + ], + ), + ), + ), + ), + ); + } + + Widget bottomButtons(BuildContext context, MediaPlaybackModel mediaPlayback) { + return Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.bottomCenter, + end: Alignment.topCenter, + colors: [ + Colors.black.withOpacity(0.8), + Colors.black.withOpacity(0), + ], + )), + child: Padding( + padding: EdgeInsets.only(bottom: bottomPadding) + .copyWith(bottom: 21) + .add(EdgeInsets.symmetric(vertical: 16)) + .add(EdgeInsets.symmetric(horizontal: AdaptiveLayout.of(context).isDesktop ? 32 : 0)), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: progressBar(mediaPlayback), + ), + const SizedBox(height: 16), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Flexible( + flex: 2, + child: Row( + children: [ + IconButton( + onPressed: () => showVideoPlayerOptions(context), icon: const Icon(IconsaxOutline.more)), + if (AdaptiveLayout.layoutOf(context) == LayoutState.tablet) ...[ + IconButton( + onPressed: () => showSubSelection(context), + icon: const Icon(IconsaxOutline.subtitle), + ), + IconButton( + onPressed: () => showAudioSelection(context), + icon: const Icon(IconsaxOutline.audio_square), + ), + ], + if (AdaptiveLayout.layoutOf(context) == LayoutState.desktop) ...[ + Flexible( + child: ElevatedButton.icon( + onPressed: () => showSubSelection(context), + icon: const Icon(IconsaxOutline.subtitle), + label: Text( + ref + .watch(playBackModel.select((value) => value?.mediaStreams?.currentSubStream)) + ?.language + .capitalize() ?? + "Off", + maxLines: 1, + ), + ), + ), + Flexible( + child: ElevatedButton.icon( + onPressed: () => showAudioSelection(context), + icon: const Icon(IconsaxOutline.audio_square), + label: Text( + ref + .watch(playBackModel.select((value) => value?.mediaStreams?.currentAudioStream)) + ?.language + .capitalize() ?? + "Off", + maxLines: 1, + ), + ), + ) + ], + ].addInBetween(const SizedBox( + width: 4, + )), + ), + ), + previousButton, + seekBackwardButton(mediaPlayback), + IconButton.filledTonal( + iconSize: 38, + onPressed: () { + ref.read(videoPlayerProvider).playOrPause(); + }, + icon: Icon( + mediaPlayback.playing ? IconsaxBold.pause : IconsaxBold.play, + ), + ), + seekForwardButton(mediaPlayback), + nextVideoButton, + Flexible( + flex: 2, + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Tooltip( + message: "Stop", + child: IconButton(onPressed: () => closePlayer(), icon: Icon(IconsaxOutline.stop))), + const Spacer(), + if (AdaptiveLayout.of(context).isDesktop && ref.read(videoPlayerProvider).player != null) ...{ + // OpenQueueButton(x), + // ChapterButton( + // position: position, + // player: ref.read(videoPlayerProvider).player!, + // ), + Listener( + onPointerSignal: (event) { + if (event is PointerScrollEvent) { + if (event.scrollDelta.dy > 0) { + ref.read(videoPlayerSettingsProvider.notifier).steppedVolume(-5); + } else { + ref.read(videoPlayerSettingsProvider.notifier).steppedVolume(5); + } + } + }, + child: VideoVolumeSlider( + onChanged: () => resetTimer(), + ), + ), + FutureBuilder( + future: windowManager.isFullScreen(), + builder: (context, snapshot) { + final isFullScreen = snapshot.data ?? true; + return IconButton( + onPressed: () => windowManager.setFullScreen(!isFullScreen), + icon: Icon( + isFullScreen ? IconsaxOutline.close_square : IconsaxOutline.maximize_4, + ), + ); + }, + ), + } + ].addInBetween(const SizedBox(width: 8)), + ), + ), + ].addInBetween(const SizedBox(width: 6)), + ), + ], + ), + ), + ); + } + + Widget progressBar(MediaPlaybackModel mediaPlayback) { + return Consumer( + builder: (context, ref, child) { + final playbackModel = ref.watch(playBackModel); + final item = playbackModel?.item; + final List details = [ + if (AdaptiveLayout.of(context).isDesktop) item?.label(context), + mediaPlayback.duration.inMinutes > 1 + ? 'ends at ${DateFormat('HH:mm').format(DateTime.now().add(mediaPlayback.duration - mediaPlayback.position))}' + : null + ]; + return Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Row( + children: [ + Expanded( + child: Text( + details.whereNotNull().join(' - '), + style: Theme.of(context).textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.bold, + shadows: [ + const Shadow(blurRadius: 16), + ], + ), + maxLines: 2, + ), + ), + const Spacer(), + if (playbackModel.label != null) + InkWell( + onTap: () => showVideoPlaybackInformation(context), + child: Card( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + child: Text(playbackModel?.label ?? ""), + ), + ), + ), + if (item != null) ...{ + Card( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + child: Text('${item.streamModel?.displayProfile?.value} ${item.streamModel?.resolution?.value}'), + ), + ), + } + ].addPadding(EdgeInsets.symmetric(horizontal: 4)), + ), + const SizedBox(height: 4), + SizedBox( + height: 25, + child: ChapterProgressSlider( + wasPlayingChanged: (value) => wasPlaying = value, + wasPlaying: wasPlaying, + duration: mediaPlayback.duration, + position: mediaPlayback.position, + buffer: mediaPlayback.buffer, + buffering: mediaPlayback.buffering, + timerReset: () => timer.reset(), + onPositionChanged: (position) => ref.read(videoPlayerProvider).seek(position), + ), + ), + const SizedBox(height: 4), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(mediaPlayback.position.readAbleDuration), + Text("-${(mediaPlayback.duration - mediaPlayback.position).readAbleDuration}"), + ], + ), + ], + ); + }, + ); + } + + Widget get previousButton { + return Consumer( + builder: (context, ref, child) { + final previousVideo = ref.watch(playBackModel.select((value) => value?.previousVideo)); + final buffering = ref.watch(mediaPlaybackProvider.select((value) => value.buffering)); + + return Tooltip( + message: previousVideo?.detailedName(context) ?? "", + textAlign: TextAlign.center, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: Theme.of(context).colorScheme.surface.withOpacity(0.95), + ), + textStyle: Theme.of(context).textTheme.labelLarge, + child: IconButton( + onPressed: previousVideo != null && !buffering + ? () => ref.read(playbackModelHelper).loadNewVideo(previousVideo) + : null, + iconSize: 30, + icon: const Icon( + IconsaxOutline.backward, + ), + ), + ); + }, + ); + } + + Widget get nextVideoButton { + return Consumer( + builder: (context, ref, child) { + final nextVideo = ref.watch(playBackModel.select((value) => value?.nextVideo)); + final buffering = ref.watch(mediaPlaybackProvider.select((value) => value.buffering)); + return Tooltip( + message: nextVideo?.detailedName(context) ?? "", + textAlign: TextAlign.center, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: Theme.of(context).colorScheme.surface.withOpacity(0.95), + ), + textStyle: Theme.of(context).textTheme.labelLarge, + child: IconButton( + onPressed: + nextVideo != null && !buffering ? () => ref.read(playbackModelHelper).loadNewVideo(nextVideo) : null, + iconSize: 30, + icon: const Icon( + IconsaxOutline.forward, + ), + ), + ); + }, + ); + } + + Widget seekBackwardButton(MediaPlaybackModel mediaPlaybackModel) { + return IconButton( + onPressed: () => seekBack(mediaPlaybackModel), + tooltip: "-10", + iconSize: 40, + icon: const Icon( + IconsaxOutline.backward_10_seconds, + ), + ); + } + + Widget seekForwardButton(MediaPlaybackModel mediaPlaybackModel) { + return IconButton( + onPressed: () => seekForward(mediaPlaybackModel), + tooltip: "15", + iconSize: 40, + icon: Stack( + children: [ + const Icon(IconsaxOutline.forward_15_seconds), + ], + ), + ); + } + + void skipIntro(IntroOutSkipModel? introSkipModel) { + resetTimer(); + final end = introSkipModel?.intro?.end; + if (end != null) { + ref.read(videoPlayerProvider).seek(end); + } + } + + void skipCredits(IntroOutSkipModel? introSkipModel) { + resetTimer(); + final end = introSkipModel?.credits?.end; + if (end != null) { + ref.read(videoPlayerProvider).seek(end); + } + } + + void seekBack(MediaPlaybackModel mediaPlayback, {int seconds = 15}) { + resetTimer(); + final newPosition = (mediaPlayback.position.inSeconds - seconds).clamp(0, mediaPlayback.duration.inSeconds); + ref.read(videoPlayerProvider).seek(Duration(seconds: newPosition)); + } + + void seekForward(MediaPlaybackModel mediaPlayback, {int seconds = 15}) { + resetTimer(); + final newPosition = (mediaPlayback.position.inSeconds + seconds).clamp(0, mediaPlayback.duration.inSeconds); + ref.read(videoPlayerProvider).seek(Duration(seconds: newPosition)); + } + + late RestartableTimer timer = RestartableTimer( + const Duration(seconds: 5), + () => mounted ? toggleOverlay(value: false) : null, + ); + + void toggleOverlay({bool? value}) { + setState(() => showOverlay = (value ?? !showOverlay)); + resetTimer(); + SystemChrome.setEnabledSystemUIMode(showOverlay ? SystemUiMode.edgeToEdge : SystemUiMode.leanBack, overlays: []); + SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( + statusBarColor: Colors.transparent, + systemNavigationBarColor: Colors.transparent, + systemNavigationBarDividerColor: Colors.transparent, + )); + } + + Future disableFullscreen() async { + resetTimer(); + final isFullScreen = await windowManager.isFullScreen(); + if (isFullScreen) { + await windowManager.setFullScreen(false); + } + } + + Future toggleFullScreen() async { + final isFullScreen = await windowManager.isFullScreen(); + await windowManager.setFullScreen(!isFullScreen); + } +} diff --git a/lib/theme.dart b/lib/theme.dart new file mode 100644 index 0000000..36657b3 --- /dev/null +++ b/lib/theme.dart @@ -0,0 +1,135 @@ +import 'package:dynamic_color/dynamic_color.dart'; +import 'package:fladder/util/custom_color_themes.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; + +ColorScheme? generateDynamicColourSchemes(ColorScheme? theme) { + if (theme == null) return null; + var base = ColorScheme.fromSeed(seedColor: theme.primary, brightness: theme.brightness); + + var newScheme = _insertAdditionalColours(base); + + return newScheme.harmonized(); +} + +ColorScheme _insertAdditionalColours(ColorScheme scheme) => scheme.copyWith( + surface: scheme.surface, + surfaceDim: scheme.surfaceDim, + surfaceBright: scheme.surfaceBright, + surfaceContainerLowest: scheme.surfaceContainerLowest, + surfaceContainerLow: scheme.surfaceContainerLow, + surfaceContainer: scheme.surfaceContainer, + surfaceContainerHigh: scheme.surfaceContainerHigh, + surfaceContainerHighest: scheme.surfaceContainerHighest, + ); + +class FladderTheme { + static RoundedRectangleBorder get smallShape => RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)); + static RoundedRectangleBorder get defaultShape => RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)); + static RoundedRectangleBorder get largeShape => RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)); + + static Color get darkBackgroundColor => Color.fromARGB(255, 10, 10, 10); + static Color get lightBackgroundColor => Color.fromARGB(237, 255, 255, 255); + + static ThemeData theme(ColorScheme? colorScheme) { + final ColorScheme? scheme = generateDynamicColourSchemes(colorScheme); + + final textTheme = GoogleFonts.rubikTextTheme( + const TextTheme(), + ); + return ThemeData( + useMaterial3: true, + colorScheme: scheme, + sliderTheme: SliderThemeData( + trackHeight: 8, + thumbColor: colorScheme?.onSurface, + ), + cardTheme: CardTheme( + elevation: 3, + clipBehavior: Clip.antiAlias, + margin: EdgeInsets.zero, + shape: defaultShape, + ), + progressIndicatorTheme: ProgressIndicatorThemeData(), + floatingActionButtonTheme: FloatingActionButtonThemeData( + backgroundColor: scheme?.secondaryContainer, + foregroundColor: scheme?.onSecondaryContainer, + shape: defaultShape, + ), + snackBarTheme: SnackBarThemeData( + backgroundColor: scheme?.secondary, + behavior: SnackBarBehavior.fixed, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), + elevation: 5, + dismissDirection: DismissDirection.horizontal, + ), + tooltipTheme: TooltipThemeData( + textAlign: TextAlign.center, + waitDuration: Duration(milliseconds: 500), + textStyle: TextStyle( + color: scheme?.onSurface, + ), + decoration: BoxDecoration( + borderRadius: defaultShape.borderRadius, + color: scheme?.surface, + ), + ), + switchTheme: SwitchThemeData( + thumbIcon: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.selected)) { + return Icon(Icons.check_rounded); + } + return null; + }), + trackOutlineWidth: WidgetStatePropertyAll(1), + ), + iconButtonTheme: IconButtonThemeData( + style: ButtonStyle( + shape: WidgetStatePropertyAll(defaultShape), + ), + ), + navigationBarTheme: NavigationBarThemeData(), + dialogTheme: DialogTheme(shape: defaultShape), + scrollbarTheme: ScrollbarThemeData( + radius: Radius.circular(16), + thumbColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.hovered)) { + return colorScheme?.primary; + } + return null; + })), + checkboxTheme: CheckboxThemeData( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6), + ), + ), + bottomSheetTheme: BottomSheetThemeData( + backgroundColor: scheme?.surface, + ), + buttonTheme: ButtonThemeData(shape: defaultShape), + chipTheme: ChipThemeData( + side: BorderSide(width: 1, color: scheme?.onSurface.withOpacity(0.05) ?? Colors.white), + shape: defaultShape, + ), + popupMenuTheme: PopupMenuThemeData( + shape: defaultShape, + color: scheme?.secondaryContainer, + iconColor: scheme?.onSecondaryContainer, + surfaceTintColor: scheme?.onSecondaryContainer, + ), + listTileTheme: ListTileThemeData(shape: defaultShape), + elevatedButtonTheme: ElevatedButtonThemeData(style: ButtonStyle(shape: WidgetStatePropertyAll(defaultShape))), + filledButtonTheme: FilledButtonThemeData(style: ButtonStyle(shape: WidgetStatePropertyAll(defaultShape))), + outlinedButtonTheme: OutlinedButtonThemeData(style: ButtonStyle(shape: WidgetStatePropertyAll(defaultShape))), + textTheme: textTheme.copyWith( + titleMedium: textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w600, + ), + ), + ); + } + + static ColorScheme defaultScheme(Brightness brightness) { + return ColorScheme.fromSeed(seedColor: ColorThemes.fladder.color, brightness: brightness); + } +} diff --git a/lib/util/absorb_events.dart b/lib/util/absorb_events.dart new file mode 100644 index 0000000..399c6ac --- /dev/null +++ b/lib/util/absorb_events.dart @@ -0,0 +1,22 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class AbsorbEvents extends ConsumerWidget { + final bool absorb; + final Widget child; + const AbsorbEvents({super.key, required this.child, this.absorb = false}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + if (absorb) { + return GestureDetector( + onDoubleTap: () {}, + onTap: () {}, + onLongPress: () {}, + child: Container(color: Colors.black.withOpacity(0), child: child), + ); + } else { + return child; + } + } +} diff --git a/lib/util/adaptive_layout.dart b/lib/util/adaptive_layout.dart new file mode 100644 index 0000000..d538b45 --- /dev/null +++ b/lib/util/adaptive_layout.dart @@ -0,0 +1,193 @@ +import 'package:fladder/util/poster_defaults.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; + +import 'package:fladder/routes/app_routes.dart'; + +enum LayoutState { + phone, + tablet, + desktop, +} + +enum ScreenLayout { + single, + dual, +} + +enum InputDevice { + touch, + pointer, +} + +class LayoutPoints { + final double start; + final double end; + final LayoutState type; + LayoutPoints({ + required this.start, + required this.end, + required this.type, + }); + + LayoutPoints copyWith({ + double? start, + double? end, + LayoutState? type, + }) { + return LayoutPoints( + start: start ?? this.start, + end: end ?? this.end, + type: type ?? this.type, + ); + } + + @override + String toString() => 'LayoutPoints(start: $start, end: $end, type: $type)'; + + @override + bool operator ==(covariant LayoutPoints other) { + if (identical(this, other)) return true; + + return other.start == start && other.end == end && other.type == type; + } + + @override + int get hashCode => start.hashCode ^ end.hashCode ^ type.hashCode; +} + +class AdaptiveLayout extends InheritedWidget { + final LayoutState layout; + final ScreenLayout size; + final InputDevice inputDevice; + final TargetPlatform platform; + final bool isDesktop; + final GoRouter router; + final PosterDefaults posterDefaults; + + const AdaptiveLayout({ + super.key, + required this.layout, + required this.size, + required this.inputDevice, + required this.platform, + required this.isDesktop, + required this.router, + required this.posterDefaults, + required super.child, + }); + + static AdaptiveLayout? maybeOf(BuildContext context) { + return context.dependOnInheritedWidgetOfExactType(); + } + + static LayoutState layoutOf(BuildContext context) { + final AdaptiveLayout? result = maybeOf(context); + return result!.layout; + } + + static PosterDefaults poster(BuildContext context) { + final AdaptiveLayout? result = maybeOf(context); + return result!.posterDefaults; + } + + static GoRouter routerOf(BuildContext context) { + final AdaptiveLayout? result = maybeOf(context); + return result!.router; + } + + static AdaptiveLayout of(BuildContext context) { + final AdaptiveLayout? result = maybeOf(context); + return result!; + } + + @override + bool updateShouldNotify(AdaptiveLayout oldWidget) { + return layout != oldWidget.layout || + size != oldWidget.size || + platform != oldWidget.platform || + inputDevice != oldWidget.inputDevice || + isDesktop != oldWidget.isDesktop || + router != oldWidget.router; + } +} + +class AdaptiveLayoutBuilder extends ConsumerStatefulWidget { + final List layoutPoints; + final LayoutState fallBack; + final Widget child; + const AdaptiveLayoutBuilder({required this.layoutPoints, required this.child, required this.fallBack, super.key}); + + @override + ConsumerState createState() => _AdaptiveLayoutBuilderState(); +} + +class _AdaptiveLayoutBuilderState extends ConsumerState { + late LayoutState layout = widget.fallBack; + late ScreenLayout size = ScreenLayout.single; + late GoRouter router = AppRoutes.routes(ref: ref, screenLayout: size); + late TargetPlatform currentPlatform = defaultTargetPlatform; + + @override + void didChangeDependencies() { + calculateLayout(); + calculateSize(); + super.didChangeDependencies(); + } + + bool get isDesktop { + if (kIsWeb) return false; + return [ + TargetPlatform.macOS, + TargetPlatform.windows, + TargetPlatform.linux, + ].contains(currentPlatform); + } + + void calculateLayout() { + LayoutState? newType; + for (var element in widget.layoutPoints) { + if (MediaQuery.of(context).size.width > element.start && MediaQuery.of(context).size.width < element.end) { + newType = element.type; + } + } + if (newType == LayoutState.phone && isDesktop) { + newType = LayoutState.tablet; + } + layout = newType ?? widget.fallBack; + } + + void calculateSize() { + ScreenLayout newSize; + if (MediaQuery.of(context).size.width > 0 && MediaQuery.of(context).size.width < 960 && !isDesktop) { + newSize = ScreenLayout.single; + } else { + newSize = ScreenLayout.dual; + } + if (size != newSize) { + size = newSize; + router = AppRoutes.routes(ref: ref, screenLayout: size); + } + } + + @override + Widget build(BuildContext context) { + return AdaptiveLayout( + layout: layout, + size: size, + inputDevice: (isDesktop || kIsWeb) ? InputDevice.pointer : InputDevice.touch, + platform: currentPlatform, + isDesktop: isDesktop, + router: router, + posterDefaults: switch (layout) { + LayoutState.phone => PosterDefaults(size: 300, ratio: 0.55), + LayoutState.tablet => PosterDefaults(size: 350, ratio: 0.55), + LayoutState.desktop => PosterDefaults(size: 400, ratio: 0.55), + }, + child: widget.child, + ); + } +} diff --git a/lib/util/application_info.dart b/lib/util/application_info.dart new file mode 100644 index 0000000..ed1d985 --- /dev/null +++ b/lib/util/application_info.dart @@ -0,0 +1,38 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +final applicationInfoProvider = StateProvider((ref) { + return ApplicationInfo( + name: "", + version: "", + os: "", + ); +}); + +class ApplicationInfo { + final String name; + final String version; + final String os; + ApplicationInfo({ + required this.name, + required this.version, + required this.os, + }); + + ApplicationInfo copyWith({ + String? name, + String? version, + String? os, + }) { + return ApplicationInfo( + name: name ?? this.name, + version: version ?? this.version, + os: os ?? this.os, + ); + } + + String get versionAndPlatform => "$version ($os)"; + + @override + String toString() => 'ApplicationInfo(name: $name, version: $version, os: $os)'; +} diff --git a/lib/util/auth_service.dart b/lib/util/auth_service.dart new file mode 100644 index 0000000..1da0feb --- /dev/null +++ b/lib/util/auth_service.dart @@ -0,0 +1,36 @@ +// ignore_for_file: depend_on_referenced_packages + +import 'package:fladder/models/account_model.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:local_auth/local_auth.dart'; +import 'package:local_auth_android/local_auth_android.dart'; +import 'package:local_auth_darwin/local_auth_darwin.dart'; + +class AuthService { + static Future authenticateUser(BuildContext context, AccountModel user) async { + final LocalAuthentication localAuthentication = LocalAuthentication(); + bool isAuthenticated = false; + bool isBiometricSupported = await localAuthentication.isDeviceSupported(); + bool canCheckBiometrics = await localAuthentication.canCheckBiometrics; + if (isBiometricSupported && canCheckBiometrics) { + try { + isAuthenticated = await localAuthentication.authenticate( + localizedReason: + context.localized.scanYourFingerprintToAuthenticate("(${user.name} - ${user.credentials.serverName})"), + authMessages: [ + AndroidAuthMessages( + signInTitle: 'Fladder', + biometricHint: context.localized.scanBiometricHint, + ), + IOSAuthMessages( + cancelButton: context.localized.cancel, + ) + ], + ); + } on PlatformException catch (_) {} + } + return isAuthenticated; + } +} diff --git a/lib/util/box_fit_extension.dart b/lib/util/box_fit_extension.dart new file mode 100644 index 0000000..5ed01d9 --- /dev/null +++ b/lib/util/box_fit_extension.dart @@ -0,0 +1,16 @@ +import 'package:fladder/util/localization_helper.dart'; +import 'package:flutter/material.dart'; + +extension BoxFitExtension on BoxFit { + String label(BuildContext context) { + return switch (this) { + BoxFit.fill => context.localized.videoScalingFill, + BoxFit.contain => context.localized.videoScalingContain, + BoxFit.cover => context.localized.videoScalingCover, + BoxFit.fitWidth => context.localized.videoScalingFitWidth, + BoxFit.fitHeight => context.localized.videoScalingFitHeight, + BoxFit.none => context.localized.none, + BoxFit.scaleDown => context.localized.videoScalingScaleDown, + }; + } +} diff --git a/lib/util/custom_color_themes.dart b/lib/util/custom_color_themes.dart new file mode 100644 index 0000000..9672bd1 --- /dev/null +++ b/lib/util/custom_color_themes.dart @@ -0,0 +1,81 @@ +import 'package:flutter/material.dart'; + +enum ColorThemes { + fladder( + name: 'Fladder', + color: Colors.orange, + ), + deepOrange( + name: 'Deep Orange', + color: Colors.deepOrange, + ), + amber( + name: 'Amber', + color: Colors.amber, + ), + green( + name: 'Green', + color: Colors.green, + ), + lightGreen( + name: 'Light Green', + color: Colors.lightGreen, + ), + lime( + name: 'Lime', + color: Colors.lime, + ), + cyan( + name: 'Cyan', + color: Colors.cyan, + ), + blue( + name: 'Blue', + color: Colors.blue, + ), + lightBlue( + name: 'Light Blue', + color: Colors.lightBlue, + ), + indigo( + name: 'Indigo', + color: Colors.indigo, + ), + deepBlue( + name: 'Deep Blue', + color: Color.fromARGB(255, 1, 34, 94), + ), + brown( + name: 'Brown', + color: Colors.brown, + ), + purple( + name: 'Purple', + color: Colors.purple, + ), + deepPurple( + name: 'Deep Purple', + color: Colors.deepPurple, + ), + blueGrey( + name: 'Blue Grey', + color: Colors.blueGrey, + ), + ; + + const ColorThemes({ + required this.name, + required this.color, + }); + + final String name; + final Color color; + + ColorScheme get schemeLight { + return ColorScheme.fromSeed(seedColor: color, brightness: Brightness.light); + } + + ColorScheme get schemeDark { + return ColorScheme.fromSeed(seedColor: color, brightness: Brightness.dark); + } +} diff --git a/lib/util/debouncer.dart b/lib/util/debouncer.dart new file mode 100644 index 0000000..ed6a93e --- /dev/null +++ b/lib/util/debouncer.dart @@ -0,0 +1,14 @@ +import 'dart:async'; +import 'package:flutter/material.dart'; + +class Debouncer { + Debouncer(this.duration); + final Duration duration; + Timer? _timer; + void run(VoidCallback action) { + if (_timer?.isActive ?? false) { + _timer?.cancel(); + } + _timer = Timer(duration, action); + } +} diff --git a/lib/util/disable_keypad_focus.dart b/lib/util/disable_keypad_focus.dart new file mode 100644 index 0000000..384f21b --- /dev/null +++ b/lib/util/disable_keypad_focus.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; + +class DisableFocus extends StatelessWidget { + final Widget child; + final bool canRequestFocus; + final bool skipTraversal; + final bool descendantsAreFocusable; + final bool descendantsAreTraversable; + const DisableFocus({ + required this.child, + super.key, + this.canRequestFocus = false, + this.skipTraversal = true, + this.descendantsAreFocusable = false, + this.descendantsAreTraversable = false, + }); + + @override + Widget build(BuildContext context) { + return Focus( + canRequestFocus: canRequestFocus, + skipTraversal: skipTraversal, + descendantsAreFocusable: descendantsAreFocusable, + descendantsAreTraversable: descendantsAreTraversable, + child: child, + ); + } +} diff --git a/lib/util/duration_extensions.dart b/lib/util/duration_extensions.dart new file mode 100644 index 0000000..8d37eb2 --- /dev/null +++ b/lib/util/duration_extensions.dart @@ -0,0 +1,17 @@ +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart' as dto; + +extension DurationExtensions on Duration { + int get toRuntimeTicks => inMilliseconds * 10000; + + String get readAbleDuration { + String twoDigits(int n) => n.toString().padLeft(2, "0"); + return "${inHours != 0 ? '${twoDigits(inHours)}:' : ''}${twoDigits(inMinutes.remainder(60))}:${twoDigits(inSeconds.remainder(60))}"; + } +} + +extension BaseItemDtoExtension on dto.BaseItemDto { + Duration? get runTimeDuration { + if (runTimeTicks == null) return null; + return Duration(milliseconds: (runTimeTicks! ~/ 10000)); + } +} diff --git a/lib/util/fab_extended_anim.dart b/lib/util/fab_extended_anim.dart new file mode 100644 index 0000000..3481348 --- /dev/null +++ b/lib/util/fab_extended_anim.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class FloatingActionButtonAnimated extends ConsumerWidget { + final Widget label; + final Widget icon; + final String tooltip; + final bool alternate; + final bool isExtended; + final void Function()? onPressed; + const FloatingActionButtonAnimated({ + required this.label, + required this.icon, + required this.tooltip, + this.alternate = false, + this.isExtended = false, + required this.onPressed, + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return FloatingActionButton.extended( + key: key, + tooltip: tooltip, + onPressed: onPressed, + foregroundColor: alternate ? Theme.of(context).colorScheme.onSecondary : null, + backgroundColor: alternate ? Theme.of(context).colorScheme.secondary : null, + extendedPadding: EdgeInsets.all(14), + label: AnimatedSize( + duration: const Duration(milliseconds: 250), + child: isExtended + ? Row( + children: [ + icon, + const SizedBox(width: 6), + label, + ], + ) + : icon, + ), + ); + } +} diff --git a/lib/util/fladder_image.dart b/lib/util/fladder_image.dart new file mode 100644 index 0000000..55fc6a8 --- /dev/null +++ b/lib/util/fladder_image.dart @@ -0,0 +1,63 @@ +import 'package:fladder/models/items/images_models.dart'; +import 'package:fladder/providers/settings/client_settings_provider.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_blurhash/flutter_blurhash.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:transparent_image/transparent_image.dart'; + +class FladderImage extends ConsumerWidget { + final ImageData? image; + final Widget Function(BuildContext context, Widget child, int? frame, bool wasSynchronouslyLoaded)? frameBuilder; + final Widget? placeHolder; + final BoxFit fit; + final bool enableBlur; + final bool blurOnly; + const FladderImage({ + required this.image, + this.frameBuilder, + this.placeHolder, + this.fit = BoxFit.cover, + this.enableBlur = false, + this.blurOnly = false, + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final useBluredPlaceHolder = ref.watch(clientSettingsProvider.select((value) => value.blurPlaceHolders)); + final newImage = image; + final blurSize = AdaptiveLayout.of(context).isDesktop ? 32 : 16; + if (newImage == null) { + return placeHolder ?? Container(); + } else { + return Stack( + key: Key(newImage.key), + fit: StackFit.expand, + children: [ + if (useBluredPlaceHolder && !enableBlur && newImage.hash.isNotEmpty && !enableBlur) + Image( + fit: fit, + excludeFromSemantics: true, + filterQuality: FilterQuality.low, + image: BlurHashImage( + newImage.hash, + decodingWidth: blurSize, + decodingHeight: blurSize, + ), + ), + if (!blurOnly) + FadeInImage( + placeholder: Image.memory(kTransparentImage).image, + fit: fit, + placeholderFit: fit, + excludeFromSemantics: true, + filterQuality: FilterQuality.high, + placeholderFilterQuality: FilterQuality.low, + image: newImage.imageProvider, + ) + ], + ); + } + } +} diff --git a/lib/util/grouping.dart b/lib/util/grouping.dart new file mode 100644 index 0000000..6cc6d61 --- /dev/null +++ b/lib/util/grouping.dart @@ -0,0 +1,14 @@ +import 'package:fladder/models/item_base_model.dart'; + +Map> groupByName(List items) { + Map> groupedItems = {}; + for (int i = 0; i < items.length; i++) { + String firstLetter = items[i].name.replaceAll('The ', '')[0].toUpperCase(); + if (!groupedItems.containsKey(firstLetter)) { + groupedItems[firstLetter] = [items[i]]; + } else { + groupedItems[firstLetter]?.add(items[i]); + } + } + return groupedItems; +} diff --git a/lib/util/header_generate.dart b/lib/util/header_generate.dart new file mode 100644 index 0000000..aa5c44b --- /dev/null +++ b/lib/util/header_generate.dart @@ -0,0 +1,11 @@ +import 'package:fladder/util/application_info.dart'; +import 'package:xid/xid.dart'; + +Map generateHeader(ApplicationInfo application) { + var xid = Xid(); + return { + 'content-type': 'application/json', + 'x-emby-authorization': + 'MediaBrowser Client="${application.name}", Device="${application.os}", DeviceId="$xid", Version="${application.version}"', + }; +} diff --git a/lib/util/humanize_duration.dart b/lib/util/humanize_duration.dart new file mode 100644 index 0000000..dacecb6 --- /dev/null +++ b/lib/util/humanize_duration.dart @@ -0,0 +1,28 @@ +import 'package:collection/collection.dart'; + +extension DurationExtensions on Duration? { + String? get humanize { + if (this == null) return null; + final duration = this!; + final hours = duration.inHours != 0 ? '${duration.inHours.toString()}h' : null; + final minutes = duration.inMinutes % 60 != 0 ? '${duration.inMinutes % 60}m'.padLeft(3, '0') : null; + final seconds = duration.inHours == 0 ? '${duration.inSeconds % 60}s'.padLeft(3, '0') : null; + final result = [hours, minutes, seconds].whereNotNull().map((e) => e).join(' '); + return result.isNotEmpty ? result : null; + } + + String? get humanizeSmall { + if (this == null) return null; + final duration = this!; + final hours = (duration.inHours != 0 ? duration.inHours : null)?.toString(); + final minutes = (duration.inMinutes % 60).toString().padLeft(2, '0'); + final seconds = (duration.inHours == 0 ? duration.inSeconds % 60 : null)?.toString().padLeft(2, '0'); + + final result = [hours, minutes, seconds].whereNotNull().map((e) => e).join(':'); + return result.isNotEmpty ? result : null; + } + + String get simpleTime { + return toString().split('.').first.padLeft(8, "0"); + } +} diff --git a/lib/util/item_base_model/item_base_model_extensions.dart b/lib/util/item_base_model/item_base_model_extensions.dart new file mode 100644 index 0000000..fc9bb38 --- /dev/null +++ b/lib/util/item_base_model/item_base_model_extensions.dart @@ -0,0 +1,250 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/book_model.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/episode_model.dart'; +import 'package:fladder/models/items/item_shared_models.dart'; +import 'package:fladder/models/items/photos_model.dart'; +import 'package:fladder/providers/sync_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/screens/collections/add_to_collection.dart'; +import 'package:fladder/screens/metadata/edit_item.dart'; +import 'package:fladder/screens/metadata/identifty_screen.dart'; +import 'package:fladder/screens/metadata/info_screen.dart'; +import 'package:fladder/screens/playlists/add_to_playlists.dart'; +import 'package:fladder/screens/metadata/refresh_metadata.dart'; +import 'package:fladder/screens/shared/fladder_snackbar.dart'; +import 'package:fladder/screens/syncing/sync_button.dart'; +import 'package:fladder/screens/syncing/sync_item_details.dart'; +import 'package:fladder/util/item_base_model/play_item_helpers.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/refresh_state.dart'; +import 'package:fladder/widgets/pop_up/delete_file.dart'; +import 'package:fladder/widgets/shared/item_actions.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +extension ItemBaseModelsBooleans on List { + Map> get groupedItems { + Map> groupedItems = {}; + for (int i = 0; i < length; i++) { + FladderItemType type = this[i].type; + if (!groupedItems.containsKey(type)) { + groupedItems[type] = [this[i]]; + } else { + groupedItems[type]?.add(this[i]); + } + } + return groupedItems; + } +} + +enum ItemActions { + play, + openShow, + openParent, + details, + showAlbum, + playFromStart, + addCollection, + addPlaylist, + markPlayed, + markUnplayed, + setFavorite, + refreshMetaData, + editMetaData, + mediaInfo, + identify, + download, +} + +extension ItemBaseModelExtensions on ItemBaseModel { + List generateActions( + BuildContext context, + WidgetRef ref, { + List otherActions = const [], + Set exclude = const {}, + Function(UserData? newData)? onUserDataChanged, + Function(ItemBaseModel item)? onItemUpdated, + Function(ItemBaseModel item)? onDeleteSuccesFully, + }) { + final isAdmin = ref.read(userProvider)?.policy?.isAdministrator ?? false; + final downloadEnabled = ref.read(userProvider.select( + (value) => value?.canDownload ?? false, + )) && + syncAble && + (canDownload ?? false); + final syncedItem = ref.read(syncProvider.notifier).getSyncedItem(this); + return [ + if (!exclude.contains(ItemActions.play)) + if (playAble) + ItemActionButton( + action: () => play(context, ref), + icon: Icon(IconsaxOutline.play), + label: Text(playButtonLabel(context)), + ), + if (parentId?.isNotEmpty == true) ...[ + if (!exclude.contains(ItemActions.openShow) && this is EpisodeModel) + ItemActionButton( + icon: Icon(FladderItemType.series.icon), + action: () => parentBaseModel.navigateTo(context), + label: Text(context.localized.openShow), + ), + if (!exclude.contains(ItemActions.openParent) && this is! EpisodeModel && !galleryItem) + ItemActionButton( + icon: Icon(FladderItemType.folder.icon), + action: () => parentBaseModel.navigateTo(context), + label: Text(context.localized.openParent), + ), + ], + if (!galleryItem && !exclude.contains(ItemActions.details)) + ItemActionButton( + action: () async => await navigateTo(context), + icon: Icon(IconsaxOutline.main_component), + label: Text(context.localized.showDetails), + ) + else if (!exclude.contains(ItemActions.showAlbum) && galleryItem) + ItemActionButton( + icon: Icon(FladderItemType.photoalbum.icon), + action: () => (this as PhotoModel).navigateToAlbum(context), + label: Text(context.localized.showAlbum), + ), + if (!exclude.contains(ItemActions.playFromStart)) + if ((userData.progress) > 0) + ItemActionButton( + icon: Icon(IconsaxOutline.refresh), + action: (this is BookModel) + ? () => ((this as BookModel).play(context, ref, currentPage: 0)) + : () => play(context, ref, startPosition: Duration.zero), + label: Text((this is BookModel) + ? context.localized.readFromStart(name) + : context.localized.playFromStart(subTextShort(context) ?? name)), + ), + ItemActionDivider(), + if (!exclude.contains(ItemActions.addCollection)) + if (type != FladderItemType.boxset) + ItemActionButton( + icon: Icon(IconsaxOutline.archive_add), + action: () async { + await addItemToCollection(context, [this]); + if (context.mounted) { + context.refreshData(); + } + }, + label: Text(context.localized.addToCollection), + ), + if (!exclude.contains(ItemActions.addPlaylist)) + if (type != FladderItemType.playlist) + ItemActionButton( + icon: Icon(IconsaxOutline.archive_add), + action: () async { + await addItemToPlaylist(context, [this]); + if (context.mounted) { + context.refreshData(); + } + }, + label: Text(context.localized.addToPlaylist), + ), + if (!exclude.contains(ItemActions.markPlayed)) + ItemActionButton( + icon: Icon(IconsaxOutline.eye), + action: () async { + final userData = await ref.read(userProvider.notifier).markAsPlayed(true, id); + onUserDataChanged?.call(userData?.bodyOrThrow); + context.refreshData(); + }, + label: Text(context.localized.markAsWatched), + ), + if (!exclude.contains(ItemActions.markUnplayed)) + ItemActionButton( + icon: Icon(IconsaxOutline.eye_slash), + label: Text(context.localized.markAsUnwatched), + action: () async { + final userData = await ref.read(userProvider.notifier).markAsPlayed(false, id); + onUserDataChanged?.call(userData?.bodyOrThrow); + context.refreshData(); + }, + ), + if (!exclude.contains(ItemActions.setFavorite)) + ItemActionButton( + icon: Icon(userData.isFavourite ? IconsaxOutline.heart_remove : IconsaxOutline.heart_add), + action: () async { + final newData = await ref.read(userProvider.notifier).setAsFavorite(!userData.isFavourite, id); + onUserDataChanged?.call(newData?.bodyOrThrow); + context.refreshData(); + }, + label: Text(userData.isFavourite ? context.localized.removeAsFavorite : context.localized.addAsFavorite), + ), + ...otherActions, + ItemActionDivider(), + if (!exclude.contains(ItemActions.editMetaData) && isAdmin) + ItemActionButton( + icon: Icon(IconsaxOutline.edit), + action: () async { + final newItem = await showEditItemPopup(context, id); + if (newItem != null) { + onItemUpdated?.call(newItem); + } + }, + label: Text(context.localized.editMetadata), + ), + if (!exclude.contains(ItemActions.refreshMetaData) && isAdmin) + ItemActionButton( + icon: Icon(IconsaxOutline.global_refresh), + action: () async { + showRefreshPopup(context, id, detailedName(context) ?? name); + }, + label: Text(context.localized.refreshMetadata), + ), + if (!exclude.contains(ItemActions.download) && downloadEnabled) ...{ + if (syncedItem == null) + ItemActionButton( + icon: Icon(IconsaxOutline.arrow_down_2), + label: Text(context.localized.sync), + action: () => ref.read(syncProvider.notifier).addSyncItem(context, this), + ) + else + ItemActionButton( + icon: IgnorePointer(child: SyncButton(item: this, syncedItem: syncedItem)), + action: () => showSyncItemDetails(context, syncedItem, ref), + label: Text(context.localized.syncDetails), + ) + }, + if (canDelete == true) + ItemActionButton( + icon: Container( + child: Icon( + IconsaxOutline.trash, + ), + ), + action: () async { + final response = await showDeleteDialog(context, this, ref); + if (response?.isSuccessful == true) { + onDeleteSuccesFully?.call(this); + if (context.mounted) { + context.refreshData(); + } + } else { + fladderSnackbarResponse(context, response); + } + }, + label: Text(context.localized.delete), + ), + if (!exclude.contains(ItemActions.identify) && identifiable && isAdmin) + ItemActionButton( + icon: Icon(IconsaxOutline.search_normal), + action: () async { + showIdentifyScreen(context, this); + }, + label: Text(context.localized.identify), + ), + if (!exclude.contains(ItemActions.mediaInfo)) + ItemActionButton( + icon: Icon(IconsaxOutline.info_circle), + action: () async { + showInfoScreen(context, this); + }, + label: Text("${type.label(context)} ${context.localized.info}"), + ), + ]; + } +} diff --git a/lib/util/item_base_model/play_item_helpers.dart b/lib/util/item_base_model/play_item_helpers.dart new file mode 100644 index 0000000..b70f3c9 --- /dev/null +++ b/lib/util/item_base_model/play_item_helpers.dart @@ -0,0 +1,340 @@ +import 'package:collection/collection.dart'; +import 'package:fladder/models/book_model.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/photos_model.dart'; +import 'package:fladder/models/media_playback_model.dart'; +import 'package:fladder/models/playback/playback_model.dart'; +import 'package:fladder/models/syncing/sync_item.dart'; +import 'package:fladder/models/video_stream_model.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:fladder/providers/book_viewer_provider.dart'; +import 'package:fladder/providers/items/book_details_provider.dart'; +import 'package:fladder/providers/sync_provider.dart'; +import 'package:fladder/providers/video_player_provider.dart'; +import 'package:fladder/screens/book_viewer/book_viewer_screen.dart'; +import 'package:fladder/screens/photo_viewer/photo_viewer_screen.dart'; +import 'package:fladder/screens/shared/adaptive_dialog.dart'; +import 'package:fladder/screens/shared/fladder_snackbar.dart'; +import 'package:fladder/screens/video_player/video_player.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/list_extensions.dart'; +import 'package:fladder/util/refresh_state.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:window_manager/window_manager.dart'; + +Future _showLoadingIndicator(BuildContext context) async { + return showDialog( + barrierDismissible: kDebugMode, + useRootNavigator: true, + context: context, + builder: (context) => const LoadIndicator(), + ); +} + +class LoadIndicator extends StatelessWidget { + const LoadIndicator({super.key}); + + @override + Widget build(BuildContext context) { + return Dialog( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 32), + child: Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const CircularProgressIndicator(strokeCap: StrokeCap.round), + const SizedBox(width: 70), + Text( + "Loading", + style: Theme.of(context).textTheme.titleLarge, + ), + const SizedBox(width: 20), + ], + ), + ), + ); + } +} + +Future _playVideo( + BuildContext context, { + required PlaybackModel? current, + Duration? startPosition, + List? queue, + required WidgetRef ref, + VoidCallback? onPlayerExit, +}) async { + if (current == null) { + if (context.mounted) { + Navigator.of(context, rootNavigator: true).pop(); + fladderSnackbar(context, title: "No video found to play"); + } + return; + } + + final loadedCorrectly = await ref.read(videoPlayerProvider.notifier).loadPlaybackItem( + current, + startPosition: startPosition, + ); + + if (!loadedCorrectly) { + if (context.mounted) { + Navigator.of(context, rootNavigator: true).pop(); + fladderSnackbar(context, title: "An error occurred loading media"); + } + return; + } + + //Pop loading screen + Navigator.of(context, rootNavigator: true).pop(); + + ref.read(mediaPlaybackProvider.notifier).update((state) => state.copyWith(state: VideoPlayerState.fullScreen)); + + if (context.mounted) { + await Navigator.of(context, rootNavigator: true).push( + MaterialPageRoute( + builder: (context) => const VideoPlayer(), + ), + ); + if (AdaptiveLayout.of(context).isDesktop) { + final fullScreen = await windowManager.isFullScreen(); + if (fullScreen) { + await windowManager.setFullScreen(false); + } + } + if (context.mounted) { + context.refreshData(); + } + onPlayerExit?.call(); + } +} + +extension BookBaseModelExtension on BookModel? { + Future play( + BuildContext context, + WidgetRef ref, { + int? currentPage, + AutoDisposeStateNotifierProvider? provider, + BuildContext? parentContext, + }) async { + if (kIsWeb) { + fladderSnackbar(context, title: "Books are not supported on web for now."); + return; + } + if (this == null) { + fladderSnackbar(context, title: "Not a selected book"); + return; + } + var newProvider = provider; + + if (newProvider == null) { + newProvider = bookDetailsProvider(this?.id ?? ""); + await ref.watch(bookDetailsProvider(this?.id ?? "").notifier).fetchDetails(this!); + } + + ref.read(bookViewerProvider.notifier).fetchBook(this); + await openBookViewer( + context, + newProvider, + initialPage: currentPage ?? this?.currentPage, + ); + parentContext?.refreshData(); + if (context.mounted) { + context.refreshData(); + } + } +} + +extension PhotoAlbumExtension on PhotoAlbumModel? { + Future play( + BuildContext context, + WidgetRef ref, { + int? currentPage, + AutoDisposeStateNotifierProvider? provider, + BuildContext? parentContext, + }) async { + _showLoadingIndicator(context); + + final albumModel = this; + if (albumModel == null) return; + final api = ref.read(jellyApiProvider); + final getChildItems = await api.itemsGet( + parentId: albumModel.id, + includeItemTypes: FladderItemType.galleryItem.map((e) => e.dtoKind).toList(), + recursive: true); + final photos = getChildItems.body?.items.whereType() ?? []; + + Navigator.of(context, rootNavigator: true).pop(); + + if (photos.isEmpty) { + return; + } + + await Navigator.of(context, rootNavigator: true).push( + MaterialPageRoute( + builder: (context) => PhotoViewerScreen( + items: photos.toList(), + ), + ), + ); + if (context.mounted) { + context.refreshData(); + } + return; + } +} + +extension ItemBaseModelExtensions on ItemBaseModel? { + Future play( + BuildContext context, + WidgetRef ref, { + Duration? startPosition, + bool showPlaybackOption = false, + }) async => + switch (this) { + PhotoAlbumModel album => album.play(context, ref), + BookModel book => book.play(context, ref), + _ => _default(context, this, ref, startPosition: startPosition), + }; + + Future _default( + BuildContext context, + ItemBaseModel? itemModel, + WidgetRef ref, { + Duration? startPosition, + bool showPlaybackOption = false, + }) async { + if (itemModel == null) return; + + _showLoadingIndicator(context); + + SyncedItem? syncedItem = ref.read(syncProvider.notifier).getSyncedItem(this); + + final options = { + PlaybackType.directStream, + PlaybackType.transcode, + if (syncedItem != null && syncedItem.status == SyncStatus.complete) PlaybackType.offline, + }; + + PlaybackModel? model; + + if (showPlaybackOption) { + final playbackType = await _showPlaybackTypeSelection( + context: context, + options: options, + ); + + model = switch (playbackType) { + PlaybackType.directStream || PlaybackType.transcode => await ref + .read(playbackModelHelper) + .createServerPlaybackModel(itemModel, playbackType, startPosition: startPosition), + PlaybackType.offline => await ref.read(playbackModelHelper).createOfflinePlaybackModel(itemModel, syncedItem), + null => null + }; + } else { + model = (await ref.read(playbackModelHelper).createServerPlaybackModel(itemModel, PlaybackType.directStream)) ?? + await ref.read(playbackModelHelper).createOfflinePlaybackModel(itemModel, syncedItem); + } + + if (model == null) { + return; + } + + await _playVideo(context, startPosition: startPosition, current: model, ref: ref); + } +} + +extension ItemBaseModelsBooleans on List { + Future playLibraryItems(BuildContext context, WidgetRef ref, {bool shuffle = false}) async { + if (isEmpty) return; + + _showLoadingIndicator(context); + + // Replace all shows/seasons with all episodes + List> newList = await Future.wait(map((element) async { + switch (element.type) { + case FladderItemType.series: + return await ref.read(jellyApiProvider).fetchEpisodeFromShow(seriesId: element.id); + default: + return [element]; + } + })); + + var expandedList = + newList.expand((element) => element).toList().where((element) => element.playAble).toList().uniqueBy( + (value) => value.id, + ); + + if (shuffle) { + expandedList.shuffle(); + } + + PlaybackModel? model = await ref.read(playbackModelHelper).createServerPlaybackModel( + expandedList.firstOrNull, + PlaybackType.directStream, + libraryQueue: expandedList, + ); + + if (context.mounted) { + await _playVideo(context, ref: ref, queue: expandedList, current: model); + if (context.mounted) { + RefreshState.of(context).refresh(); + } + } + } +} + +Future _showPlaybackTypeSelection({ + required BuildContext context, + required Set options, +}) async { + PlaybackType? playbackType; + + await showDialogAdaptive( + context: context, + builder: (context) { + return PlaybackDialogue( + options: options, + onClose: (type) { + playbackType = type; + Navigator.of(context).pop(); + }, + ); + }, + ); + return playbackType; +} + +class PlaybackDialogue extends StatelessWidget { + final Set options; + final Function(PlaybackType type) onClose; + const PlaybackDialogue({required this.options, required this.onClose, super.key}); + + @override + Widget build(BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16).add(EdgeInsets.only(top: 16, bottom: 8)), + child: Text( + "Playback type", + style: Theme.of(context).textTheme.titleLarge, + ), + ), + const Divider(), + ...options.map((type) => ListTile( + title: Text(type.name), + leading: Icon(type.icon), + onTap: () { + onClose(type); + }, + )) + ], + ); + } +} diff --git a/lib/util/jelly_id.dart b/lib/util/jelly_id.dart new file mode 100644 index 0000000..11e1832 --- /dev/null +++ b/lib/util/jelly_id.dart @@ -0,0 +1,8 @@ +// ignore: depend_on_referenced_packages +import 'package:uuid/uuid.dart'; + +String get jellyId { + var uuid = Uuid(); + var guid = uuid.v4().replaceAll('-', ''); // Remove hyphens + return guid.substring(0, 32); // Take only the first 32 characters +} diff --git a/lib/util/jellyfin_extension.dart b/lib/util/jellyfin_extension.dart new file mode 100644 index 0000000..562cc08 --- /dev/null +++ b/lib/util/jellyfin_extension.dart @@ -0,0 +1,28 @@ +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:chopper/chopper.dart'; +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; + +extension JellyApiExtension on JellyfinOpenApi { + Future?> itemIdImagesImageTypePost( + ImageType type, + String itemId, + Uint8List data, + ) async { + final client = this.client; + final uri = Uri.parse('/Items/$itemId/Images/${type.value}'); + final response = await client.send( + Request( + 'POST', + uri, + this.client.baseUrl, + body: base64Encode(data), + headers: { + 'Content-Type': 'image/*', + }, + ), + ); + return response; + } +} diff --git a/lib/util/keyed_list_view.dart b/lib/util/keyed_list_view.dart new file mode 100644 index 0000000..3aacd22 --- /dev/null +++ b/lib/util/keyed_list_view.dart @@ -0,0 +1,96 @@ +import 'package:collection/collection.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; + +class KeyedListView extends ConsumerStatefulWidget { + final Map map; + final Widget Function(BuildContext context, int index) itemBuilder; + const KeyedListView({required this.map, required this.itemBuilder, super.key}); + + @override + ConsumerState createState() => _KeyedListViewState(); +} + +class _KeyedListViewState extends ConsumerState { + final ItemScrollController itemScrollController = ItemScrollController(); + final ScrollOffsetController scrollOffsetController = ScrollOffsetController(); + final ItemPositionsListener itemPositionsListener = ItemPositionsListener.create(); + final ScrollOffsetListener scrollOffsetListener = ScrollOffsetListener.create(); + int currentIndex = 0; + + @override + void initState() { + super.initState(); + itemPositionsListener.itemPositions.addListener(() { + if (currentIndex != itemPositionsListener.itemPositions.value.toList()[0].index) { + setState(() { + currentIndex = itemPositionsListener.itemPositions.value.toList()[0].index; + }); + } + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Row( + children: [ + Flexible( + child: ScrollablePositionedList.builder( + itemCount: widget.map.length, + itemBuilder: widget.itemBuilder, + itemScrollController: itemScrollController, + scrollOffsetController: scrollOffsetController, + itemPositionsListener: itemPositionsListener, + scrollOffsetListener: scrollOffsetListener, + ), + ), + const SizedBox(width: 8), + SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, + children: widget.map.keys.mapIndexed( + (index, e) { + final atPosition = currentIndex == index; + return Container( + decoration: BoxDecoration( + color: atPosition ? Theme.of(context).colorScheme.secondary : Colors.transparent, + borderRadius: BorderRadius.circular(5), + ), + height: 28, + width: 28, + child: TextButton( + style: TextButton.styleFrom( + padding: EdgeInsets.zero, + textStyle: Theme.of(context).textTheme.titleSmall?.copyWith(fontWeight: FontWeight.bold), + foregroundColor: atPosition + ? Theme.of(context).colorScheme.onSecondary + : Theme.of(context).colorScheme.onSurface.withOpacity(0.35), + ), + onPressed: () { + itemScrollController.scrollTo( + index: index, + duration: const Duration(seconds: 1), + opacityAnimationWeights: [20, 20, 60], + curve: Curves.easeOutCubic, + ); + }, + child: Text( + e, + ), + ), + ); + }, + ).toList(), + ), + ), + ], + ); + } +} diff --git a/lib/util/list_extensions.dart b/lib/util/list_extensions.dart new file mode 100644 index 0000000..fd176bb --- /dev/null +++ b/lib/util/list_extensions.dart @@ -0,0 +1,92 @@ +import 'package:collection/collection.dart'; + +extension ListExtensions on List { + List replace(T entry) { + var tempList = toList(); + final index = indexOf(entry); + tempList.removeAt(index); + tempList.insert(index, entry); + return tempList; + } + + List toggle(T entry) { + var tempList = toList(); + if (contains(entry)) { + return tempList..remove(entry); + } else { + return tempList..add(entry); + } + } + + bool containsAny(Iterable entries) { + for (var value in entries) { + if (contains(value)) { + return true; + } + } + return false; + } + + List toggleUnique(T entry) => toggle(entry).toSet().toList(); + + List random() { + List tempList = this; + tempList.shuffle(); + return tempList; + } + + List uniqueBy(dynamic Function(T value) keySelector) { + final Map uniqueMap = {}; + + for (var item in this) { + final key = keySelector(item); + if (!uniqueMap.containsKey(key)) { + uniqueMap[key] = item; + } + } + + return uniqueMap.values.toList(); + } + + Iterable> chunk(int size) sync* { + if (size <= 0) { + throw ArgumentError('Chunk size must be greater than zero.'); + } + + final iterator = this.iterator; + while (iterator.moveNext()) { + final chunk = []; + for (var i = 0; i < size; i++) { + if (!iterator.moveNext()) { + break; + } + chunk.add(iterator.current); + } + yield chunk; + } + } + + T? nextOrNull(T item) { + int indexOf = this.indexOf(item); + if (indexOf + 1 >= length) return null; + return elementAtOrNull(indexOf + 1); + } + + T? previousOrNull(T item) { + int indexOf = this.indexOf(item); + if (indexOf - 1 < 0) return null; + return elementAtOrNull(indexOf - 1); + } + + T? nextWhereOrNull(bool Function(T element) test) { + final indexOf = indexWhere((element) => test(element)); + if (indexOf + 1 < length) return null; + return elementAtOrNull(indexOf + 1); + } + + T? previousWhereOrNull(bool Function(T element) test) { + final indexOf = indexWhere((element) => test(element)); + if (indexOf - 1 < length) return null; + return elementAtOrNull(indexOf - 1); + } +} diff --git a/lib/util/list_padding.dart b/lib/util/list_padding.dart new file mode 100644 index 0000000..354de08 --- /dev/null +++ b/lib/util/list_padding.dart @@ -0,0 +1,42 @@ +import 'package:collection/collection.dart'; +import 'package:flutter/material.dart'; + +extension ListExtensions on List { + addInBetween(Widget widget) { + return mapIndexed( + (index, element) { + if (element != last) { + return [element, widget]; + } else { + return [element]; + } + }, + ).expand((element) => element).toList(); + } + + addPadding(EdgeInsets padding) { + return map((e) { + if (e is Expanded || e is Spacer || e is Flexible) return e; + return Padding( + padding: padding.copyWith( + top: e == first ? 0 : null, + left: e == first ? 0 : null, + right: e == last ? 0 : null, + bottom: e == last ? 0 : null, + ), + child: e, + ); + }).toList(); + } + + addSize({double? width, double? height}) { + return map((e) { + if (e is Expanded || e is Spacer || e is Flexible) return e; + return SizedBox( + width: width, + height: height, + child: e, + ); + }).toList(); + } +} diff --git a/lib/util/local_extension.dart b/lib/util/local_extension.dart new file mode 100644 index 0000000..12f255d --- /dev/null +++ b/lib/util/local_extension.dart @@ -0,0 +1,14 @@ +import 'package:flutter/material.dart'; + +extension LocalExtensions on Locale { + String label() { + return switch (languageCode) { + "nl" => "Nederlands", + "zh" => "简体中文", + "es" => "Español", + "fr" => "Français", + "ja" => "日本語 (にほんご)", + "en" || _ => "English", + }; + } +} diff --git a/lib/util/localization_helper.dart b/lib/util/localization_helper.dart new file mode 100644 index 0000000..6448f52 --- /dev/null +++ b/lib/util/localization_helper.dart @@ -0,0 +1,6 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +extension BuildContextExtension on BuildContext { + AppLocalizations get localized => AppLocalizations.of(this); +} diff --git a/lib/util/map_bool_helper.dart b/lib/util/map_bool_helper.dart new file mode 100644 index 0000000..b5f0dea --- /dev/null +++ b/lib/util/map_bool_helper.dart @@ -0,0 +1,62 @@ +extension MapExtensions on Map { + Map toggleKey(T wantedKey) { + return map((key, value) => MapEntry(key, wantedKey == key ? !value : value)); + } + + Map setKey(T? wantedKey, bool enable) { + return map((key, value) => MapEntry(key, wantedKey == key ? enable : value)); + } + + Map setKeys(Iterable wantedKey, bool enable) { + var tempMap = map((key, value) => MapEntry(key, value)); + for (var element in wantedKey) { + tempMap = tempMap.setKey(element, enable); + } + return tempMap; + } + + Map setAll(bool toggle) { + return map((key, value) => MapEntry(key, toggle)); + } + + List get included { + return entries.where((entry) => entry.value).map((entry) => entry.key).toList(); + } + + List get notIncluded { + return entries.where((entry) => !entry.value).map((entry) => entry.key).toList(); + } + + Map get enabledFirst { + final enabled = Map.from(this)..removeWhere((key, value) => !value); + final disabled = Map.from(this)..removeWhere((key, value) => value); + + return enabled..addAll(disabled); + } + + bool get hasEnabled => values.any((element) => element == true); + + Map replaceMap(Map oldMap) { + Map result = {}; + + forEach((key, value) { + result[key] = oldMap[key] ?? false; + }); + + return result; + } +} + +extension MapExtensionsGeneric on Map { + Map setKey(K? wantedKey, V newValue) { + return map((key, value) => MapEntry(key, key == wantedKey ? newValue : value)); + } + + Map setKeys(Iterable wantedKey, V value) { + var tempMap = map((key, value) => MapEntry(key, value)); + for (var element in wantedKey) { + tempMap = tempMap.setKey(element, value); + } + return tempMap; + } +} diff --git a/lib/util/mouse_parking.dart b/lib/util/mouse_parking.dart new file mode 100644 index 0000000..e6df68d --- /dev/null +++ b/lib/util/mouse_parking.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class MouseParking extends ConsumerStatefulWidget { + final Function(PointerEvent)? onHover; + const MouseParking({this.onHover, super.key}); + + @override + ConsumerState createState() => _MouseParkingState(); +} + +class _MouseParkingState extends ConsumerState { + bool parked = false; + @override + Widget build(BuildContext context) { + return SizedBox( + width: 100, + height: 100, + child: MouseRegion( + onEnter: (event) => setState(() => parked = true), + onExit: (event) => setState(() => parked = false), + onHover: widget.onHover, + cursor: SystemMouseCursors.none, + child: Container( + decoration: BoxDecoration( + borderRadius: const BorderRadius.only(topLeft: Radius.circular(20)), + color: parked ? Theme.of(context).colorScheme.primary.withOpacity(0.5) : Colors.black12, + ), + child: const Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.mouse_rounded), + Icon(Icons.local_parking), + ], + ), + ), + ), + ); + } +} diff --git a/lib/util/num_extension.dart b/lib/util/num_extension.dart new file mode 100644 index 0000000..be37ef2 --- /dev/null +++ b/lib/util/num_extension.dart @@ -0,0 +1,14 @@ +import 'dart:math'; + +extension RangeNum on num { + bool isInRange(num index, num range) { + return index - range < this && this < index + range; + } +} + +extension DoubleExtension on double { + double roundTo(int places) { + num mod = pow(10.0, places); + return ((this * mod).round().toDouble() / mod); + } +} diff --git a/lib/util/option_dialogue.dart b/lib/util/option_dialogue.dart new file mode 100644 index 0000000..16e7340 --- /dev/null +++ b/lib/util/option_dialogue.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; + +Future openOptionDialogue( + BuildContext context, { + required String label, + required List items, + bool isNullable = false, + required Widget Function(T? type) itemBuilder, +}) { + return showDialog( + context: context, + builder: (context) { + return AlertDialog.adaptive( + title: Text(label), + content: SizedBox( + width: MediaQuery.of(context).size.width * 0.65, + child: ListView( + physics: const AlwaysScrollableScrollPhysics(), + shrinkWrap: true, + children: [ + if (isNullable) itemBuilder(null), + ...items.map( + (e) => itemBuilder(e), + ) + ], + ), + ), + ); + }, + ); +} diff --git a/lib/util/player_extensions.dart b/lib/util/player_extensions.dart new file mode 100644 index 0000000..5130796 --- /dev/null +++ b/lib/util/player_extensions.dart @@ -0,0 +1,16 @@ +import 'package:collection/collection.dart'; +import 'package:fladder/models/items/media_streams_model.dart'; +import 'package:media_kit/media_kit.dart'; +import 'dart:io' show Platform; + +extension PlayerExtensions on Player { + Future addSubtitles(List subtitles) async { + final separator = Platform.isWindows ? ";" : ":"; + await (platform as NativePlayer).setProperty( + "sub-files", + subtitles + .mapIndexed((index, e) => "${Platform.isWindows ? e.url : e.url?.replaceFirst(":", "\\:")}@${e.displayTitle}") + .join(separator), + ); + } +} diff --git a/lib/util/player_extensions_web.dart b/lib/util/player_extensions_web.dart new file mode 100644 index 0000000..ff0e63f --- /dev/null +++ b/lib/util/player_extensions_web.dart @@ -0,0 +1,6 @@ +import 'package:fladder/models/items/media_streams_model.dart'; +import 'package:media_kit/media_kit.dart'; + +extension PlayerExtensions on Player { + Future addSubtitles(List subtitles) async {} +} diff --git a/lib/util/poster_defaults.dart b/lib/util/poster_defaults.dart new file mode 100644 index 0000000..c9dacfc --- /dev/null +++ b/lib/util/poster_defaults.dart @@ -0,0 +1,8 @@ +class PosterDefaults { + final double size; + final double ratio; + + double get gridRatio => size * ratio; + + const PosterDefaults({required this.size, required this.ratio}); +} diff --git a/lib/util/refresh_state.dart b/lib/util/refresh_state.dart new file mode 100644 index 0000000..97413bc --- /dev/null +++ b/lib/util/refresh_state.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; + +class RefreshState extends InheritedWidget { + final GlobalKey refreshKey; + final bool refreshAble; + + const RefreshState({ + super.key, + required this.refreshKey, + this.refreshAble = true, + required super.child, + }); + + Future refresh() async { + if (refreshAble) return await refreshKey.currentState?.show(); + return; + } + + static RefreshState? maybeOf(BuildContext context) { + return context.dependOnInheritedWidgetOfExactType(); + } + + static RefreshState of(BuildContext context) { + final RefreshState? result = maybeOf(context); + return result!; + } + + @override + bool updateShouldNotify(RefreshState oldWidget) { + return refreshKey != oldWidget.refreshKey; + } +} + +extension RefreshContextExtension on BuildContext { + Future refreshData() async { + //Small delay to fix server not updating response based on successful query + await Future.delayed(const Duration(milliseconds: 250)); + await RefreshState.maybeOf(this)?.refresh(); + } +} diff --git a/lib/util/simple_duration_picker.dart b/lib/util/simple_duration_picker.dart new file mode 100644 index 0000000..8564ff7 --- /dev/null +++ b/lib/util/simple_duration_picker.dart @@ -0,0 +1,174 @@ +import 'dart:developer'; + +import 'package:fladder/screens/shared/outlined_text_field.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +String timePickerString(BuildContext context, Duration? duration) { + if (duration == null) return context.localized.never; + if (duration.inSeconds <= 0) return context.localized.immediately; + + final minutes = duration.inMinutes; + final seconds = duration.inSeconds % 60; + + final minutesString = "$minutes ${context.localized.minutes(minutes)}"; + final secondsString = "$seconds ${context.localized.seconds(seconds)}"; + + if (minutes > 0 && seconds > 0) { + return context.localized.timeAndAnnotation(minutesString, secondsString); + } else if (minutes > 0) { + return minutesString; + } else { + return secondsString; + } +} + +Future showSimpleDurationPicker({ + required BuildContext context, + required Duration initialValue, + bool showNever = true, +}) async { + Duration? duration; + await showDialog( + context: context, + builder: (context) => AlertDialog.adaptive( + title: Text(context.localized.selectTime), + content: SimpleDurationPicker( + initialValue: initialValue, + onChanged: (value) { + duration = value; + Navigator.of(context).pop(); + }, + showNever: showNever, + ), + ), + ); + return duration; +} + +class SimpleDurationPicker extends ConsumerWidget { + final Duration initialValue; + final ValueChanged onChanged; + final bool showNever; + const SimpleDurationPicker({required this.initialValue, required this.onChanged, required this.showNever, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final minuteTextController = TextEditingController(text: initialValue.inMinutes.toString().padLeft(2, '0')); + final secondsTextController = TextEditingController(text: (initialValue.inSeconds % 60).toString().padLeft(2, '0')); + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 32), + child: Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Flexible( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + OutlinedTextField( + controller: minuteTextController, + style: Theme.of(context).textTheme.displaySmall, + keyboardType: const TextInputType.numberWithOptions(decimal: false, signed: false), + inputFormatters: [FilteringTextInputFormatter.digitsOnly], + borderWidth: 0, + textInputAction: TextInputAction.done, + textAlign: TextAlign.center, + ), + const SizedBox(height: 6), + Text( + context.localized.minutes(0), + style: Theme.of(context).textTheme.labelLarge, + ) + ], + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + ':', + style: Theme.of(context).textTheme.displayLarge, + ), + ), + Flexible( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + OutlinedTextField( + controller: secondsTextController, + style: Theme.of(context).textTheme.displaySmall, + keyboardType: const TextInputType.numberWithOptions(decimal: false, signed: false), + inputFormatters: [FilteringTextInputFormatter.digitsOnly], + borderWidth: 0, + textInputAction: TextInputAction.done, + onSubmitted: (value) { + try { + final parsedValue = int.parse(value); + if (parsedValue >= 60) { + secondsTextController.text = (parsedValue % 60).toString().padLeft(2, '0'); + minuteTextController.text = (int.parse(minuteTextController.text) + parsedValue / 60) + .floor() + .toString() + .padLeft(2, '0'); + } + onChanged( + Duration( + minutes: int.tryParse(minuteTextController.text) ?? 0, + seconds: int.tryParse(secondsTextController.text) ?? 0, + ), + ); + } catch (e) { + log(e.toString()); + } + }, + textAlign: TextAlign.center, + ), + const SizedBox(height: 6), + Text( + context.localized.seconds(0), + style: Theme.of(context).textTheme.labelLarge, + ) + ], + ), + ), + ], + ), + ), + Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + if (showNever) ...{ + TextButton( + onPressed: () => onChanged(null), + child: Text(context.localized.never), + ), + const Spacer(), + }, + TextButton( + onPressed: () => onChanged(initialValue), + child: Text(context.localized.cancel), + ), + if (!showNever) const Spacer() else const SizedBox(width: 6), + FilledButton( + onPressed: () => onChanged( + Duration( + minutes: int.tryParse(minuteTextController.text) ?? 0, + seconds: int.tryParse(secondsTextController.text) ?? 0, + ), + ), + child: Text(context.localized.set), + ), + ], + ) + ], + ); + } +} diff --git a/lib/util/size_formatting.dart b/lib/util/size_formatting.dart new file mode 100644 index 0000000..e7f3816 --- /dev/null +++ b/lib/util/size_formatting.dart @@ -0,0 +1,22 @@ +// ignore_for_file: constant_identifier_names + +extension IntExtension on int? { + String? get byteFormat { + final bytes = this; + if (bytes == null) return null; + if (bytes == 0) return "- bytes"; + const int KB = 1024; + const int MB = KB * KB; + const int GB = MB * KB; + + if (bytes >= GB) { + return '${(bytes / GB).toStringAsFixed(2)} GB'; + } else if (bytes >= MB) { + return '${(bytes / MB).toStringAsFixed(2)} MB'; + } else if (bytes >= KB) { + return '${(bytes / KB).toStringAsFixed(2)} KB'; + } else { + return '$bytes Bytes'; + } + } +} diff --git a/lib/util/sliver_list_padding.dart b/lib/util/sliver_list_padding.dart new file mode 100644 index 0000000..a53ad6e --- /dev/null +++ b/lib/util/sliver_list_padding.dart @@ -0,0 +1,25 @@ +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +class DefautlSliverBottomPadding extends StatelessWidget { + const DefautlSliverBottomPadding({super.key}); + + @override + Widget build(BuildContext context) { + return (AdaptiveLayout.of(context).isDesktop || kIsWeb) + ? const SliverToBoxAdapter() + : SliverPadding(padding: EdgeInsets.only(bottom: 85 + MediaQuery.of(context).padding.bottom)); + } +} + +class DefaultSliverTopBadding extends StatelessWidget { + const DefaultSliverTopBadding({super.key}); + + @override + Widget build(BuildContext context) { + return (AdaptiveLayout.of(context).isDesktop || kIsWeb) + ? const SliverPadding(padding: EdgeInsets.only(top: 35)) + : SliverPadding(padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top)); + } +} diff --git a/lib/util/sticky_header_text.dart b/lib/util/sticky_header_text.dart new file mode 100644 index 0000000..d70d929 --- /dev/null +++ b/lib/util/sticky_header_text.dart @@ -0,0 +1,49 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/screens/shared/flat_button.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class StickyHeaderText extends ConsumerStatefulWidget { + final String label; + final Function()? onClick; + + const StickyHeaderText({required this.label, this.onClick, super.key}); + + @override + ConsumerState createState() => StickyHeaderTextState(); +} + +class StickyHeaderTextState extends ConsumerState { + late Color color = Theme.of(context).colorScheme.onSurface; + + @override + Widget build(BuildContext context) { + return FlatButton( + onTap: widget.onClick, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 2), + child: Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text( + widget.label, + style: Theme.of(context).textTheme.titleLarge?.copyWith( + fontWeight: FontWeight.bold, + ), + ), + if (widget.onClick != null) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8).copyWith(bottom: 4), + child: Icon( + IconsaxOutline.arrow_right_3, + size: 18, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ) + ], + ), + ), + ); + } +} diff --git a/lib/util/stream_value.dart b/lib/util/stream_value.dart new file mode 100644 index 0000000..5fd0c04 --- /dev/null +++ b/lib/util/stream_value.dart @@ -0,0 +1,38 @@ +import 'dart:async'; + +class StreamValue { + final T _initialValue; + T _latestValue; + final StreamController _controller; + bool _hasInitialValue = true; + + StreamValue(T initialValue) + : _initialValue = initialValue, + _latestValue = initialValue, + _controller = StreamController.broadcast(); + + Stream get stream => _controller.stream; + + void add(T value) { + _latestValue = value; + _hasInitialValue = false; + _controller.add(value); + } + + void addError(Object error, [StackTrace? stackTrace]) { + _controller.addError(error, stackTrace); + } + + void listen(void Function(T) onData, {Function? onError, void Function()? onDone, bool? cancelOnError}) { + if (_hasInitialValue) { + onData(_initialValue); + } else { + onData(_latestValue); + } + _controller.stream.listen(onData, onError: onError, onDone: onDone, cancelOnError: cancelOnError); + } + + void close() { + _controller.close(); + } +} diff --git a/lib/util/string_extensions.dart b/lib/util/string_extensions.dart new file mode 100644 index 0000000..00863aa --- /dev/null +++ b/lib/util/string_extensions.dart @@ -0,0 +1,68 @@ +import 'package:collection/collection.dart'; + +import 'package:fladder/models/items/item_shared_models.dart'; + +extension StringExtensions on String { + String capitalize() { + if (isEmpty) return ''; + return "${this[0].toUpperCase()}${substring(1).toLowerCase()}"; + } + + String rtrim([String? chars]) { + var pattern = chars != null ? RegExp('[$chars]+\$') : RegExp(r'\s+$'); + return replaceAll(pattern, ''); + } + + String maxLength({int limitTo = 75}) { + if (length > limitTo) { + return "${substring(0, limitTo.clamp(0, length))}..."; + } else { + return substring(0, limitTo.clamp(0, length)); + } + } + + String getInitials({int limitTo = 2}) { + if (isEmpty) return ""; + var buffer = StringBuffer(); + var split = this.split(' '); + for (var i = 0; i < (limitTo.clamp(0, split.length)); i++) { + buffer.write(split[i][0]); + } + + return buffer.toString(); + } + + String toUpperCaseSplit() { + String result = ''; + + for (int i = 0; i < length; i++) { + if (i == 0) { + result += this[i].toUpperCase(); + } else if ((i > 0 && this[i].toUpperCase() == this[i])) { + result += ' ${this[i].toUpperCase()}'; + } else { + result += this[i]; + } + } + + return result; + } +} + +extension ListExtensions on List { + String flatString({int count = 3}) { + return take(3).map((e) => e.capitalize()).join(" | "); + } +} + +extension GenreExtensions on List { + String flatString({int count = 3}) { + return take(3).map((e) => e.name.capitalize()).join(" | "); + } +} + +extension StringListExtension on List { + String get detailsTitle { + return whereNotNull().join(" ● "); + } +} diff --git a/lib/util/theme_extensions.dart b/lib/util/theme_extensions.dart new file mode 100644 index 0000000..611a18c --- /dev/null +++ b/lib/util/theme_extensions.dart @@ -0,0 +1,6 @@ +import 'package:flutter/material.dart'; + +extension ThemeExtensions on BuildContext { + ColorScheme get colors => Theme.of(this).colorScheme; + TextTheme get textTheme => Theme.of(this).textTheme; +} diff --git a/lib/util/theme_mode_extension.dart b/lib/util/theme_mode_extension.dart new file mode 100644 index 0000000..1993856 --- /dev/null +++ b/lib/util/theme_mode_extension.dart @@ -0,0 +1,12 @@ +import 'package:fladder/util/localization_helper.dart'; +import 'package:flutter/material.dart'; + +extension ThemeModeExtension on ThemeMode { + String label(BuildContext context) { + return switch (this) { + ThemeMode.light => context.localized.themeModeLight, + ThemeMode.dark => context.localized.themeModeDark, + ThemeMode.system => context.localized.themeModeSystem, + }; + } +} diff --git a/lib/util/themes_data.dart b/lib/util/themes_data.dart new file mode 100644 index 0000000..54c83df --- /dev/null +++ b/lib/util/themes_data.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; + +class ThemesData extends InheritedWidget { + const ThemesData({ + super.key, + required this.light, + required this.dark, + required super.child, + }); + + final ThemeData light; + final ThemeData dark; + + static ThemesData? maybeOf(BuildContext context) { + return context.dependOnInheritedWidgetOfExactType(); + } + + static ThemesData of(BuildContext context) { + final ThemesData? result = maybeOf(context); + return result!; + } + + @override + bool updateShouldNotify(ThemesData oldWidget) => light != oldWidget.light || dark != oldWidget.dark; +} diff --git a/lib/util/throttler.dart b/lib/util/throttler.dart new file mode 100644 index 0000000..de83fbf --- /dev/null +++ b/lib/util/throttler.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; + +class Throttler { + final Duration duration; + int? lastActionTime; + + Throttler({required this.duration}); + + void run(VoidCallback action) { + if (lastActionTime == null) { + lastActionTime = DateTime.now().millisecondsSinceEpoch; + action(); + } else { + if (DateTime.now().millisecondsSinceEpoch - lastActionTime! > (duration.inMilliseconds)) { + lastActionTime = DateTime.now().millisecondsSinceEpoch; + action(); + } + } + } +} diff --git a/lib/util/track_extensions.dart b/lib/util/track_extensions.dart new file mode 100644 index 0000000..822e06f --- /dev/null +++ b/lib/util/track_extensions.dart @@ -0,0 +1,45 @@ +import 'package:media_kit/media_kit.dart'; +import 'package:validators/validators.dart'; +import 'string_extensions.dart'; + +extension SubtitleExtension on SubtitleTrack { + String get cleanName { + final names = { + id, + title, + }; + return names + .where((element) => element != null) + .map((e) { + if (e == null) return e; + if (isNumeric(e)) return ''; + if (e == "no") { + return "Off"; + } + return e.capitalize(); + }) + .where((element) => element != null && element.isNotEmpty) + .join(" - "); + } +} + +extension AudioTrackExtension on AudioTrack { + String get cleanName { + final names = { + id, + title, + }; + return names + .where((element) => element != null) + .map((e) { + if (e == null) return e; + if (isNumeric(e)) return ''; + if (e == "no") { + return "Off"; + } + return e.capitalize(); + }) + .where((element) => element != null && element.isNotEmpty) + .join(" - "); + } +} diff --git a/lib/util/video_properties.dart b/lib/util/video_properties.dart new file mode 100644 index 0000000..fdd1651 --- /dev/null +++ b/lib/util/video_properties.dart @@ -0,0 +1,119 @@ +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart' as dto; +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; +import 'package:fladder/models/items/media_streams_model.dart'; +import 'package:fladder/screens/shared/flat_button.dart'; +import 'package:flutter/material.dart'; +import 'package:collection/collection.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +enum Resolution { + sd("SD"), + hd("HD"), + udh("4K"); + + const Resolution(this.value); + final String value; + + Widget icon( + BuildContext context, + Function()? onTap, + ) { + return DefaultVideoInformationBox( + onTap: onTap, + child: Text( + value, + ), + ); + } + + static Resolution? fromVideoStream(VideoStreamModel? model) { + if (model == null) return null; + return Resolution.fromSize(model.width, model.height); + } + + static Resolution? fromSize(int? width, int? height) { + if (width == null || height == null) return null; + if (height <= 1080 && width <= 1920) { + return Resolution.hd; + } else if (height <= 2160 && width <= 3840) { + return Resolution.udh; + } else { + return Resolution.sd; + } + } +} + +enum DisplayProfile { + sdr("SDR"), + hdr("HDR"), + hdr10("HDR10"), + dolbyVision("Dolby Vision"), + dolbyVisionHdr10("DoVi/HDR10"), + hlg("HLG"); + + const DisplayProfile(this.value); + final String value; + + Widget icon( + BuildContext context, + Function()? onTap, + ) { + return DefaultVideoInformationBox( + onTap: onTap, + child: Text( + value, + ), + ); + } + + static DisplayProfile? fromStreams(List? mediaStreams) { + final videoStream = (mediaStreams?.firstWhereOrNull((element) => element.type == dto.MediaStreamType.video) ?? + mediaStreams?.firstOrNull); + if (videoStream == null) return null; + return DisplayProfile.fromVideoStream(VideoStreamModel.fromMediaStream(videoStream)); + } + + static DisplayProfile? fromVideoStreams(List? mediaStreams) { + final videoStream = mediaStreams?.firstWhereOrNull((element) => element.isDefault) ?? mediaStreams?.firstOrNull; + if (videoStream == null) return null; + return DisplayProfile.fromVideoStream(videoStream); + } + + static DisplayProfile fromVideoStream(VideoStreamModel stream) { + switch (stream.videoRangeType) { + case null: + case dto.VideoRangeType.hlg: + return DisplayProfile.hlg; + case dto.VideoRangeType.hdr10: + return DisplayProfile.hdr10; + default: + return DisplayProfile.sdr; + } + } +} + +class DefaultVideoInformationBox extends ConsumerWidget { + final Widget child; + final Function()? onTap; + const DefaultVideoInformationBox({required this.child, this.onTap, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Card( + child: FlatButton( + onTap: onTap, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), + child: Material( + type: MaterialType.button, + textStyle: Theme.of(context).textTheme.bodyLarge?.copyWith( + fontWeight: FontWeight.bold, + ), + color: Colors.transparent, + child: Center(child: child), + ), + ), + ), + ); + } +} diff --git a/lib/util/widget_extensions.dart b/lib/util/widget_extensions.dart new file mode 100644 index 0000000..d97c23e --- /dev/null +++ b/lib/util/widget_extensions.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; + +extension WidgetExtensions on Widget { + Widget padding(EdgeInsets insets) { + return Padding( + padding: insets, + child: this, + ); + } + + Widget setKey(Key? key) { + return Center( + key: key, + child: this, + ); + } + + Widget addHeroTag(String? tag) { + if (tag != null) { + return Hero(tag: tag, child: this); + } else { + return this; + } + } + + Widget addVisiblity(bool visible) { + return AnimatedOpacity(duration: const Duration(milliseconds: 250), opacity: visible ? 1 : 0, child: this); + } +} diff --git a/lib/widgets/gapped_container_shape.dart b/lib/widgets/gapped_container_shape.dart new file mode 100644 index 0000000..9f4705f --- /dev/null +++ b/lib/widgets/gapped_container_shape.dart @@ -0,0 +1,108 @@ +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class GappedContainerShape extends StatelessWidget { + final Color? activeColor; + final Color? inActiveColor; + final double? trackGapWidth; + final double thumbPosition; + + const GappedContainerShape({ + this.activeColor, + this.inActiveColor, + this.trackGapWidth, + required this.thumbPosition, + super.key, + }); + + @override + Widget build(BuildContext context) { + return CustomPaint( + painter: _GappedContainerPainter( + activeColor: + activeColor ?? Theme.of(context).sliderTheme.activeTrackColor ?? Theme.of(context).colorScheme.primary, + inActiveColor: inActiveColor ?? + Theme.of(context).sliderTheme.inactiveTrackColor ?? + Theme.of(context).colorScheme.secondaryContainer, + trackGapWidth: trackGapWidth ?? 18, + thumbCenterDxFraction: thumbPosition, + ), + child: Container(), + ); + } +} + +class _GappedContainerPainter extends CustomPainter { + final Color activeColor; + final Color inActiveColor; + final double trackGapWidth; + final double thumbCenterDxFraction; + + _GappedContainerPainter({ + required this.activeColor, + required this.inActiveColor, + required this.trackGapWidth, + required this.thumbCenterDxFraction, + }); + + @override + void paint(Canvas canvas, Size size) { + final Paint paint = Paint() + ..color = activeColor // Change this to the desired color + ..style = PaintingStyle.fill; + final Paint inActive = Paint() + ..color = inActiveColor // Change this to the desired color + ..style = PaintingStyle.fill; + + final Rect trackRect = Offset.zero & size; + + // Ensure thumbCenterDxFraction is not NaN or Infinity + final double thumbCenterDx = + thumbCenterDxFraction.isFinite ? thumbCenterDxFraction * size.width : 0.0; // Default to 0 if invalid fraction + + final Radius trackCornerRadius = Radius.circular(trackRect.shortestSide / 2); + final Radius trackInsideCornerRadius = Radius.circular(2.0); + + final RRect trackRRect = RRect.fromRectAndCorners( + trackRect, + topLeft: trackCornerRadius, + bottomLeft: trackCornerRadius, + topRight: trackCornerRadius, + bottomRight: trackCornerRadius, + ); + + final RRect leftRRect = RRect.fromLTRBAndCorners( + trackRect.left, + trackRect.top, + math.max(trackRect.left, thumbCenterDx - trackGapWidth / 2), + trackRect.bottom, + topLeft: trackCornerRadius, + bottomLeft: trackCornerRadius, + topRight: trackInsideCornerRadius, + bottomRight: trackInsideCornerRadius, + ); + + final RRect rightRRect = RRect.fromLTRBAndCorners( + thumbCenterDx + trackGapWidth / 2, + trackRect.top, + trackRect.right, + trackRect.bottom, + topRight: trackCornerRadius, + bottomRight: trackCornerRadius, + topLeft: trackInsideCornerRadius, + bottomLeft: trackInsideCornerRadius, + ); + + canvas + ..save() + ..clipRRect(trackRRect); + canvas.drawRRect(leftRRect, paint); + canvas.drawRRect(rightRRect, inActive); + canvas.restore(); + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + return false; + } +} diff --git a/lib/widgets/navigation_scaffold/components/adaptive_fab.dart b/lib/widgets/navigation_scaffold/components/adaptive_fab.dart new file mode 100644 index 0000000..a0ae48c --- /dev/null +++ b/lib/widgets/navigation_scaffold/components/adaptive_fab.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; + +class AdaptiveFab { + final BuildContext context; + final String title; + final Widget child; + final Function() onPressed; + final Key? key; + AdaptiveFab({ + required this.context, + this.title = '', + required this.child, + required this.onPressed, + this.key, + }); + + FloatingActionButton get normal { + return FloatingActionButton( + key: key, + onPressed: onPressed, + tooltip: title, + child: child, + ); + } + + Widget get extended { + return AnimatedContainer( + key: key, + duration: const Duration(milliseconds: 250), + height: 60, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 4), + child: ElevatedButton( + onPressed: onPressed, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + children: [ + child, + const Spacer(), + Flexible(child: Text(title)), + const Spacer(), + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/widgets/navigation_scaffold/components/destination_model.dart b/lib/widgets/navigation_scaffold/components/destination_model.dart new file mode 100644 index 0000000..6ad6b40 --- /dev/null +++ b/lib/widgets/navigation_scaffold/components/destination_model.dart @@ -0,0 +1,92 @@ +import 'package:fladder/routes/build_routes/route_builder.dart'; +import 'package:fladder/widgets/navigation_scaffold/components/adaptive_fab.dart'; +import 'package:fladder/widgets/navigation_scaffold/components/navigation_button.dart'; +import 'package:flutter/material.dart'; + +class DestinationModel { + final String label; + final Widget? icon; + final Widget? selectedIcon; + final CustomRoute? route; + final Function()? action; + final String? tooltip; + final Badge? badge; + final AdaptiveFab? floatingActionButton; + // final FloatingActionButton? floatingActionButton; + + DestinationModel({ + required this.label, + this.icon, + this.selectedIcon, + this.route, + this.action, + this.tooltip, + this.badge, + this.floatingActionButton, + }) : assert( + badge == null || icon == null, + 'Only one of icon or badge should be provided, not both.', + ); + + /// Converts this [DestinationModel] to a [NavigationRailDestination] used in a [NavigationRail]. + NavigationRailDestination toNavigationRailDestination({EdgeInsets? padding}) { + if (badge != null) { + return NavigationRailDestination( + icon: badge!, + label: Text(label), + selectedIcon: badge!, + padding: padding, + ); + } + return NavigationRailDestination( + icon: icon!, + label: Text(label), + selectedIcon: selectedIcon, + padding: padding, + ); + } + + /// Converts this [DestinationModel] to a [NavigationDrawerDestination] used in a [NavigationDrawer]. + NavigationDrawerDestination toNavigationDrawerDestination() { + if (badge != null) { + return NavigationDrawerDestination( + icon: badge!, + label: Text(label), + selectedIcon: badge!, + ); + } + return NavigationDrawerDestination( + icon: icon!, + label: Text(label), + selectedIcon: selectedIcon, + ); + } + + /// Converts this [DestinationModel] to a [NavigationDestination] used in a [BottomNavigationBar]. + NavigationDestination toNavigationDestination() { + if (badge != null) { + return NavigationDestination( + icon: badge!, + label: label, + selectedIcon: badge!, + ); + } + return NavigationDestination( + icon: icon!, + label: label, + selectedIcon: selectedIcon, + tooltip: tooltip, + ); + } + + NavigationButton toNavigationButton(bool selected, bool expanded) { + return NavigationButton( + label: label, + selected: selected, + onPressed: action, + horizontal: expanded, + selectedIcon: selectedIcon!, + icon: icon!, + ); + } +} diff --git a/lib/widgets/navigation_scaffold/components/drawer_list_button.dart b/lib/widgets/navigation_scaffold/components/drawer_list_button.dart new file mode 100644 index 0000000..55ee378 --- /dev/null +++ b/lib/widgets/navigation_scaffold/components/drawer_list_button.dart @@ -0,0 +1,77 @@ +import 'package:fladder/screens/shared/animated_fade_size.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/widgets/shared/item_actions.dart'; +import 'package:fladder/widgets/shared/modal_bottom_sheet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class DrawerListButton extends ConsumerStatefulWidget { + final String label; + final Widget selectedIcon; + final Widget icon; + final Function()? onPressed; + final List actions; + final bool selected; + final Duration duration; + const DrawerListButton({ + required this.label, + required this.selectedIcon, + required this.icon, + this.onPressed, + this.actions = const [], + this.selected = false, + this.duration = const Duration(milliseconds: 125), + super.key, + }); + + @override + ConsumerState createState() => _DrawerListButtonState(); +} + +class _DrawerListButtonState extends ConsumerState { + bool showPopupButton = false; + @override + Widget build(BuildContext context) { + return MouseRegion( + onEnter: (event) => setState(() => showPopupButton = true), + onExit: (event) => setState(() => showPopupButton = false), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), + child: ListTile( + onTap: widget.onPressed, + horizontalTitleGap: 15, + selected: widget.selected, + selectedTileColor: Theme.of(context).colorScheme.primary, + selectedColor: Theme.of(context).colorScheme.onPrimary, + onLongPress: widget.actions.isNotEmpty && AdaptiveLayout.of(context).inputDevice == InputDevice.touch + ? () => showBottomSheetPill( + context: context, + content: (context, scrollController) => ListView( + shrinkWrap: true, + controller: scrollController, + children: widget.actions.listTileItems(context, useIcons: true), + ), + ) + : null, + contentPadding: const EdgeInsets.symmetric(horizontal: 14, vertical: 5), + leading: Padding( + padding: const EdgeInsets.all(3), + child: + AnimatedFadeSize(duration: widget.duration, child: widget.selected ? widget.selectedIcon : widget.icon), + ), + trailing: widget.actions.isNotEmpty && AdaptiveLayout.of(context).inputDevice == InputDevice.pointer + ? AnimatedOpacity( + duration: const Duration(milliseconds: 125), + opacity: showPopupButton ? 1 : 0, + child: PopupMenuButton( + tooltip: "Options", + itemBuilder: (context) => widget.actions.popupMenuItems(useIcons: true), + ), + ) + : null, + title: Text(widget.label), + ), + ), + ); + } +} diff --git a/lib/widgets/navigation_scaffold/components/fladder_appbar.dart b/lib/widgets/navigation_scaffold/components/fladder_appbar.dart new file mode 100644 index 0000000..1f13d70 --- /dev/null +++ b/lib/widgets/navigation_scaffold/components/fladder_appbar.dart @@ -0,0 +1,59 @@ +import 'package:fladder/screens/shared/default_titlebar.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:go_router/go_router.dart'; + +bool get _isDesktop { + if (kIsWeb) return false; + return [ + TargetPlatform.windows, + TargetPlatform.linux, + TargetPlatform.macOS, + ].contains(defaultTargetPlatform); +} + +class FladderAppbar extends StatelessWidget implements PreferredSize { + final double height; + final String? label; + final bool automaticallyImplyLeading; + const FladderAppbar({this.height = 35, this.automaticallyImplyLeading = false, this.label, super.key}); + + @override + Widget build(BuildContext context) { + if (AdaptiveLayout.of(context).isDesktop) { + return PreferredSize( + preferredSize: Size(double.infinity, height), + child: SizedBox( + height: height, + child: Row( + children: [ + if (automaticallyImplyLeading && context.canPop()) BackButton(), + Expanded( + child: DefaultTitleBar( + label: label, + ), + ) + ], + ), + )); + } else { + return AppBar( + toolbarHeight: 0, + backgroundColor: Theme.of(context).colorScheme.surface.withOpacity(0), + scrolledUnderElevation: 0, + elevation: 0, + systemOverlayStyle: SystemUiOverlayStyle(), + title: const Text(""), + automaticallyImplyLeading: automaticallyImplyLeading, + ); + } + } + + @override + Widget get child => Container(); + + @override + Size get preferredSize => Size(double.infinity, _isDesktop ? height : 0); +} diff --git a/lib/widgets/navigation_scaffold/components/floating_player_bar.dart b/lib/widgets/navigation_scaffold/components/floating_player_bar.dart new file mode 100644 index 0000000..1559406 --- /dev/null +++ b/lib/widgets/navigation_scaffold/components/floating_player_bar.dart @@ -0,0 +1,207 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/media_playback_model.dart'; +import 'package:fladder/providers/settings/video_player_settings_provider.dart'; +import 'package:fladder/providers/video_player_provider.dart'; +import 'package:fladder/screens/shared/fladder_snackbar.dart'; +import 'package:fladder/screens/shared/flat_button.dart'; +import 'package:fladder/screens/video_player/video_player.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/duration_extensions.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/refresh_state.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:media_kit_video/media_kit_video.dart'; +import 'package:window_manager/window_manager.dart'; + +class FloatingPlayerBar extends ConsumerStatefulWidget { + const FloatingPlayerBar({super.key}); + + @override + ConsumerState createState() => _CurrentlyPlayingBarState(); +} + +class _CurrentlyPlayingBarState extends ConsumerState { + bool showExpandButton = false; + + Future openFullScreenPlayer() async { + setState(() => showExpandButton = false); + ref.read(mediaPlaybackProvider.notifier).update((state) => state.copyWith(state: VideoPlayerState.fullScreen)); + await Navigator.of(context, rootNavigator: true).push( + MaterialPageRoute( + builder: (context) => const VideoPlayer(), + ), + ); + if (AdaptiveLayout.of(context).isDesktop || kIsWeb) { + final fullScreen = await windowManager.isFullScreen(); + if (fullScreen) { + await windowManager.setFullScreen(false); + } + } + if (context.mounted) { + context.refreshData(); + } + } + + Future stopPlayer() async { + ref.read(mediaPlaybackProvider.notifier).update((state) => state.copyWith(state: VideoPlayerState.disposed)); + return ref.read(videoPlayerProvider).stop(); + } + + @override + Widget build(BuildContext context) { + final playbackInfo = ref.watch(mediaPlaybackProvider); + final player = ref.watch(videoPlayerProvider); + final playbackModel = ref.watch(playBackModel.select((value) => value?.item)); + final progress = playbackInfo.position.inMilliseconds / playbackInfo.duration.inMilliseconds; + return Dismissible( + key: Key("CurrentlyPlayingBar"), + confirmDismiss: (direction) async { + if (direction == DismissDirection.up) { + await openFullScreenPlayer(); + } else { + await stopPlayer(); + } + return false; + }, + direction: DismissDirection.vertical, + child: InkWell( + onLongPress: () { + fladderSnackbar(context, title: "Swipe up/down to open/close the player"); + }, + child: Card( + elevation: 3, + child: ConstrainedBox( + constraints: BoxConstraints(minHeight: 50, maxHeight: 85), + child: LayoutBuilder(builder: (context, constraints) { + return Row( + children: [ + Flexible( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.all(8), + child: Row( + children: [ + if (playbackInfo.state == VideoPlayerState.minimized) + Card( + child: SizedBox( + child: AspectRatio( + aspectRatio: 1.67, + child: MouseRegion( + onEnter: (event) => setState(() => showExpandButton = true), + onExit: (event) => setState(() => showExpandButton = false), + child: Stack( + children: [ + Hero( + tag: "HeroPlayer", + child: Video( + controller: player.controller!, + fit: BoxFit.fitHeight, + controls: NoVideoControls, + wakelock: playbackInfo.playing, + ), + ), + Positioned.fill( + child: Tooltip( + message: "Expand player", + waitDuration: Duration(milliseconds: 500), + child: AnimatedOpacity( + opacity: showExpandButton ? 1 : 0, + duration: const Duration(milliseconds: 125), + child: Container( + color: Colors.black.withOpacity(0.6), + child: FlatButton( + onTap: () async => openFullScreenPlayer(), + child: Icon(Icons.keyboard_arrow_up_rounded), + ), + ), + ), + ), + ) + ], + ), + ), + ), + ), + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Flexible( + child: Text( + playbackModel?.title ?? "", + style: Theme.of(context).textTheme.titleLarge, + ), + ), + if (playbackModel?.detailedName(context)?.isNotEmpty == true) + Flexible( + child: Text( + playbackModel?.detailedName(context) ?? "", + style: Theme.of(context).textTheme.titleMedium, + ), + ), + ], + ), + ), + if (!progress.isNaN && constraints.maxWidth > 500) + Text( + "${playbackInfo.position.readAbleDuration} / ${playbackInfo.duration.readAbleDuration}"), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: IconButton.filledTonal( + onPressed: () => ref.read(videoPlayerProvider).playOrPause(), + icon: playbackInfo.playing + ? Icon(Icons.pause_rounded) + : Icon(Icons.play_arrow_rounded), + ), + ), + if (constraints.maxWidth > 500) ...{ + IconButton( + onPressed: () { + final volume = player.player?.state.volume == 0 ? 100.0 : 0.0; + ref.read(videoPlayerSettingsProvider.notifier).setVolume(volume); + player.setVolume(volume); + }, + icon: Icon( + ref.watch(videoPlayerSettingsProvider.select((value) => value.volume)) <= 0 + ? IconsaxBold.volume_cross + : IconsaxBold.volume_high, + ), + ), + Tooltip( + message: "Stop playback", + waitDuration: Duration(milliseconds: 500), + child: IconButton( + onPressed: () async => stopPlayer(), + icon: Icon(IconsaxBold.stop), + ), + ), + }, + ].addInBetween(SizedBox(width: 8)), + ), + ), + ), + LinearProgressIndicator( + minHeight: 6, + backgroundColor: Colors.black.withOpacity(0.25), + color: Theme.of(context).colorScheme.primary, + value: progress.clamp(0, 1), + ) + ], + ), + ), + ], + ); + }), + ), + ), + ), + ); + } +} diff --git a/lib/widgets/navigation_scaffold/components/navigation_body.dart b/lib/widgets/navigation_scaffold/components/navigation_body.dart new file mode 100644 index 0000000..09a7c32 --- /dev/null +++ b/lib/widgets/navigation_scaffold/components/navigation_body.dart @@ -0,0 +1,170 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/providers/views_provider.dart'; +import 'package:fladder/widgets/navigation_scaffold/components/navigation_drawer.dart'; +import 'package:flutter/material.dart'; + +import 'package:collection/collection.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'package:fladder/routes/build_routes/settings_routes.dart'; +import 'package:fladder/screens/shared/animated_fade_size.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/widgets/navigation_scaffold/components/adaptive_fab.dart'; +import 'package:fladder/widgets/navigation_scaffold/components/destination_model.dart'; +import 'package:fladder/widgets/navigation_scaffold/components/settings_user_icon.dart'; + +class NavigationBody extends ConsumerStatefulWidget { + final BuildContext parentContext; + final Widget child; + final int currentIndex; + final List destinations; + final String currentLocation; + final GlobalKey drawerKey; + const NavigationBody({ + required this.parentContext, + required this.child, + required this.currentIndex, + required this.destinations, + required this.currentLocation, + required this.drawerKey, + super.key, + }); + + @override + ConsumerState createState() => _NavigationBodyState(); +} + +class _NavigationBodyState extends ConsumerState { + bool expandedSideBar = true; + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((value) { + ref.read(viewsProvider.notifier).fetchViews(); + }); + } + + @override + Widget build(BuildContext context) { + final views = ref.watch(viewsProvider.select((value) => value.views)); + return switch (AdaptiveLayout.layoutOf(context)) { + LayoutState.phone => MediaQuery.removePadding( + context: widget.parentContext, + child: widget.child, + ), + LayoutState.tablet => Row( + children: [ + navigationRail(context), + Flexible( + child: widget.child, + ) + ], + ), + LayoutState.desktop => Row( + children: [ + AnimatedFadeSize( + duration: const Duration(milliseconds: 125), + child: expandedSideBar + ? MediaQuery.removePadding( + context: widget.parentContext, + child: NestedNavigationDrawer( + isExpanded: expandedSideBar, + actionButton: actionButton(), + toggleExpanded: (value) { + setState(() { + expandedSideBar = value; + }); + }, + views: views, + destinations: widget.destinations, + currentLocation: widget.currentLocation, + ), + ) + : navigationRail(context), + ), + Flexible( + child: widget.child, + ), + ], + ) + }; + } + + AdaptiveFab? actionButton() { + return (widget.currentIndex >= 0 && widget.currentIndex < widget.destinations.length) + ? widget.destinations[widget.currentIndex].floatingActionButton + : null; + } + + Widget navigationRail(BuildContext context) { + return Padding( + key: const Key('navigation_rail'), + padding: AdaptiveLayout.of(context).isDesktop ? EdgeInsets.zero : MediaQuery.of(context).padding, + child: Column( + children: [ + if (AdaptiveLayout.of(context).isDesktop && AdaptiveLayout.of(context).platform != TargetPlatform.macOS) ...{ + const SizedBox(height: 4), + Text( + "Fladder", + style: Theme.of(context).textTheme.titleSmall, + ), + }, + const SizedBox(height: 8), + IconButton( + onPressed: () { + if (AdaptiveLayout.layoutOf(context) != LayoutState.desktop) { + widget.drawerKey.currentState?.openDrawer(); + } else { + setState(() { + expandedSideBar = true; + }); + } + }, + icon: const Icon(IconsaxBold.menu), + ), + if (AdaptiveLayout.of(context).isDesktop) ...[ + const SizedBox(height: 8), + AnimatedFadeSize( + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 250), + transitionBuilder: (Widget child, Animation animation) { + return ScaleTransition(scale: animation, child: child); + }, + child: actionButton()?.normal, + ), + ), + ], + const Spacer(), + IconTheme( + data: IconThemeData(size: 28), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + ...widget.destinations.mapIndexed( + (index, destination) => destination.toNavigationButton(widget.currentIndex == index, false), + ) + ], + ), + ), + const Spacer(), + SizedBox( + height: 48, + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 250), + child: widget.currentLocation.contains(SettingsRoute().route) + ? Card( + color: Theme.of(context).colorScheme.primaryContainer, + child: Padding( + padding: const EdgeInsets.all(10), + child: Icon(IconsaxBold.setting_3), + ), + ) + : const SettingsUserIcon()), + ), + if (AdaptiveLayout.of(context).inputDevice == InputDevice.pointer) const SizedBox(height: 16), + ], + ), + ); + } +} diff --git a/lib/widgets/navigation_scaffold/components/navigation_button.dart b/lib/widgets/navigation_scaffold/components/navigation_button.dart new file mode 100644 index 0000000..0fe4bff --- /dev/null +++ b/lib/widgets/navigation_scaffold/components/navigation_button.dart @@ -0,0 +1,125 @@ +import 'package:fladder/util/widget_extensions.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class NavigationButton extends ConsumerStatefulWidget { + final String? label; + final Widget selectedIcon; + final Widget icon; + final bool horizontal; + final Function()? onPressed; + final bool selected; + final Duration duration; + const NavigationButton({ + required this.label, + required this.selectedIcon, + required this.icon, + this.horizontal = false, + this.onPressed, + this.selected = false, + this.duration = const Duration(milliseconds: 125), + super.key, + }); + + @override + ConsumerState createState() => _NavigationButtonState(); +} + +class _NavigationButtonState extends ConsumerState { + @override + Widget build(BuildContext context) { + return Tooltip( + waitDuration: const Duration(seconds: 1), + preferBelow: false, + triggerMode: TooltipTriggerMode.longPress, + message: widget.label ?? "", + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: widget.horizontal + ? Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: getChildren(context), + ) + : Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: getChildren(context), + ), + ), + ); + } + + List getChildren(BuildContext context) { + return [ + Flexible( + child: ElevatedButton( + style: ButtonStyle( + elevation: WidgetStatePropertyAll(0), + padding: WidgetStatePropertyAll(EdgeInsets.zero), + backgroundColor: WidgetStatePropertyAll(Colors.transparent), + foregroundColor: WidgetStateProperty.resolveWith((states) { + return widget.selected + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.onSurface.withOpacity(0.45); + })), + onPressed: widget.onPressed, + child: AnimatedContainer( + curve: Curves.fastOutSlowIn, + duration: widget.duration, + child: Padding( + padding: const EdgeInsets.all(12), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Row( + children: [ + AnimatedSwitcher( + duration: widget.duration, + child: widget.selected + ? widget.selectedIcon.setKey(Key("${widget.label}+selected")) + : widget.icon.setKey(Key("${widget.label}+normal")), + ), + if (widget.horizontal && widget.label != null) + Padding( + padding: const EdgeInsets.only(left: 8.0), + child: _Label(widget: widget), + ) + ], + ), + AnimatedContainer( + duration: Duration(milliseconds: 250), + margin: EdgeInsets.only(top: widget.selected ? 8 : 0), + height: widget.selected ? 6 : 0, + width: widget.selected ? 14 : 0, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: Theme.of(context).colorScheme.primary.withOpacity(widget.selected ? 1 : 0), + ), + ), + ], + ), + ), + ), + ), + ), + ]; + } +} + +class _Label extends StatelessWidget { + const _Label({required this.widget}); + + final NavigationButton widget; + + @override + Widget build(BuildContext context) { + return Text( + widget.label!, + maxLines: 1, + overflow: TextOverflow.fade, + style: + Theme.of(context).textTheme.labelMedium?.copyWith(color: Theme.of(context).colorScheme.onSecondaryContainer), + ); + } +} diff --git a/lib/widgets/navigation_scaffold/components/navigation_drawer.dart b/lib/widgets/navigation_scaffold/components/navigation_drawer.dart new file mode 100644 index 0000000..a3807a1 --- /dev/null +++ b/lib/widgets/navigation_scaffold/components/navigation_drawer.dart @@ -0,0 +1,153 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/models/collection_types.dart'; +import 'package:fladder/models/view_model.dart'; +import 'package:fladder/routes/build_routes/home_routes.dart'; +import 'package:fladder/routes/build_routes/route_builder.dart'; +import 'package:fladder/routes/build_routes/settings_routes.dart'; +import 'package:fladder/screens/metadata/refresh_metadata.dart'; +import 'package:fladder/screens/shared/animated_fade_size.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/widgets/navigation_scaffold/components/adaptive_fab.dart'; +import 'package:fladder/widgets/navigation_scaffold/components/destination_model.dart'; +import 'package:fladder/widgets/navigation_scaffold/components/drawer_list_button.dart'; +import 'package:fladder/widgets/navigation_scaffold/components/settings_user_icon.dart'; +import 'package:fladder/widgets/shared/item_actions.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class NestedNavigationDrawer extends ConsumerWidget { + final bool isExpanded; + final Function(bool expanded) toggleExpanded; + final List destinations; + final AdaptiveFab? actionButton; + final List views; + final String currentLocation; + const NestedNavigationDrawer( + {this.isExpanded = false, + required this.toggleExpanded, + required this.actionButton, + required this.destinations, + required this.views, + required this.currentLocation, + super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return NavigationDrawer( + key: const Key('navigation_drawer'), + backgroundColor: isExpanded ? Colors.transparent : null, + surfaceTintColor: isExpanded ? Colors.transparent : null, + children: [ + if (AdaptiveLayout.of(context).isDesktop || kIsWeb) const SizedBox(height: 16), + Padding( + padding: const EdgeInsets.fromLTRB(28, 0, 16, 0), + child: Row( + children: [ + Expanded( + child: Text( + context.localized.navigation, + style: Theme.of(context).textTheme.titleMedium, + ), + ), + IconButton( + onPressed: () => toggleExpanded(false), + icon: const Icon(IconsaxOutline.menu), + ), + ], + ), + ), + Padding( + padding: EdgeInsets.symmetric(horizontal: 12, vertical: actionButton != null ? 8 : 0), + child: AnimatedFadeSize( + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 250), + transitionBuilder: (Widget child, Animation animation) { + return ScaleTransition(scale: animation, child: child); + }, + child: actionButton?.extended, + ), + ), + ), + ...destinations.map((destination) => DrawerListButton( + label: destination.label, + selected: destination.route?.route == currentLocation, + selectedIcon: destination.selectedIcon!, + icon: destination.icon!, + onPressed: () { + destination.action!(); + Scaffold.of(context).closeDrawer(); + }, + )), + if (views.isNotEmpty) ...{ + const Divider(indent: 28, endIndent: 28), + Padding( + padding: const EdgeInsets.fromLTRB(28, 16, 16, 10), + child: Text( + context.localized.library(2), + style: Theme.of(context).textTheme.titleMedium, + ), + ), + ...views.map((library) => DrawerListButton( + label: library.name, + selected: currentLocation.contains(library.id), + actions: [ + ItemActionButton( + label: Text(context.localized.scanLibrary), + icon: Icon(IconsaxOutline.refresh), + action: () => showRefreshPopup(context, library.id, library.name), + ), + ], + onPressed: () { + context.routePushOrGo(LibrarySearchRoute(id: library.id)); + Scaffold.of(context).closeDrawer(); + }, + selectedIcon: Icon(library.collectionType.icon), + icon: Icon(library.collectionType.iconOutlined))), + }, + const Divider(indent: 28, endIndent: 28), + if (isExpanded) + Transform.translate( + offset: Offset(-8, 0), + child: DrawerListButton( + label: context.localized.settings, + selectedIcon: const Icon(IconsaxBold.setting_3), + selected: currentLocation.contains(SettingsRoute().basePath), + icon: const SizedBox(width: 35, height: 35, child: SettingsUserIcon()), + onPressed: () { + switch (AdaptiveLayout.of(context).size) { + case ScreenLayout.single: + context.routePush(SettingsRoute()); + break; + case ScreenLayout.dual: + context.routeGo(ClientSettingsRoute()); + break; + } + Scaffold.of(context).closeDrawer(); + }, + ), + ) + else + DrawerListButton( + label: context.localized.settings, + selectedIcon: Icon(IconsaxBold.setting_2), + icon: Icon(IconsaxOutline.setting_2), + selected: currentLocation.contains(SettingsRoute().basePath), + onPressed: () { + switch (AdaptiveLayout.of(context).size) { + case ScreenLayout.single: + context.routePush(SettingsRoute()); + break; + case ScreenLayout.dual: + context.routeGo(ClientSettingsRoute()); + break; + } + Scaffold.of(context).closeDrawer(); + }, + ), + if (AdaptiveLayout.of(context).isDesktop || kIsWeb) const SizedBox(height: 8), + ], + ); + } +} diff --git a/lib/widgets/navigation_scaffold/components/settings_user_icon.dart b/lib/widgets/navigation_scaffold/components/settings_user_icon.dart new file mode 100644 index 0000000..b09ee2d --- /dev/null +++ b/lib/widgets/navigation_scaffold/components/settings_user_icon.dart @@ -0,0 +1,30 @@ +import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/routes/build_routes/route_builder.dart'; +import 'package:fladder/routes/build_routes/settings_routes.dart'; +import 'package:fladder/screens/shared/user_icon.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class SettingsUserIcon extends ConsumerWidget { + const SettingsUserIcon({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final users = ref.watch(userProvider); + return Tooltip( + message: context.localized.settings, + waitDuration: const Duration(seconds: 1), + child: UserIcon( + user: users, + cornerRadius: 200, + onLongPress: () => context.routePush(LockScreenRoute()), + onTap: () => switch (AdaptiveLayout.of(context).size) { + ScreenLayout.single => context.routePush(SettingsRoute()), + ScreenLayout.dual => context.routePush(ClientSettingsRoute()), + }, + ), + ); + } +} diff --git a/lib/widgets/navigation_scaffold/navigation_scaffold.dart b/lib/widgets/navigation_scaffold/navigation_scaffold.dart new file mode 100644 index 0000000..a83bff3 --- /dev/null +++ b/lib/widgets/navigation_scaffold/navigation_scaffold.dart @@ -0,0 +1,118 @@ +import 'package:fladder/models/media_playback_model.dart'; +import 'package:fladder/providers/video_player_provider.dart'; +import 'package:fladder/providers/views_provider.dart'; +import 'package:fladder/routes/app_routes.dart'; +import 'package:fladder/screens/shared/nested_bottom_appbar.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/widgets/navigation_scaffold/components/floating_player_bar.dart'; +import 'package:fladder/widgets/navigation_scaffold/components/destination_model.dart'; +import 'package:fladder/widgets/navigation_scaffold/components/fladder_appbar.dart'; +import 'package:fladder/widgets/navigation_scaffold/components/navigation_body.dart'; +import 'package:fladder/widgets/navigation_scaffold/components/navigation_drawer.dart'; +import 'package:fladder/widgets/shared/hide_on_scroll.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class NavigationScaffold extends ConsumerStatefulWidget { + final int? currentIndex; + final String? location; + final Widget? nestedChild; + final List destinations; + final GlobalKey? nestedNavigatorKey; + const NavigationScaffold({ + this.currentIndex, + this.location, + this.nestedChild, + required this.destinations, + this.nestedNavigatorKey, + super.key, + }); + + @override + ConsumerState createState() => _NavigationScaffoldState(); +} + +class _NavigationScaffoldState extends ConsumerState { + final GlobalKey _key = GlobalKey(); + + int get currentIndex => widget.destinations.indexWhere((element) => element.route?.route == widget.location); + String get currentLocation => widget.location ?? "Nothing"; + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((value) { + ref.read(viewsProvider.notifier).fetchViews(); + }); + } + + @override + Widget build(BuildContext context) { + final playerState = ref.watch(mediaPlaybackProvider.select((value) => value.state)); + final views = ref.watch(viewsProvider.select((value) => value.views)); + return PopScope( + canPop: currentIndex == 0, + onPopInvoked: (didPop) { + if (currentIndex != 0) { + widget.destinations.first.action!(); + } + }, + child: Scaffold( + key: _key, + appBar: const FladderAppbar(), + extendBodyBehindAppBar: true, + extendBody: true, + floatingActionButtonLocation: + playerState == VideoPlayerState.minimized ? FloatingActionButtonLocation.centerFloat : null, + floatingActionButton: AdaptiveLayout.of(context).layout == LayoutState.phone + ? switch (playerState) { + VideoPlayerState.minimized => Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: FloatingPlayerBar(), + ), + _ => widget.destinations.elementAtOrNull(currentIndex)?.floatingActionButton?.normal, + } + : null, + drawer: NestedNavigationDrawer( + actionButton: null, + toggleExpanded: (value) { + _key.currentState?.closeDrawer(); + }, + views: views, + destinations: widget.destinations, + currentLocation: currentLocation, + ), + bottomNavigationBar: AdaptiveLayout.of(context).layout == LayoutState.phone + ? HideOnScroll( + controller: AppRoutes.scrollController, + child: NestedBottomAppBar( + child: Transform.translate( + offset: Offset(0, 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: widget.destinations + .map( + (destination) => + destination.toNavigationButton(widget.location == destination.route?.route, false), + ) + .toList(), + ), + ), + ), + ) + : null, + body: widget.nestedChild != null + ? NavigationBody( + child: widget.nestedChild!, + parentContext: context, + currentIndex: currentIndex, + destinations: widget.destinations, + currentLocation: currentLocation, + drawerKey: _key, + ) + : null, + ), + ); + } +} diff --git a/lib/widgets/pop_up/delete_file.dart b/lib/widgets/pop_up/delete_file.dart new file mode 100644 index 0000000..d453960 --- /dev/null +++ b/lib/widgets/pop_up/delete_file.dart @@ -0,0 +1,39 @@ +import 'package:chopper/chopper.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/providers/api_provider.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/widgets/shared/filled_button_await.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +Future?> showDeleteDialog(BuildContext context, ItemBaseModel item, WidgetRef ref) async { + Response? response; + await showDialog( + context: context, + barrierDismissible: false, + builder: (context) => AlertDialog.adaptive( + title: Text(context.localized.deleteItem(item.type.label(context))), + content: Text( + context.localized.deleteFileFromSystem(item.name), + ), + scrollable: true, + actions: [ + ElevatedButton(onPressed: () => Navigator.of(context).pop(), child: Text(context.localized.cancel)), + FilledButtonAwait( + style: FilledButton.styleFrom( + backgroundColor: Theme.of(context).colorScheme.errorContainer, + foregroundColor: Theme.of(context).colorScheme.onErrorContainer, + ), + onPressed: () async { + response = await ref.read(jellyApiProvider).deleteItem(item.id); + Navigator.of(context).pop(); + }, + child: Text( + context.localized.delete, + ), + ) + ], + ), + ); + return response; +} diff --git a/lib/widgets/shared/adaptive_date_picker.dart b/lib/widgets/shared/adaptive_date_picker.dart new file mode 100644 index 0000000..58ea15a --- /dev/null +++ b/lib/widgets/shared/adaptive_date_picker.dart @@ -0,0 +1,57 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +Future showAdaptiveDatePicker( + BuildContext context, { + DateTime? initialDateTime, +}) async { + final ThemeData theme = Theme.of(context); + if (theme.platform == TargetPlatform.iOS) { + return _buildCupertinoDatePicker( + context, + initialDateTime: initialDateTime, + ); + } else { + return _buildMaterialDatePicker( + context, + initialDateTime: initialDateTime, + ); + } +} + +Future _buildCupertinoDatePicker( + BuildContext context, { + DateTime? initialDateTime, +}) async { + DateTime? newDate; + showModalBottomSheet( + context: context, + builder: (BuildContext builder) { + return Container( + height: MediaQuery.of(context).copyWith().size.height / 3, + color: Theme.of(context).colorScheme.surface, + child: CupertinoDatePicker( + onDateTimeChanged: (value) { + newDate = value; + }, + initialDateTime: initialDateTime, + dateOrder: DatePickerDateOrder.ymd, + ), + ); + }, + ); + return newDate; +} + +Future _buildMaterialDatePicker( + BuildContext context, { + DateTime? initialDateTime, +}) async { + final DateTime? picked = await showDatePicker( + context: context, + initialDate: initialDateTime ?? DateTime.now(), + firstDate: DateTime(2000), + lastDate: DateTime(2025), + ); + return picked; +} diff --git a/lib/widgets/shared/animated_icon.dart b/lib/widgets/shared/animated_icon.dart new file mode 100644 index 0000000..b5275cc --- /dev/null +++ b/lib/widgets/shared/animated_icon.dart @@ -0,0 +1,92 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; + +class AnimatedVisibilityIcon extends StatefulWidget { + final bool isFilled; + final IconData filledIcon; + final Color filledColor; + final IconData outlinedIcon; + final Color? outlinedColor; + final Duration displayDuration; + + const AnimatedVisibilityIcon({ + super.key, + required this.isFilled, + required this.filledIcon, + this.filledColor = Colors.redAccent, + required this.outlinedIcon, + this.outlinedColor, + this.displayDuration = const Duration(seconds: 2), + }); + + @override + AnimatedVisibilityIconState createState() => AnimatedVisibilityIconState(); +} + +class AnimatedVisibilityIconState extends State { + bool _isVisible = false; + bool _currentFilledState = false; + + Timer? timer; + + @override + void didUpdateWidget(covariant AnimatedVisibilityIcon oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.isFilled != oldWidget.isFilled) { + _animateIconChange(); + } + } + + void _animateIconChange() { + timer?.cancel(); + setState(() { + _isVisible = true; + _currentFilledState = widget.isFilled; + }); + + timer = Timer.periodic( + widget.displayDuration, + (timer) { + if (mounted) { + setState(() { + _isVisible = false; + }); + } + timer.cancel(); + }, + ); + } + + @override + Widget build(BuildContext context) { + return AnimatedScale( + duration: const Duration(milliseconds: 300), + scale: _currentFilledState ? 1.2 : 1.0, + curve: Curves.easeInOutCubic, + child: AnimatedOpacity( + opacity: _isVisible ? 1.0 : 0.0, + duration: const Duration(milliseconds: 300), + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + child: AnimatedContainer( + duration: const Duration(milliseconds: 300), + decoration: BoxDecoration( + color: (_currentFilledState ? widget.filledColor : widget.outlinedColor)?.withOpacity(0.2), + shape: BoxShape.circle, + ), + child: Padding( + padding: const EdgeInsets.only(left: 12, right: 12, top: 8, bottom: 6), + child: Icon( + _currentFilledState ? widget.filledIcon : widget.outlinedIcon, + size: 42, + color: _currentFilledState ? widget.filledColor : widget.outlinedColor, + key: ValueKey(_currentFilledState), + ), + ), + ), + ), + ), + ); + } +} diff --git a/lib/widgets/shared/clickable_text.dart b/lib/widgets/shared/clickable_text.dart new file mode 100644 index 0000000..25f4585 --- /dev/null +++ b/lib/widgets/shared/clickable_text.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class ClickableText extends ConsumerStatefulWidget { + final String text; + final double opacity; + final int? maxLines; + final TextOverflow? overflow; + final TextStyle? style; + final VoidCallback? onTap; + const ClickableText( + {required this.text, + this.style, + this.maxLines, + this.overflow = TextOverflow.ellipsis, + this.opacity = 1.0, + this.onTap, + super.key}); + + @override + ConsumerState createState() => _ClickableTextState(); +} + +class _ClickableTextState extends ConsumerState { + bool hovering = false; + + Widget _textWidget(bool showDecoration) { + return Opacity( + opacity: widget.opacity, + child: Text( + widget.text, + maxLines: widget.maxLines, + overflow: widget.overflow, + style: widget.style?.copyWith( + color: showDecoration ? Theme.of(context).colorScheme.primary : null, + decoration: showDecoration ? TextDecoration.underline : TextDecoration.none, + decorationColor: showDecoration ? Theme.of(context).colorScheme.primary : null, + decorationThickness: 3, + ), + ), + ); + } + + Widget _buildClickable() { + final showDecoration = ((widget.onTap != null) && hovering); + return MouseRegion( + cursor: widget.onTap != null ? SystemMouseCursors.click : SystemMouseCursors.basic, + onEnter: (event) => setState(() => hovering = true), + onExit: (event) => setState(() => hovering = false), + child: GestureDetector( + onTap: widget.onTap, + child: Tooltip(message: widget.text, child: _textWidget(showDecoration)), + ), + ); + } + + @override + Widget build(BuildContext context) { + return widget.onTap != null ? _buildClickable() : _textWidget(false); + } +} diff --git a/lib/widgets/shared/elevated_icon.dart b/lib/widgets/shared/elevated_icon.dart new file mode 100644 index 0000000..841ab8a --- /dev/null +++ b/lib/widgets/shared/elevated_icon.dart @@ -0,0 +1,85 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +IconData getBackIcon(BuildContext context) { + if (kIsWeb) { + // Always use 'Icons.arrow_back' as a back_button icon in web. + return Icons.arrow_back; + } + switch (Theme.of(context).platform) { + case TargetPlatform.android: + case TargetPlatform.fuchsia: + case TargetPlatform.linux: + case TargetPlatform.windows: + return Icons.arrow_back; + case TargetPlatform.iOS: + case TargetPlatform.macOS: + return Icons.arrow_back_ios; + } +} + +final _shadows = [ + BoxShadow(blurRadius: 1, spreadRadius: 1, color: Colors.black.withOpacity(0.2)), + BoxShadow(blurRadius: 4, spreadRadius: 4, color: Colors.black.withOpacity(0.1)), + BoxShadow(blurRadius: 16, spreadRadius: 6, color: Colors.black.withOpacity(0.2)), +]; + +class ElevatedIconButton extends ConsumerWidget { + final Function() onPressed; + final IconData icon; + final Color? color; + const ElevatedIconButton({required this.onPressed, required this.icon, this.color, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return IconButton( + onPressed: onPressed, + style: IconButtonTheme.of(context).style?.copyWith( + backgroundColor: WidgetStatePropertyAll(color?.withOpacity(0.15)), + ), + color: color, + icon: Icon( + icon, + shadows: _shadows, + ), + ); + } +} + +class ElevatedIconButtonLabel extends StatelessWidget { + final Function() onPressed; + final String label; + final IconData icon; + final Color? color; + const ElevatedIconButtonLabel({ + required this.onPressed, + required this.label, + required this.icon, + this.color, + super.key, + }); + + @override + Widget build(BuildContext context) { + return Tooltip( + message: label, + child: ConstrainedBox( + constraints: BoxConstraints(maxWidth: 65), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ElevatedIconButton(onPressed: onPressed, icon: icon), + Flexible( + child: Text( + label, + textAlign: TextAlign.center, + maxLines: 2, + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/widgets/shared/enum_selection.dart b/lib/widgets/shared/enum_selection.dart new file mode 100644 index 0000000..c18b125 --- /dev/null +++ b/lib/widgets/shared/enum_selection.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class EnumBox extends StatelessWidget { + final String current; + final List> Function(BuildContext context) itemBuilder; + + const EnumBox({required this.current, required this.itemBuilder, super.key}); + + @override + Widget build(BuildContext context) { + final textStyle = Theme.of(context).textTheme.titleMedium; + const padding = EdgeInsets.symmetric(horizontal: 12, vertical: 6); + final itemList = itemBuilder(context); + return Card( + color: Theme.of(context).colorScheme.primaryContainer, + shadowColor: Colors.transparent, + elevation: 0, + child: PopupMenuButton( + tooltip: '', + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), + enabled: itemList.length > 1, + itemBuilder: itemBuilder, + padding: padding, + child: Padding( + padding: padding, + child: Material( + textStyle: textStyle?.copyWith( + fontWeight: FontWeight.bold, + color: itemList.length > 1 ? Theme.of(context).colorScheme.onPrimaryContainer : null), + color: Colors.transparent, + child: Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Flexible( + child: Text( + current, + textAlign: TextAlign.start, + ), + ), + const SizedBox(width: 6), + if (itemList.length > 1) + Icon( + Icons.keyboard_arrow_down, + color: Theme.of(context).colorScheme.onPrimaryContainer, + ) + ], + ), + ), + ), + ), + ); + } +} + +class EnumSelection extends StatelessWidget { + final Text label; + final String current; + final List> Function(BuildContext context) itemBuilder; + const EnumSelection({ + required this.label, + required this.current, + required this.itemBuilder, + }); + + @override + Widget build(BuildContext context) { + return Material( + color: Colors.transparent, + textStyle: Theme.of(context).textTheme.titleMedium, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + label, + const Spacer(), + EnumBox(current: current, itemBuilder: itemBuilder), + ].toList(), + ), + ); + } +} diff --git a/lib/widgets/shared/filled_button_await.dart b/lib/widgets/shared/filled_button_await.dart new file mode 100644 index 0000000..d2272b6 --- /dev/null +++ b/lib/widgets/shared/filled_button_await.dart @@ -0,0 +1,61 @@ +import 'dart:async'; +import 'dart:developer'; + +import 'package:fladder/screens/shared/animated_fade_size.dart'; +import 'package:flutter/material.dart'; + +class FilledButtonAwait extends StatefulWidget { + final FutureOr Function() onPressed; + final ButtonStyle? style; + final Widget child; + + const FilledButtonAwait({ + required this.onPressed, + this.style, + required this.child, + super.key, + }); + + @override + State createState() => FilledButtonAwaitState(); +} + +class FilledButtonAwaitState extends State { + bool loading = false; + + @override + Widget build(BuildContext context) { + const duration = Duration(milliseconds: 250); + const iconSize = 24.0; + return FilledButton( + style: widget.style, + onPressed: loading + ? null + : () async { + setState(() => loading = true); + try { + await widget.onPressed(); + } catch (e) { + log(e.toString()); + } finally { + setState(() => loading = false); + } + }, + child: AnimatedFadeSize( + duration: duration, + child: loading + ? Opacity( + opacity: 0.75, + child: SizedBox( + width: iconSize, + height: iconSize, + child: CircularProgressIndicator( + strokeCap: StrokeCap.round, + color: widget.style?.foregroundColor?.resolve({WidgetState.hovered}), + ), + ), + ) + : widget.child, + )); + } +} diff --git a/lib/widgets/shared/fladder_scrollbar.dart b/lib/widgets/shared/fladder_scrollbar.dart new file mode 100644 index 0000000..b5f8949 --- /dev/null +++ b/lib/widgets/shared/fladder_scrollbar.dart @@ -0,0 +1,39 @@ +import 'package:flexible_scrollbar/flexible_scrollbar.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class FladderScrollbar extends ConsumerWidget { + final ScrollController controller; + final Widget child; + final bool visible; + const FladderScrollbar({ + required this.controller, + required this.child, + this.visible = true, + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return visible + ? FlexibleScrollbar( + child: child, + controller: controller, + alwaysVisible: false, + scrollThumbBuilder: (ScrollbarInfo info) { + return AnimatedContainer( + width: info.isDragging ? 24 : 8, + height: (info.thumbMainAxisSize / 2), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5), + color: info.isDragging + ? Theme.of(context).colorScheme.secondary + : Theme.of(context).colorScheme.secondaryContainer.withOpacity(0.75), + ), + duration: Duration(milliseconds: 250), + ); + }, + ) + : child; + } +} diff --git a/lib/widgets/shared/fladder_slider.dart b/lib/widgets/shared/fladder_slider.dart new file mode 100644 index 0000000..d06e899 --- /dev/null +++ b/lib/widgets/shared/fladder_slider.dart @@ -0,0 +1,202 @@ +import 'package:fladder/util/num_extension.dart'; +import 'package:fladder/widgets/gapped_container_shape.dart'; +import 'package:flutter/material.dart'; + +double normalize(double min, double max, double value) { + return (value - min) / (max - min); +} + +class FladderSlider extends StatefulWidget { + final double value; + final double min; + final double max; + final int? divisions; + final double thumbWidth; + final bool showThumb; + final Duration animation; + final Function(double value)? onChanged; + final Function(double value)? onChangeStart; + final Function(double value)? onChangeEnd; + + const FladderSlider({ + required this.value, + this.min = 0.0, + this.max = 1.0, + this.divisions, + this.onChanged, + this.thumbWidth = 6.5, + this.showThumb = true, + this.animation = const Duration(milliseconds: 100), + this.onChangeStart, + this.onChangeEnd, + super.key, + }) : assert(value >= min || value <= max); + + @override + FladderSliderState createState() => FladderSliderState(); +} + +class FladderSliderState extends State with SingleTickerProviderStateMixin { + late AnimationController _controller; + late Animation _animation; + double _currentValue = 0.0; + bool hovering = false; + bool dragging = false; + + @override + void initState() { + super.initState(); + _currentValue = widget.value; + _controller = AnimationController(vsync: this, duration: widget.animation); + _animation = Tween(begin: widget.value, end: widget.value).animate(_controller); + } + + @override + void didUpdateWidget(covariant FladderSlider oldWidget) { + super.didUpdateWidget(oldWidget); + + if (oldWidget.value != widget.value || oldWidget.divisions != widget.divisions) { + double newValue = widget.value; + + if (widget.divisions != null) { + final stepSize = (widget.max - widget.min) / widget.divisions!; + newValue = ((newValue - widget.min) / stepSize).round() * stepSize + widget.min; + } + + setState(() { + _currentValue = newValue; + }); + + _animation = Tween(begin: _animation.value, end: _currentValue).animate(_controller); + _controller.forward(from: 0.0); + } + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + double normalize(double min, double max, double value) { + return (value - min) / (max - min); + } + + @override + Widget build(BuildContext context) { + final thumbWidth = widget.thumbWidth; + final height = Theme.of(context).sliderTheme.trackHeight ?? 24.0; + + double calculateChange(double offset, double width) { + double relativeOffset = (offset / width).clamp(0.0, 1.0); + double newValue = (widget.max - widget.min) * relativeOffset + widget.min; + + if (widget.divisions != null) { + final stepSize = (widget.max - widget.min) / widget.divisions!; + newValue = ((newValue - widget.min) / stepSize).round() * stepSize + widget.min; + } + + setState(() { + _currentValue = newValue.clamp(widget.min, widget.max); + }); + + return _currentValue.roundTo(2); + } + + return Container( + height: height * 4, + color: Colors.transparent, + child: LayoutBuilder( + builder: (context, constraints) { + final width = constraints.maxWidth; + final divisionSize = 5.0 * 0.95; + final stepSize = constraints.maxWidth / (widget.divisions ?? 1); + return MouseRegion( + cursor: SystemMouseCursors.click, + onEnter: (event) => setState(() => hovering = true), + onExit: (event) => setState(() => hovering = false), + child: GestureDetector( + onTapUp: (details) => widget.onChangeEnd?.call(calculateChange(details.localPosition.dx, width)), + onTapDown: (details) => widget.onChanged?.call(calculateChange(details.localPosition.dx, width)), + onHorizontalDragStart: (details) { + setState(() { + dragging = true; + }); + widget.onChangeStart?.call(calculateChange(details.localPosition.dx, width)); + }, + onHorizontalDragEnd: (details) { + setState(() { + dragging = false; + }); + widget.onChangeEnd?.call(calculateChange(details.localPosition.dx, width)); + }, + onHorizontalDragUpdate: (details) => + widget.onChanged?.call(calculateChange(details.localPosition.dx, width)), + child: Container( + color: Colors.transparent, + child: AnimatedBuilder( + animation: _animation, + builder: (context, child) { + final relativeValue = normalize(widget.min, widget.max, _animation.value); + return Stack( + alignment: Alignment.center, + clipBehavior: Clip.none, + children: [ + SizedBox( + height: height, + width: constraints.maxWidth, + child: GappedContainerShape( + thumbPosition: relativeValue, + ), + ), + if (widget.divisions != null && stepSize > divisionSize * 3) + ...List.generate( + widget.divisions! + 1, + (index) { + final offset = (stepSize * index) + .clamp(divisionSize / 1.2, constraints.maxWidth - divisionSize / 1.2); + final active = (1.0 / widget.divisions!) * index > relativeValue; + return Positioned( + left: offset - divisionSize / 2, + child: Container( + width: divisionSize, + height: divisionSize, + decoration: BoxDecoration( + color: active + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.onPrimary, + shape: BoxShape.circle, + ), + ), + ); + }, + ), + // Thumb + if (widget.showThumb) + Positioned( + left: + (width * relativeValue).clamp(thumbWidth / 2, width - thumbWidth / 2) - thumbWidth / 2, + child: AnimatedContainer( + duration: const Duration(milliseconds: 125), + height: (hovering || dragging) ? height * 3 : height, + width: thumbWidth, + decoration: BoxDecoration( + color: (hovering || dragging) + ? Theme.of(context).colorScheme.onSurface + : Theme.of(context).colorScheme.primary, + borderRadius: BorderRadius.circular(8), + ), + ), + ), + ], + ); + }, + ), + ), + ), + ); + }, + ), + ); + } +} diff --git a/lib/widgets/shared/hide_on_scroll.dart b/lib/widgets/shared/hide_on_scroll.dart new file mode 100644 index 0000000..5c8469d --- /dev/null +++ b/lib/widgets/shared/hide_on_scroll.dart @@ -0,0 +1,77 @@ +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class HideOnScroll extends ConsumerStatefulWidget { + final Widget? child; + final ScrollController? controller; + final double height; + final Widget? Function(bool visible)? visibleBuilder; + final Duration duration; + const HideOnScroll({ + this.child, + this.controller, + this.height = kBottomNavigationBarHeight, + this.visibleBuilder, + this.duration = const Duration(milliseconds: 200), + super.key, + }) : assert(child != null || visibleBuilder != null); + + @override + ConsumerState createState() => _HideOnScrollState(); +} + +class _HideOnScrollState extends ConsumerState { + late final scrollController = widget.controller ?? ScrollController(); + bool isVisible = true; + bool atEdge = false; + + @override + void initState() { + super.initState(); + scrollController.addListener(listen); + } + + @override + void dispose() { + scrollController.removeListener(listen); + super.dispose(); + } + + void listen() { + final direction = scrollController.position.userScrollDirection; + + if (scrollController.offset < scrollController.position.maxScrollExtent) { + if (direction == ScrollDirection.forward) { + if (!isVisible) { + setState(() => isVisible = true); + } + } else if (direction == ScrollDirection.reverse) { + if (isVisible) { + setState(() => isVisible = false); + } + } + } else { + setState(() { + isVisible = true; + }); + } + } + + @override + Widget build(BuildContext context) { + if (widget.visibleBuilder != null) return widget.visibleBuilder!(isVisible)!; + if (widget.child == null) return const SizedBox(); + if (AdaptiveLayout.of(context).layout == LayoutState.desktop) { + return widget.child!; + } else { + return AnimatedAlign( + alignment: const Alignment(0, -1), + heightFactor: isVisible ? 1.0 : 0, + duration: widget.duration, + child: Wrap(children: [widget.child!]), + ); + } + } +} diff --git a/lib/widgets/shared/horizontal_list.dart b/lib/widgets/shared/horizontal_list.dart new file mode 100644 index 0000000..fcc7b4d --- /dev/null +++ b/lib/widgets/shared/horizontal_list.dart @@ -0,0 +1,190 @@ +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/providers/settings/client_settings_provider.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/disable_keypad_focus.dart'; +import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/sticky_header_text.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; + +class HorizontalList extends ConsumerStatefulWidget { + final String? label; + final List titleActions; + final Function()? onLabelClick; + final String? subtext; + final List items; + final int? startIndex; + final Widget Function(BuildContext context, int index) itemBuilder; + final bool scrollToEnd; + final EdgeInsets contentPadding; + final double? height; + final bool shrinkWrap; + const HorizontalList({ + required this.items, + required this.itemBuilder, + this.startIndex, + this.height, + this.label, + this.titleActions = const [], + this.onLabelClick, + this.scrollToEnd = false, + this.contentPadding = const EdgeInsets.symmetric(horizontal: 16), + this.subtext, + this.shrinkWrap = false, + super.key, + }); + + @override + ConsumerState createState() => _HorizontalListState(); +} + +class _HorizontalListState extends ConsumerState { + final itemScrollController = ItemScrollController(); + late final scrollOffsetController = ScrollOffsetController(); + + @override + void initState() { + super.initState(); + Future.microtask(() async { + if (widget.startIndex != null) { + itemScrollController.jumpTo(index: widget.startIndex!); + scrollOffsetController.animateScroll( + offset: -widget.contentPadding.left, duration: const Duration(milliseconds: 125)); + } + }); + } + + @override + void dispose() { + super.dispose(); + } + + void _scrollToStart() { + itemScrollController.scrollTo(index: 0, duration: const Duration(milliseconds: 250), curve: Curves.easeInOut); + } + + void _scrollToEnd() { + itemScrollController.scrollTo( + index: widget.items.length, duration: const Duration(milliseconds: 250), curve: Curves.easeInOut); + } + + @override + Widget build(BuildContext context) { + final hasPointer = AdaptiveLayout.of(context).inputDevice == InputDevice.pointer; + return Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + DisableFocus( + child: Padding( + padding: widget.contentPadding, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Flexible( + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + if (widget.label != null) + Flexible( + child: StickyHeaderText( + label: widget.label ?? "", + onClick: widget.onLabelClick, + ), + ), + if (widget.subtext != null) + Opacity( + opacity: 0.5, + child: Text( + widget.subtext!, + style: Theme.of(context).textTheme.titleMedium, + ), + ), + ...widget.titleActions + ], + ), + ), + if (widget.items.length > 1) + Card( + elevation: 5, + color: Theme.of(context).colorScheme.surface, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + if (hasPointer) + GestureDetector( + onLongPress: () => _scrollToStart(), + child: IconButton( + onPressed: () { + scrollOffsetController.animateScroll( + offset: -(MediaQuery.of(context).size.width / 1.75), + duration: const Duration(milliseconds: 250), + curve: Curves.easeInOut); + }, + icon: const Icon( + IconsaxOutline.arrow_left_2, + size: 20, + )), + ), + if (widget.startIndex != null) + IconButton( + tooltip: "Scroll to current", + onPressed: () { + if (widget.startIndex != null) { + itemScrollController.jumpTo(index: widget.startIndex!); + scrollOffsetController.animateScroll( + offset: -widget.contentPadding.left, + duration: const Duration(milliseconds: 250), + curve: Curves.easeInOutQuad); + } + }, + icon: const Icon( + Icons.circle, + size: 16, + )), + if (hasPointer) + GestureDetector( + onLongPress: () => _scrollToEnd(), + child: IconButton( + onPressed: () { + scrollOffsetController.animateScroll( + offset: (MediaQuery.of(context).size.width / 1.75), + duration: const Duration(milliseconds: 250), + curve: Curves.easeInOut); + }, + icon: const Icon( + IconsaxOutline.arrow_right_3, + size: 20, + )), + ), + ], + ), + ), + ].addPadding(const EdgeInsets.symmetric(horizontal: 6)), + ), + ), + ), + const SizedBox(height: 8), + SizedBox( + height: widget.height ?? + AdaptiveLayout.poster(context).size * + ref.watch(clientSettingsProvider.select((value) => value.posterSize)), + child: ScrollablePositionedList.separated( + shrinkWrap: widget.shrinkWrap, + itemScrollController: itemScrollController, + scrollOffsetController: scrollOffsetController, + padding: widget.contentPadding, + itemCount: widget.items.length, + scrollDirection: Axis.horizontal, + separatorBuilder: (context, index) => const SizedBox( + width: 16, + ), + itemBuilder: widget.itemBuilder, + ), + ), + ], + ); + } +} diff --git a/lib/widgets/shared/hover_widget.dart b/lib/widgets/shared/hover_widget.dart new file mode 100644 index 0000000..fc80567 --- /dev/null +++ b/lib/widgets/shared/hover_widget.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class HoverWidget extends ConsumerStatefulWidget { + final Size size; + final Widget Function(bool visible) child; + const HoverWidget({ + this.size = Size.infinite, + required this.child, + super.key, + }); + + @override + ConsumerState createState() => _HoverWidgetState(); +} + +class _HoverWidgetState extends ConsumerState { + bool hovering = false; + + void setHovering(bool value) => setState(() => hovering = value); + + @override + Widget build(BuildContext context) { + return MouseRegion( + onEnter: (event) => setHovering(true), + onExit: (event) => setHovering(false), + child: widget.child(hovering), + ); + } +} diff --git a/lib/widgets/shared/icon_button_await.dart b/lib/widgets/shared/icon_button_await.dart new file mode 100644 index 0000000..2aaaa95 --- /dev/null +++ b/lib/widgets/shared/icon_button_await.dart @@ -0,0 +1,56 @@ +import 'dart:async'; +import 'dart:developer'; + +import 'package:fladder/screens/shared/animated_fade_size.dart'; +import 'package:flutter/material.dart'; + +class IconButtonAwait extends StatefulWidget { + final FutureOr Function() onPressed; + final Color? color; + final Widget icon; + + const IconButtonAwait({required this.onPressed, required this.icon, this.color, super.key}); + + @override + State createState() => IconButtonAwaitState(); +} + +class IconButtonAwaitState extends State { + bool loading = false; + + @override + Widget build(BuildContext context) { + const duration = Duration(milliseconds: 250); + const iconSize = 24.0; + return IconButton( + color: widget.color, + onPressed: loading + ? null + : () async { + setState(() => loading = true); + try { + await widget.onPressed(); + } catch (e) { + log(e.toString()); + } finally { + setState(() => loading = false); + } + }, + icon: AnimatedFadeSize( + duration: duration, + child: loading + ? Opacity( + opacity: 0.75, + child: SizedBox( + width: iconSize, + height: iconSize, + child: CircularProgressIndicator( + strokeCap: StrokeCap.round, + color: Theme.of(context).colorScheme.primary, + ), + ), + ) + : widget.icon, + )); + } +} diff --git a/lib/widgets/shared/item_actions.dart b/lib/widgets/shared/item_actions.dart new file mode 100644 index 0000000..63f9059 --- /dev/null +++ b/lib/widgets/shared/item_actions.dart @@ -0,0 +1,119 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +import 'dart:async'; + +import 'package:collection/collection.dart'; +import 'package:flutter/material.dart'; + +abstract class ItemAction { + Widget toMenuItemButton(); + PopupMenuEntry toPopupMenuItem({bool useIcons = false}); + Widget toLabel(); + Widget toListItem(BuildContext context, {bool useIcons = false, bool shouldPop = true}); +} + +class ItemActionDivider extends ItemAction { + Widget toWidget() => Divider(); + + @override + Divider toMenuItemButton() => Divider(); + + @override + PopupMenuEntry toPopupMenuItem({bool useIcons = false}) => PopupMenuDivider(height: 3); + + @override + Widget toLabel() => Container(); + + @override + Widget toListItem(BuildContext context, {bool useIcons = false, bool shouldPop = true}) => Divider(); +} + +class ItemActionButton extends ItemAction { + final Widget? icon; + final Widget? label; + final FutureOr Function()? action; + ItemActionButton({ + this.icon, + this.label, + this.action, + }); + + ItemActionButton copyWith({ + Widget? icon, + Widget? label, + Future Function()? action, + }) { + return ItemActionButton( + icon: icon ?? this.icon, + label: label ?? this.label, + action: action ?? this.action, + ); + } + + @override + MenuItemButton toMenuItemButton() { + return MenuItemButton(leadingIcon: icon, onPressed: action, child: label); + } + + @override + PopupMenuItem toPopupMenuItem({bool useIcons = false}) { + return PopupMenuItem( + onTap: action, + child: useIcons + ? Builder(builder: (context) { + return Padding( + padding: const EdgeInsets.all(4.0), + child: Theme( + data: ThemeData( + iconTheme: IconThemeData(color: Theme.of(context).colorScheme.onSurface), + ), + child: Row( + children: [if (icon != null) icon!, SizedBox(width: 8), if (label != null) Flexible(child: label!)], + ), + ), + ); + }) + : label, + ); + } + + @override + Widget toLabel() { + return label ?? const Text("Empty"); + } + + @override + ListTile toListItem(BuildContext context, {bool useIcons = false, bool shouldPop = true}) { + return ListTile( + onTap: () { + if (shouldPop) { + Navigator.of(context).pop(); + } + action?.call(); + }, + title: useIcons + ? Builder(builder: (context) { + return Theme( + data: ThemeData( + iconTheme: IconThemeData(color: Theme.of(context).colorScheme.onSurface), + ), + child: Row( + children: [if (icon != null) icon!, SizedBox(width: 8), if (label != null) Flexible(child: label!)], + ), + ); + }) + : label, + ); + } +} + +extension ItemActionExtension on List { + List popupMenuItems({bool useIcons = false}) => map((e) => e.toPopupMenuItem(useIcons: useIcons)) + .whereNotIndexed((index, element) => (index == 0 && element is PopupMenuDivider)) + .toList(); + List menuItemButtonItems() => + map((e) => e.toMenuItemButton()).whereNotIndexed((index, element) => (index == 0 && element is Divider)).toList(); + List listTileItems(BuildContext context, {bool useIcons = false, bool shouldPop = true}) => + map((e) => e.toListItem(context, useIcons: useIcons, shouldPop: shouldPop)) + .whereNotIndexed((index, element) => (index == 0 && element is Divider)) + .toList(); +} diff --git a/lib/widgets/shared/list_button.dart b/lib/widgets/shared/list_button.dart new file mode 100644 index 0000000..6494b6c --- /dev/null +++ b/lib/widgets/shared/list_button.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class ListButton extends ConsumerWidget { + final String label; + final Icon icon; + final VoidCallback onTap; + final double height; + const ListButton({required this.label, required this.icon, required this.onTap, this.height = 56, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return ListTile( + onTap: onTap, + horizontalTitleGap: 15, + contentPadding: const EdgeInsets.symmetric(horizontal: 14, vertical: 5), + leading: Padding( + padding: const EdgeInsets.all(3), + child: icon, + ), + title: Text( + label, + style: Theme.of(context).textTheme.labelLarge, + ), + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(28.0)), + ), + ); + } +} diff --git a/lib/widgets/shared/modal_bottom_sheet.dart b/lib/widgets/shared/modal_bottom_sheet.dart new file mode 100644 index 0000000..fdeb473 --- /dev/null +++ b/lib/widgets/shared/modal_bottom_sheet.dart @@ -0,0 +1,101 @@ +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/fladder_image.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +Future showBottomSheetPill({ + ItemBaseModel? item, + bool showPill = true, + Function()? onDismiss, + EdgeInsets padding = const EdgeInsets.all(16), + required BuildContext context, + required Widget Function( + BuildContext context, + ScrollController scrollController, + ) content, +}) async { + await showModalBottomSheet( + isScrollControlled: true, + useRootNavigator: true, + showDragHandle: true, + enableDrag: true, + context: context, + constraints: AdaptiveLayout.of(context).layout == LayoutState.phone + ? BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.9) + : BoxConstraints( + maxWidth: MediaQuery.of(context).size.width * 0.75, maxHeight: MediaQuery.of(context).size.height * 0.85), + builder: (context) { + final controller = ScrollController(); + return ListView( + shrinkWrap: true, + controller: controller, + children: [ + if (item != null) ...{ + ItemBottomSheetPreview(item: item), + const Divider(), + }, + content(context, controller), + ], + ); + }, + ); + onDismiss?.call(); +} + +class ItemBottomSheetPreview extends ConsumerWidget { + final ItemBaseModel item; + const ItemBottomSheetPreview({required this.item, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: Row( + children: [ + Card( + child: SizedBox( + height: 90, + child: AspectRatio( + aspectRatio: 1, + child: FladderImage( + image: item.images?.primary, + fit: BoxFit.contain, + ), + ), + ), + ), + const SizedBox(width: 16), + Flexible( + child: Column( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + item.title, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.titleLarge, + ), + if (item.subText?.isNotEmpty ?? false) + Opacity( + opacity: 0.75, + child: Text( + item.subText!, + overflow: TextOverflow.ellipsis, + maxLines: 2, + style: Theme.of(context).textTheme.titleMedium, + ), + ), + ], + ), + ), + ], + ), + ), + ], + ); + } +} diff --git a/lib/widgets/shared/modal_side_sheet.dart b/lib/widgets/shared/modal_side_sheet.dart new file mode 100644 index 0000000..e51eb1f --- /dev/null +++ b/lib/widgets/shared/modal_side_sheet.dart @@ -0,0 +1,146 @@ +import 'package:flutter/material.dart'; + +Future showModalSideSheet( + BuildContext context, { + required Widget content, + Widget? header, + bool barrierDismissible = true, + bool backButton = false, + bool closeButton = false, + bool addDivider = true, + List? actions, + Function()? onDismiss, + Duration? transitionDuration, +}) async { + await showGeneralDialog( + context: context, + transitionDuration: transitionDuration ?? const Duration(milliseconds: 200), + barrierDismissible: barrierDismissible, + barrierColor: Theme.of(context).colorScheme.scrim.withOpacity(0.3), + barrierLabel: 'Material 3 side sheet', + useRootNavigator: false, + transitionBuilder: (context, animation, secondaryAnimation, child) { + return SlideTransition( + position: Tween(begin: const Offset(1, 0), end: const Offset(0, 0)).animate( + animation, + ), + child: child, + ); + }, + pageBuilder: (context, animation1, animation2) { + return Align( + alignment: Alignment.centerRight, + child: Sheet( + header: header, + backButton: backButton, + closeButton: closeButton, + actions: actions, + content: content, + addDivider: addDivider, + ), + ); + }, + ); + onDismiss?.call(); +} + +class Sheet extends StatelessWidget { + final Widget? header; + final bool backButton; + final bool closeButton; + final Widget content; + final bool addDivider; + final List? actions; + + const Sheet({ + super.key, + this.header, + required this.backButton, + required this.closeButton, + required this.content, + required this.addDivider, + this.actions, + }); + + @override + Widget build(BuildContext context) { + final size = MediaQuery.of(context).size; + final theme = Theme.of(context); + final colorScheme = theme.colorScheme; + + return Material( + elevation: 1, + color: colorScheme.surface, + surfaceTintColor: colorScheme.onSurface, + borderRadius: const BorderRadius.horizontal(left: Radius.circular(20)), + child: Padding( + padding: MediaQuery.of(context).padding, + child: Container( + constraints: BoxConstraints( + minWidth: 256, + maxWidth: size.width <= 600 ? size.width : 400, + minHeight: size.height, + maxHeight: size.height, + ), + child: Column( + children: [ + _buildHeader(context), + Expanded( + child: content, + ), + if (actions?.isNotEmpty ?? false) _buildFooter(context) + ], + ), + ), + ), + ); + } + + Widget _buildHeader(BuildContext context) { + return Padding( + padding: const EdgeInsets.fromLTRB(24, 16, 16, 16), + child: Row( + children: [ + Visibility( + visible: backButton, + child: const BackButton(), + ), + if (header != null) + Material( + textStyle: Theme.of(context) + .textTheme + .titleLarge + ?.copyWith(color: Theme.of(context).colorScheme.onSurfaceVariant), + color: Colors.transparent, + child: header!, + ), + const Spacer(), + Visibility( + visible: closeButton, + child: const CloseButton(), + ), + ], + ), + ); + } + + Widget _buildFooter(BuildContext context) { + return Column( + children: [ + Visibility( + visible: addDivider, + child: const Divider( + indent: 24, + endIndent: 24, + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(24.0, 16, 24, 24), + child: Row( + children: actions ?? [], + ), + ), + ], + ); + } +} diff --git a/lib/widgets/shared/pinch_poster_zoom.dart b/lib/widgets/shared/pinch_poster_zoom.dart new file mode 100644 index 0000000..31f8c8d --- /dev/null +++ b/lib/widgets/shared/pinch_poster_zoom.dart @@ -0,0 +1,33 @@ +import 'package:fladder/providers/settings/client_settings_provider.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class PinchPosterZoom extends ConsumerStatefulWidget { + final Widget child; + final Function(double difference)? scaleDifference; + const PinchPosterZoom({required this.child, this.scaleDifference, super.key}); + + @override + ConsumerState createState() => _PinchPosterZoomState(); +} + +class _PinchPosterZoomState extends ConsumerState { + double lastScale = 1.0; + + @override + Widget build(BuildContext context) { + return GestureDetector( + onScaleStart: (details) { + lastScale = 1; + }, + onScaleUpdate: (details) { + final difference = details.scale - lastScale; + if (ref.watch(clientSettingsProvider.select((value) => value.pinchPosterZoom))) { + widget.scaleDifference?.call(difference); + } + lastScale = details.scale; + }, + child: widget.child, + ); + } +} diff --git a/lib/widgets/shared/poster_size_slider.dart b/lib/widgets/shared/poster_size_slider.dart new file mode 100644 index 0000000..89c5739 --- /dev/null +++ b/lib/widgets/shared/poster_size_slider.dart @@ -0,0 +1,43 @@ +import 'package:fladder/providers/settings/client_settings_provider.dart'; +import 'package:fladder/widgets/shared/fladder_slider.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class PosterSizeWidget extends ConsumerWidget { + final Color? iconColor; + final double width; + const PosterSizeWidget({this.width = 150, this.iconColor, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + if (ref.watch(clientSettingsProvider.select((value) => value.pinchPosterZoom))) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + Tooltip( + message: 'Set poster size', + child: IconButton( + onPressed: () => + ref.read(clientSettingsProvider.notifier).update((current) => current.copyWith(posterSize: 1)), + icon: Icon(Icons.photo_size_select_large_rounded), + color: iconColor ?? Theme.of(context).colorScheme.onSurface, + ), + ), + SizedBox( + width: width, + child: FladderSlider( + value: ref.watch(clientSettingsProvider.select((value) => value.posterSize)), + min: 0.5, + divisions: 12, + max: 1.5, + onChanged: (value) => + ref.read(clientSettingsProvider.notifier).update((current) => current.copyWith(posterSize: value)), + ), + ), + ], + ); + } else { + return Container(); + } + } +} diff --git a/lib/widgets/shared/progress_floating_button.dart b/lib/widgets/shared/progress_floating_button.dart new file mode 100644 index 0000000..168899f --- /dev/null +++ b/lib/widgets/shared/progress_floating_button.dart @@ -0,0 +1,181 @@ +import 'dart:async'; + +import 'package:async/async.dart'; +import 'package:ficonsax/ficonsax.dart'; +import 'package:fladder/providers/settings/photo_view_settings_provider.dart'; +import 'package:fladder/util/simple_duration_picker.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:square_progress_indicator/square_progress_indicator.dart'; + +class RestarableTimerController { + late Duration _steps = const Duration(milliseconds: 32); + RestartableTimer? _timer; + late Duration _duration = const Duration(seconds: 1); + late Function() _onTimeout; + + late Duration _timeLeft = _duration; + set setTimeLeft(Duration value) { + _timeLeftController.add(value); + _timeLeft = value; + } + + final StreamController _timeLeftController = StreamController.broadcast(); + final StreamController _isActiveController = StreamController.broadcast(); + + RestarableTimerController(Duration duration, Duration steps, Function() onTimeout) { + _steps = steps; + _duration = duration; + _onTimeout = onTimeout; + } + + void playPause() { + if (_timer?.isActive == true) { + cancel(); + } else { + play(); + } + } + + void play() { + _timer?.cancel(); + _timer = _startTimer(); + _isActiveController.add(_timer?.isActive ?? true); + } + + RestartableTimer _startTimer() { + return RestartableTimer( + _steps, + () { + if (_timeLeft < _steps) { + setTimeLeft = _duration; + _onTimeout.call(); + } else { + setTimeLeft = _timeLeft - _steps; + } + _timer?.reset(); + }, + ); + } + + bool get timerIsActive => _timer?.isActive ?? false; + + Stream get isActive => _isActiveController.stream; + + Stream get timeLeft => _timeLeftController.stream; + + void setDuration(Duration value) => { + _duration = value, + }; + + void cancel() { + _timer?.cancel(); + _timer = null; + _isActiveController.add(false); + } + + void reset() { + setTimeLeft = _duration; + _timer?.reset(); + } + + void dispose() => _timer?.cancel(); +} + +class ProgressFloatingButton extends ConsumerStatefulWidget { + final RestarableTimerController? controller; + final Function()? onTimeOut; + const ProgressFloatingButton({this.controller, this.onTimeOut, super.key}); + + @override + ConsumerState createState() => _ProgressFloatingButtonState(); +} + +class _ProgressFloatingButtonState extends ConsumerState { + late RestarableTimerController timer; + late Duration timeLeft = timer._duration; + late bool isActive = false; + + List subscriptions = []; + + @override + void initState() { + super.initState(); + timer = widget.controller ?? + RestarableTimerController( + const Duration(seconds: 1), + const Duration(milliseconds: 32), + widget.onTimeOut ?? () {}, + ); + subscriptions.addAll([ + timer.timeLeft.listen((event) => setState(() => timeLeft = event)), + timer.isActive.listen((event) => setState(() => isActive = event)) + ]); + } + + @override + void dispose() { + timer.cancel(); + for (var element in subscriptions) { + element.cancel(); + } + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onDoubleTap: () { + HapticFeedback.vibrate(); + setState(() { + timer.reset(); + }); + }, + onLongPress: () async { + HapticFeedback.vibrate(); + final newTimer = + await showSimpleDurationPicker(context: context, initialValue: timer._duration, showNever: false); + if (newTimer != null) { + setState(() { + ref.read(photoViewSettingsProvider.notifier).update((state) => state.copyWith(timer: newTimer)); + timer.setDuration(newTimer); + }); + } + }, + child: FloatingActionButton( + onPressed: isActive ? timer.cancel : timer.play, + child: Stack( + fit: StackFit.expand, + alignment: Alignment.center, + children: [ + SquareProgressIndicator( + color: Theme.of(context).colorScheme.onSecondaryContainer, + borderRadius: 6, + strokeWidth: 4, + value: timeLeft.inMilliseconds / timer._duration.inMilliseconds, + ), + Icon(isActive ? IconsaxBold.pause : IconsaxBold.play) + ], + ), + ), + ); + } +} + +class CustomTrackShape extends RoundedRectSliderTrackShape { + @override + Rect getPreferredRect({ + required RenderBox parentBox, + Offset offset = Offset.zero, + required SliderThemeData sliderTheme, + bool isEnabled = false, + bool isDiscrete = false, + }) { + final trackHeight = sliderTheme.trackHeight; + final trackLeft = offset.dx; + final trackTop = offset.dy + (parentBox.size.height - trackHeight!) / 2; + final trackWidth = parentBox.size.width; + return Rect.fromLTWH(trackLeft, trackTop, trackWidth, trackHeight); + } +} diff --git a/lib/widgets/shared/pull_to_refresh.dart b/lib/widgets/shared/pull_to_refresh.dart new file mode 100644 index 0000000..3d6a17b --- /dev/null +++ b/lib/widgets/shared/pull_to_refresh.dart @@ -0,0 +1,83 @@ +import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/refresh_state.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class PullToRefresh extends ConsumerStatefulWidget { + final GlobalKey? refreshKey; + final double? displacement; + final bool refreshOnStart; + final bool autoFocus; + final bool contextRefresh; + final Future Function()? onRefresh; + final Widget child; + const PullToRefresh({ + required this.child, + this.displacement, + this.autoFocus = true, + this.refreshOnStart = true, + this.contextRefresh = true, + required this.onRefresh, + this.refreshKey, + super.key, + }); + + @override + ConsumerState createState() => _PullToRefreshState(); +} + +class _PullToRefreshState extends ConsumerState { + final GlobalKey _refreshIndicatorKey = GlobalKey(); + final FocusNode focusNode = FocusNode(); + + GlobalKey get refreshKey { + return (widget.refreshKey ?? _refreshIndicatorKey); + } + + @override + void initState() { + super.initState(); + if (widget.refreshOnStart) { + Future.microtask( + () => refreshKey.currentState?.show(), + ); + } + } + + @override + Widget build(BuildContext context) { + if ((AdaptiveLayout.of(context).isDesktop || kIsWeb) && widget.autoFocus) { + focusNode.requestFocus(); + } + return RefreshState( + refreshKey: refreshKey, + refreshAble: widget.contextRefresh, + child: Focus( + focusNode: focusNode, + autofocus: true, + onKeyEvent: (node, event) { + if (event is KeyDownEvent) { + if (event.logicalKey == LogicalKeyboardKey.f5) { + refreshKey.currentState?.show(); + return KeyEventResult.handled; + } + return KeyEventResult.ignored; + } + return KeyEventResult.ignored; + }, + child: widget.onRefresh != null + ? RefreshIndicator.adaptive( + displacement: widget.displacement ?? 80 + MediaQuery.of(context).viewPadding.top, + key: refreshKey, + onRefresh: widget.onRefresh!, + color: Theme.of(context).colorScheme.onPrimaryContainer, + backgroundColor: Theme.of(context).colorScheme.primaryContainer, + child: widget.child, + ) + : widget.child, + ), + ); + } +} diff --git a/lib/widgets/shared/scroll_position.dart b/lib/widgets/shared/scroll_position.dart new file mode 100644 index 0000000..fb3bc6d --- /dev/null +++ b/lib/widgets/shared/scroll_position.dart @@ -0,0 +1,66 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +enum ScrollState { + top, + middle, + bottom, +} + +class ScrollStatePosition extends ConsumerStatefulWidget { + final ScrollController? controller; + final Widget Function(ScrollState state) positionBuilder; + + const ScrollStatePosition({ + this.controller, + required this.positionBuilder, + super.key, + }); + + @override + ConsumerState createState() => _ScrollStatePositionState(); +} + +class _ScrollStatePositionState extends ConsumerState { + late final scrollController = widget.controller ?? ScrollController(); + ScrollState scrollState = ScrollState.top; + + @override + void initState() { + super.initState(); + scrollController.addListener(listen); + } + + @override + void dispose() { + scrollController.removeListener(listen); + super.dispose(); + } + + void listen() { + if (scrollController.offset < scrollController.position.maxScrollExtent) { + if (scrollController.position.atEdge) { + bool isTop = scrollController.position.pixels == 0; + if (isTop) { + setState(() { + scrollState = ScrollState.top; + }); + print('At the top'); + } else { + setState(() { + scrollState = ScrollState.bottom; + }); + } + } else { + setState(() { + scrollState = ScrollState.middle; + }); + } + } + } + + @override + Widget build(BuildContext context) { + return widget.positionBuilder(scrollState); + } +} diff --git a/lib/widgets/shared/selectable_icon_button.dart b/lib/widgets/shared/selectable_icon_button.dart new file mode 100644 index 0000000..63036a3 --- /dev/null +++ b/lib/widgets/shared/selectable_icon_button.dart @@ -0,0 +1,103 @@ +import 'dart:async'; +import 'dart:developer'; + +import 'package:fladder/screens/shared/animated_fade_size.dart'; +import 'package:fladder/util/refresh_state.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class SelectableIconButton extends ConsumerStatefulWidget { + final FutureOr Function() onPressed; + final String? label; + final IconData icon; + final IconData? selectedIcon; + final bool selected; + const SelectableIconButton({ + required this.onPressed, + required this.selected, + required this.icon, + this.selectedIcon, + this.label, + super.key, + }); + + @override + ConsumerState createState() => _SelectableIconButtonState(); +} + +class _SelectableIconButtonState extends ConsumerState { + bool loading = false; + @override + Widget build(BuildContext context) { + const duration = Duration(milliseconds: 250); + const iconSize = 24.0; + return Tooltip( + message: widget.label ?? "", + child: ElevatedButton( + style: ButtonStyle( + backgroundColor: widget.selected ? WidgetStatePropertyAll(Theme.of(context).colorScheme.primary) : null, + foregroundColor: widget.selected ? WidgetStatePropertyAll(Theme.of(context).colorScheme.onPrimary) : null, + padding: const WidgetStatePropertyAll(EdgeInsets.zero), + ), + onPressed: loading + ? null + : () async { + setState(() => loading = true); + try { + await widget.onPressed(); + if (context.mounted) await context.refreshData(); + } catch (e) { + log(e.toString()); + } finally { + setState(() => loading = false); + } + }, + child: Padding( + padding: EdgeInsets.symmetric(vertical: 10, horizontal: widget.label != null ? 18 : 0), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (widget.label != null) ...{ + Text( + widget.label.toString(), + ), + const SizedBox(width: 10), + }, + AnimatedFadeSize( + duration: duration, + child: loading + ? Opacity( + opacity: 0.75, + child: SizedBox( + width: iconSize, + height: iconSize, + child: CircularProgressIndicator( + strokeCap: StrokeCap.round, + color: widget.selected + ? Theme.of(context).colorScheme.onPrimary + : Theme.of(context).colorScheme.primary, + ), + ), + ) + : !widget.selected + ? Opacity( + opacity: 0.65, + child: Icon( + key: const Key("selected-off"), + widget.icon, + size: iconSize, + ), + ) + : Icon( + key: const Key("selected-on"), + widget.selectedIcon, + size: iconSize, + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/widgets/shared/shapes.dart b/lib/widgets/shared/shapes.dart new file mode 100644 index 0000000..8020260 --- /dev/null +++ b/lib/widgets/shared/shapes.dart @@ -0,0 +1,65 @@ +import 'package:flutter/material.dart'; + +class AppBarShape extends OutlinedBorder { + @override + OutlinedBorder copyWith({BorderSide? side}) => this; //todo + + @override + Path getInnerPath(Rect rect, {TextDirection? textDirection}) { + Path path = Path() + ..fillType = PathFillType.evenOdd + ..addRect(rect) + ..addRRect(RRect.fromRectAndCorners( + Rect.fromLTWH(rect.left, rect.bottom - 14, rect.width, 14), + topLeft: Radius.circular(14), + topRight: Radius.circular(14), + )); + return path; + } + + @override + Path getOuterPath(Rect rect, {TextDirection? textDirection}) { + return getInnerPath(rect, textDirection: textDirection); + } + + @override + void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) { + /// create shader linear gradient + canvas.drawPath(getInnerPath(rect), Paint()..color = Colors.transparent); + } + + @override + ShapeBorder scale(double t) => this; +} + +class BottomBarShape extends OutlinedBorder { + @override + OutlinedBorder copyWith({BorderSide? side}) => this; //todo + + @override + Path getInnerPath(Rect rect, {TextDirection? textDirection}) { + Path path = Path() + ..fillType = PathFillType.evenOdd + ..addRect(rect) + ..addRRect(RRect.fromRectAndCorners( + Rect.fromLTWH(rect.left, rect.top, rect.width, 14), + bottomLeft: Radius.circular(14), + bottomRight: Radius.circular(14), + )); + return path; + } + + @override + Path getOuterPath(Rect rect, {TextDirection? textDirection}) { + return getInnerPath(rect, textDirection: textDirection); + } + + @override + void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) { + /// create shader linear gradient + canvas.drawPath(getInnerPath(rect), Paint()..color = Colors.transparent); + } + + @override + ShapeBorder scale(double t) => this; +} diff --git a/lib/widgets/shared/spaced_list_tile.dart b/lib/widgets/shared/spaced_list_tile.dart new file mode 100644 index 0000000..7396888 --- /dev/null +++ b/lib/widgets/shared/spaced_list_tile.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; + +class SpacedListTile extends StatelessWidget { + final Widget title; + final Widget? content; + final Function()? onTap; + const SpacedListTile({required this.title, this.content, this.onTap, super.key}); + + @override + Widget build(BuildContext context) { + return ListTile( + title: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible(flex: 1, child: title), + if (content != null) + Flexible( + flex: 1, + child: content!, + ), + ], + ), + onTap: onTap, + ); + } +} diff --git a/lib/widgets/shared/status_card.dart b/lib/widgets/shared/status_card.dart new file mode 100644 index 0000000..4d4d528 --- /dev/null +++ b/lib/widgets/shared/status_card.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class StatusCard extends ConsumerWidget { + final Color? color; + final Widget child; + + const StatusCard({this.color, required this.child, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Padding( + padding: EdgeInsets.all(5), + child: SizedBox( + width: 33, + height: 33, + child: Card( + elevation: 10, + surfaceTintColor: color, + shadowColor: color != null ? Colors.transparent : null, + child: IconTheme( + data: IconThemeData( + color: color, + ), + child: Center(child: child), + ), + ), + ), + ); + } +} diff --git a/lib/widgets/shared/trickplay_image.dart b/lib/widgets/shared/trickplay_image.dart new file mode 100644 index 0000000..f223e90 --- /dev/null +++ b/lib/widgets/shared/trickplay_image.dart @@ -0,0 +1,126 @@ +import 'dart:async'; +import 'dart:io'; +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:http/http.dart' as http; + +import 'package:fladder/models/items/trick_play_model.dart'; + +class TrickplayImage extends ConsumerStatefulWidget { + final TrickPlayModel trickplay; + final Duration? position; + + const TrickplayImage(this.trickplay, {this.position, super.key}); + + @override + ConsumerState createState() => _TrickplayImageState(); +} + +class _TrickplayImageState extends ConsumerState { + ui.Image? image; + late TrickPlayModel model = widget.trickplay; + late Duration time = widget.position ?? Duration.zero; + late Offset currentOffset = Offset(0, 0); + String? currentUrl; + + @override + void initState() { + super.initState(); + loadImage(); + } + + @override + void didUpdateWidget(covariant TrickplayImage oldWidget) { + if (oldWidget.position?.inMilliseconds != widget.position?.inMilliseconds) { + time = widget.position ?? Duration.zero; + model = widget.trickplay; + loadImage(); + } + super.didUpdateWidget(oldWidget); + } + + @override + Widget build(BuildContext context) { + return Container( + child: image != null + ? CustomPaint( + painter: TilledPainter(image!, currentOffset, widget.trickplay), + ) + : Container( + color: Colors.purple, + ), + ); + } + + Future loadImage() async { + if (model.images.isEmpty) return; + final newUrl = model.getTile(time); + currentOffset = model.offset(time); + if (newUrl != currentUrl) { + currentUrl = newUrl; + final tempUrl = currentUrl; + if (tempUrl == null) return; + if (tempUrl.startsWith('http')) { + await loadNetworkImage(tempUrl); + } else { + await loadFileImage(tempUrl); + } + } + } + + Future loadNetworkImage(String url) async { + final http.Response response = await http.get(Uri.parse(url)); + if (response.statusCode == 200) { + final Uint8List bytes = response.bodyBytes; + final ui.Codec codec = await ui.instantiateImageCodec(bytes); + final ui.FrameInfo frameInfo = await codec.getNextFrame(); + setState(() { + image = frameInfo.image; + }); + } else { + throw Exception('Failed to load network image'); + } + } + + Future loadFileImage(String path) async { + final Uint8List bytes = await File(path).readAsBytes(); + final ui.Codec codec = await ui.instantiateImageCodec(bytes); + final ui.FrameInfo frameInfo = await codec.getNextFrame(); + setState(() { + image = frameInfo.image; + }); + } +} + +class TilledPainter extends CustomPainter { + final ui.Image image; + final Offset offset; + final TrickPlayModel model; + + TilledPainter(this.image, this.offset, this.model); + + @override + void paint(Canvas canvas, Size size) { + // Define the source rectangle from the image + Rect srcRect = Rect.fromLTWH( + offset.dx, + offset.dy, + model.width.toDouble(), + model.height.toDouble(), + ); // Adjust these values to control the part of the image to display + + // Define the destination rectangle on the canvas + Rect dstRect = Rect.fromLTWH(0, 0, size.width, size.height); + + // Draw the image part onto the canvas + canvas.drawImageRect(image, srcRect, dstRect, Paint()); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return false; + } +} diff --git a/lib/wrappers/media_control_base.dart b/lib/wrappers/media_control_base.dart new file mode 100644 index 0000000..51a54c7 --- /dev/null +++ b/lib/wrappers/media_control_base.dart @@ -0,0 +1,64 @@ +import 'package:audio_service/audio_service.dart'; +import 'package:media_kit/media_kit.dart'; + +get audioServiceConfig => AudioServiceConfig( + androidNotificationChannelId: 'nl.jknaapen.fladder.channel.playback', + androidNotificationChannelName: 'Video playback', + androidNotificationOngoing: true, + androidStopForegroundOnPause: true, + // androidNotificationIcon: "mipmap/ic_notification_icon", + rewindInterval: Duration(seconds: 10), + fastForwardInterval: Duration(seconds: 15), + androidNotificationChannelDescription: "Playback", + androidShowNotificationBadge: true, + ); + +abstract class MediaControlBase { + Future init() { + throw UnimplementedError(); + } + + Player setup() { + throw UnimplementedError(); + } + + Future seek(Duration position) { + throw UnimplementedError(); + } + + Future play() { + throw UnimplementedError(); + } + + Future fastForward() { + throw UnimplementedError(); + } + + Future rewind() { + throw UnimplementedError(); + } + + Future setSpeed(double speed) { + throw UnimplementedError(); + } + + Future pause() { + throw UnimplementedError(); + } + + Future stop() { + throw UnimplementedError(); + } + + void playOrPause() { + throw UnimplementedError(); + } + + Future setSubtitleTrack(SubtitleTrack subtitleTrack) { + throw UnimplementedError(); + } + + Future setAudioTrack(AudioTrack subtitleTrack) { + throw UnimplementedError(); + } +} diff --git a/lib/wrappers/media_control_wrapper.dart b/lib/wrappers/media_control_wrapper.dart new file mode 100644 index 0000000..bc8bde2 --- /dev/null +++ b/lib/wrappers/media_control_wrapper.dart @@ -0,0 +1,241 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:audio_service/audio_service.dart'; +import 'package:collection/collection.dart'; +import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/providers/settings/client_settings_provider.dart'; +import 'package:fladder/providers/settings/video_player_settings_provider.dart'; +import 'package:fladder/providers/video_player_provider.dart'; +import 'package:fladder/wrappers/media_control_base.dart'; +import 'package:fladder/wrappers/media_wrapper_interface.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:media_kit/media_kit.dart'; +import 'package:media_kit_video/media_kit_video.dart'; +import 'package:smtc_windows/smtc_windows.dart'; +import 'package:wakelock_plus/wakelock_plus.dart'; + +class MediaControlsWrapper extends MediaPlayback implements MediaControlBase { + MediaControlsWrapper({required this.ref}); + + final Ref ref; + + List subscriptions = []; + SMTCWindows? smtc; + + @override + Future init() async { + await AudioService.init( + builder: () => this, + config: audioServiceConfig, + ); + } + + @override + Player setup() => setPlayer(_initPlayer()); + + Player _initPlayer() { + for (var element in subscriptions) { + element.cancel(); + } + + stop(); + + player?.dispose(); + + final newPlayer = Player( + configuration: PlayerConfiguration( + bufferSize: 64 * 1024 * 1024, + libassAndroidFont: 'assets/fonts/mp-font.ttf', + libass: !kIsWeb && + ref.read( + videoPlayerSettingsProvider.select((value) => value.useLibass), + ), + ), + ); + setPlayer(newPlayer); + setController(VideoController( + newPlayer, + configuration: VideoControllerConfiguration( + enableHardwareAcceleration: ref.read( + videoPlayerSettingsProvider.select((value) => value.hardwareAccel), + ), + ), + )); + _subscribePlayer(); + return newPlayer; + } + + void _subscribePlayer() { + if (Platform.isWindows) { + smtc = SMTCWindows( + config: const SMTCConfig( + fastForwardEnabled: true, + nextEnabled: false, + pauseEnabled: true, + playEnabled: true, + rewindEnabled: true, + prevEnabled: false, + stopEnabled: true, + ), + ); + + if (smtc != null) { + subscriptions.add( + smtc!.buttonPressStream.listen((event) { + switch (event) { + case PressedButton.play: + play(); + break; + case PressedButton.pause: + pause(); + break; + case PressedButton.fastForward: + fastForward(); + break; + case PressedButton.rewind: + rewind(); + break; + case PressedButton.previous: + break; + case PressedButton.stop: + stop(); + break; + default: + break; + } + }), + ); + } + } + + subscriptions.addAll([ + player?.stream.buffer.listen((buffer) { + playbackState.add(playbackState.value.copyWith( + bufferedPosition: buffer, + )); + }), + player?.stream.buffering.listen((buffering) { + playbackState.add(playbackState.value.copyWith( + processingState: buffering ? AudioProcessingState.buffering : AudioProcessingState.ready, + )); + }), + player?.stream.position.listen((position) { + playbackState.add(playbackState.value.copyWith( + updatePosition: position, + )); + smtc?.setPosition(position); + }), + player?.stream.playing.listen((playing) { + if (playing) { + WakelockPlus.enable(); + } else { + WakelockPlus.disable(); + } + playbackState.add(playbackState.value.copyWith( + playing: playing, + )); + smtc?.setPlaybackStatus(playing ? PlaybackStatus.Playing : PlaybackStatus.Paused); + }), + ].whereNotNull()); + } + + @override + Future play() async { + if (!ref.read(clientSettingsProvider).enableMediaKeys) { + await player?.play(); + return super.play(); + } + + final playBackItem = ref.read(playBackModel.select((value) => value?.item)); + final currentPosition = await ref.read(playBackModel.select((value) => value?.startDuration())); + final poster = playBackItem?.images?.firstOrNull; + + if (playBackItem == null) return; + + windowSMTCSetup(playBackItem, currentPosition ?? Duration.zero); + + //Everything else setup + mediaItem.add(MediaItem( + id: playBackItem.id, + title: playBackItem.title, + rating: Rating.newHeartRating(playBackItem.userData.isFavourite), + duration: playBackItem.overview.runTime ?? const Duration(seconds: 0), + artUri: poster != null ? Uri.parse(poster.path) : null, + )); + playbackState.add(PlaybackState( + playing: true, + controls: [ + MediaControl.pause, + MediaControl.stop, + ], + systemActions: const { + MediaAction.seek, + MediaAction.fastForward, + MediaAction.setSpeed, + MediaAction.rewind, + }, + processingState: AudioProcessingState.ready, + )); + + await player?.play(); + return super.play(); + } + + Future windowSMTCSetup(ItemBaseModel playBackItem, Duration currentPosition) async { + final poster = playBackItem.images?.firstOrNull; + + //Windows setup + smtc?.updateMetadata(MusicMetadata( + title: playBackItem.title, + thumbnail: poster?.path, + )); + smtc?.updateTimeline( + PlaybackTimeline( + startTimeMs: currentPosition.inMilliseconds, + endTimeMs: (playBackItem.overview.runTime ?? const Duration(seconds: 0)).inMilliseconds, + positionMs: 0, + minSeekTimeMs: 0, + maxSeekTimeMs: (playBackItem.overview.runTime ?? const Duration(seconds: 0)).inMilliseconds, + ), + ); + + smtc?.enableSmtc(); + smtc?.setPlaybackStatus(PlaybackStatus.Playing); + } + + @override + Future stop() async { + WakelockPlus.disable(); + final position = player?.state.position; + final totalDuration = player?.state.duration; + await player?.stop(); + ref.read(playBackModel)?.playbackStopped(position ?? Duration.zero, totalDuration, ref); + ref.read(mediaPlaybackProvider.notifier).update((state) => state.copyWith(position: Duration.zero)); + smtc?.setPlaybackStatus(PlaybackStatus.Stopped); + smtc?.clearMetadata(); + smtc?.disableSmtc(); + playbackState.add( + playbackState.value.copyWith( + playing: false, + processingState: AudioProcessingState.completed, + controls: [], + ), + ); + return super.stop(); + } + + @override + void playOrPause() async { + await player?.playOrPause(); + playbackState.add(playbackState.value.copyWith( + playing: player?.state.playing ?? false, + controls: [MediaControl.play], + )); + final playerState = player; + if (playerState != null) { + ref.read(playBackModel)?.updatePlaybackPosition(playerState.state.position, playerState.state.playing, ref); + } + } +} diff --git a/lib/wrappers/media_control_wrapper_web.dart b/lib/wrappers/media_control_wrapper_web.dart new file mode 100644 index 0000000..5ea46e5 --- /dev/null +++ b/lib/wrappers/media_control_wrapper_web.dart @@ -0,0 +1,169 @@ +import 'dart:async'; + +import 'package:audio_service/audio_service.dart'; +import 'package:collection/collection.dart'; +import 'package:fladder/providers/settings/client_settings_provider.dart'; +import 'package:fladder/providers/settings/video_player_settings_provider.dart'; +import 'package:fladder/providers/video_player_provider.dart'; +import 'package:fladder/wrappers/media_control_base.dart'; +import 'package:fladder/wrappers/media_wrapper_interface.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:media_kit/media_kit.dart'; +import 'package:media_kit_video/media_kit_video.dart'; +import 'package:wakelock_plus/wakelock_plus.dart'; + +class MediaControlsWrapper extends MediaPlayback implements MediaControlBase { + MediaControlsWrapper({required this.ref}); + + final Ref ref; + + List subscriptions = []; + + @override + Future init() async { + await AudioService.init( + builder: () => this, + config: audioServiceConfig, + ); + } + + @override + Player setup() => setPlayer(_initPlayer()); + + Player _initPlayer() { + for (var element in subscriptions) { + element.cancel(); + } + + stop(); + + player?.dispose(); + + final newPlayer = Player( + configuration: PlayerConfiguration( + bufferSize: 64 * 1024 * 1024, + libassAndroidFont: 'assets/fonts/mp-font.ttf', + libass: ref.read( + videoPlayerSettingsProvider.select((value) => value.useLibass), + ), + ), + ); + setPlayer(newPlayer); + setController(VideoController( + newPlayer, + configuration: VideoControllerConfiguration( + enableHardwareAcceleration: ref.read( + videoPlayerSettingsProvider.select((value) => value.hardwareAccel), + ), + ), + )); + _subscribePlayer(); + return newPlayer; + } + + Future _subscribePlayer() async { + subscriptions.addAll([ + player?.stream.buffer.listen((buffer) { + playbackState.add(playbackState.value.copyWith( + bufferedPosition: buffer, + )); + }), + player?.stream.buffering.listen((buffering) { + playbackState.add(playbackState.value.copyWith( + processingState: buffering ? AudioProcessingState.buffering : AudioProcessingState.ready, + )); + }), + player?.stream.position.listen((position) { + playbackState.add(playbackState.value.copyWith( + updatePosition: position, + )); + }), + player?.stream.playing.listen((playing) { + playbackState.add(playbackState.value.copyWith( + playing: playing, + )); + }), + ].whereNotNull()); + } + + @override + Future seek(Duration position) async => player?.seek(position); + + @override + Future play() async { + if (!ref.read(clientSettingsProvider).enableMediaKeys) { + await player?.play(); + return super.play(); + } + + final playBackItem = ref.read(playBackModel.select((value) => value?.item)); + if (playBackItem == null) return; + + final poster = playBackItem.images?.firstOrNull; + + //Everything else setup + mediaItem.add(MediaItem( + id: playBackItem.id, + title: playBackItem.title, + artist: playBackItem.subText, + rating: Rating.newHeartRating(playBackItem.userData.isFavourite), + duration: playBackItem.overview.runTime ?? const Duration(seconds: 0), + artUri: poster != null ? Uri.parse(poster.path) : null, + )); + playbackState.add(playbackState.value.copyWith( + playing: true, + controls: [ + MediaControl.pause, + MediaControl.stop, + ], + systemActions: const { + MediaAction.seek, + MediaAction.fastForward, + MediaAction.setSpeed, + MediaAction.rewind, + }, + processingState: AudioProcessingState.ready, + )); + + await player?.play(); + return super.play(); + } + + @override + Future pause() async { + playbackState.add(playbackState.value.copyWith( + playing: false, + controls: [MediaControl.play], + )); + await player?.pause(); + return super.pause(); + } + + @override + Future stop() async { + WakelockPlus.disable(); + final position = player?.state.position; + final totalDuration = player?.state.duration; + await player?.stop(); + ref.read(playBackModel)?.playbackStopped(position ?? Duration.zero, totalDuration, ref); + ref.read(mediaPlaybackProvider.notifier).update((state) => state.copyWith(position: Duration.zero)); + + playbackState.add( + playbackState.value.copyWith( + playing: false, + processingState: AudioProcessingState.completed, + controls: [], + ), + ); + return super.stop(); + } + + @override + void playOrPause() { + player?.playOrPause(); + playbackState.add(playbackState.value.copyWith( + playing: player?.state.playing ?? false, + controls: [MediaControl.play], + )); + } +} diff --git a/lib/wrappers/media_wrapper_interface.dart b/lib/wrappers/media_wrapper_interface.dart new file mode 100644 index 0000000..fd59c07 --- /dev/null +++ b/lib/wrappers/media_wrapper_interface.dart @@ -0,0 +1,71 @@ +import 'package:audio_service/audio_service.dart'; +import 'package:media_kit/media_kit.dart'; +import 'package:media_kit_video/media_kit_video.dart'; + +class MediaPlayback extends BaseAudioHandler { + Player? _player; + VideoController? _controller; + Player? get player => _player; + VideoController? get controller => _controller; + + Player setPlayer(Player player) => _player = player; + VideoController setController(VideoController player) => _controller = player; + + Future setVolume(double volume) async => _player?.setVolume(volume); + + Future setSubtitleTrack(SubtitleTrack track) async => _player?.setSubtitleTrack(track); + List get subTracks => _player?.state.tracks.subtitle ?? []; + SubtitleTrack get subtitleTrack => _player?.state.track.subtitle ?? SubtitleTrack.no(); + + Future setAudioTrack(AudioTrack track) async => _player?.setAudioTrack(track); + List get audioTracks => _player?.state.tracks.audio ?? []; + AudioTrack get audioTrack => _player?.state.track.audio ?? AudioTrack.no(); + + @override + Future seek(Duration position) async => player?.seek(position); + + @override + Future play() async { + await player?.play(); + return super.play(); + } + + Future open( + Playable playable, { + bool play = true, + }) async { + return player?.open(playable, play: play); + } + + @override + Future fastForward() async { + if (player != null) { + await player!.seek(player!.state.position + const Duration(seconds: 30)); + } + return super.fastForward(); + } + + @override + Future rewind() async { + if (player != null) { + await player?.seek(player!.state.position - const Duration(seconds: 10)); + } + return super.rewind(); + } + + @override + Future setSpeed(double speed) async { + await player?.setRate(speed); + return super.setSpeed(speed); + } + + @override + Future pause() async { + playbackState.add(playbackState.value.copyWith( + playing: false, + controls: [MediaControl.play], + )); + await player?.pause(); + return super.pause(); + } +} diff --git a/linux/.gitignore b/linux/.gitignore new file mode 100644 index 0000000..d3896c9 --- /dev/null +++ b/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt new file mode 100644 index 0000000..126b98b --- /dev/null +++ b/linux/CMakeLists.txt @@ -0,0 +1,138 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "Fladder") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.fladder") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Define the application target. To change its name, change BINARY_NAME above, +# not the value here, or `flutter run` will no longer work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/linux/flutter/CMakeLists.txt b/linux/flutter/CMakeLists.txt new file mode 100644 index 0000000..d5bd016 --- /dev/null +++ b/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000..a6f5cf6 --- /dev/null +++ b/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,43 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) desktop_drop_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopDropPlugin"); + desktop_drop_plugin_register_with_registrar(desktop_drop_registrar); + g_autoptr(FlPluginRegistrar) dynamic_color_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "DynamicColorPlugin"); + dynamic_color_plugin_register_with_registrar(dynamic_color_registrar); + g_autoptr(FlPluginRegistrar) isar_flutter_libs_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "IsarFlutterLibsPlugin"); + isar_flutter_libs_plugin_register_with_registrar(isar_flutter_libs_registrar); + g_autoptr(FlPluginRegistrar) media_kit_libs_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitLibsLinuxPlugin"); + media_kit_libs_linux_plugin_register_with_registrar(media_kit_libs_linux_registrar); + g_autoptr(FlPluginRegistrar) media_kit_video_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitVideoPlugin"); + media_kit_video_plugin_register_with_registrar(media_kit_video_registrar); + g_autoptr(FlPluginRegistrar) screen_retriever_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverPlugin"); + screen_retriever_plugin_register_with_registrar(screen_retriever_registrar); + g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); + url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); + g_autoptr(FlPluginRegistrar) window_manager_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "WindowManagerPlugin"); + window_manager_plugin_register_with_registrar(window_manager_registrar); +} diff --git a/linux/flutter/generated_plugin_registrant.h b/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000..e0f0a47 --- /dev/null +++ b/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake new file mode 100644 index 0000000..b16442a --- /dev/null +++ b/linux/flutter/generated_plugins.cmake @@ -0,0 +1,32 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + desktop_drop + dynamic_color + isar_flutter_libs + media_kit_libs_linux + media_kit_video + screen_retriever + url_launcher_linux + window_manager +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST + media_kit_native_event_loop +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/linux/main.cc b/linux/main.cc new file mode 100644 index 0000000..e7c5c54 --- /dev/null +++ b/linux/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/linux/my_application.cc b/linux/my_application.cc new file mode 100644 index 0000000..7f7c6c9 --- /dev/null +++ b/linux/my_application.cc @@ -0,0 +1,116 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication +{ + GtkApplication parent_instance; + char **dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication *application) +{ + MyApplication *self = MY_APPLICATION(application); + GtkWindow *window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen *screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) + { + const gchar *wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) + { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) + { + GtkHeaderBar *header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "fladder"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } + else + { + gtk_window_set_title(window, "fladder"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView *view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication *application, gchar ***arguments, int *exit_status) +{ + MyApplication *self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) + { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject *object) +{ + MyApplication *self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass *klass) +{ + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication *self) {} + +MyApplication *my_application_new() +{ + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/linux/my_application.h b/linux/my_application.h new file mode 100644 index 0000000..72271d5 --- /dev/null +++ b/linux/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/macos/.gitignore b/macos/.gitignore new file mode 100644 index 0000000..746adbb --- /dev/null +++ b/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/macos/Flutter/Flutter-Debug.xcconfig b/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 0000000..4b81f9b --- /dev/null +++ b/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/macos/Flutter/Flutter-Release.xcconfig b/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 0000000..5caa9d1 --- /dev/null +++ b/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 0000000..2538ce4 --- /dev/null +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,48 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import audio_service +import audio_session +import desktop_drop +import dynamic_color +import isar_flutter_libs +import just_audio +import media_kit_libs_macos_video +import media_kit_video +import package_info_plus +import path_provider_foundation +import screen_brightness_macos +import screen_retriever +import share_plus +import shared_preferences_foundation +import sqflite +import url_launcher_macos +import video_player_avfoundation +import wakelock_plus +import window_manager + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + AudioServicePlugin.register(with: registry.registrar(forPlugin: "AudioServicePlugin")) + AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin")) + DesktopDropPlugin.register(with: registry.registrar(forPlugin: "DesktopDropPlugin")) + DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin")) + IsarFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "IsarFlutterLibsPlugin")) + JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin")) + MediaKitLibsMacosVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosVideoPlugin")) + MediaKitVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitVideoPlugin")) + FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + ScreenBrightnessMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenBrightnessMacosPlugin")) + ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin")) + SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) + UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) + FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin")) + WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin")) + WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin")) +} diff --git a/macos/Podfile b/macos/Podfile new file mode 100644 index 0000000..c795730 --- /dev/null +++ b/macos/Podfile @@ -0,0 +1,43 @@ +platform :osx, '10.14' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/macos/Podfile.lock b/macos/Podfile.lock new file mode 100644 index 0000000..5d22e95 --- /dev/null +++ b/macos/Podfile.lock @@ -0,0 +1,123 @@ +PODS: + - audio_service (0.14.1): + - FlutterMacOS + - audio_session (0.0.1): + - FlutterMacOS + - dynamic_color (0.0.2): + - FlutterMacOS + - FlutterMacOS (1.0.0) + - FMDB (2.7.5): + - FMDB/standard (= 2.7.5) + - FMDB/standard (2.7.5) + - media_kit_libs_macos_video (1.0.4): + - FlutterMacOS + - media_kit_native_event_loop (1.0.0): + - FlutterMacOS + - media_kit_video (0.0.1): + - FlutterMacOS + - package_info_plus (0.0.1): + - FlutterMacOS + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - screen_brightness_macos (0.1.0): + - FlutterMacOS + - screen_retriever (0.0.1): + - FlutterMacOS + - share_plus (0.0.1): + - FlutterMacOS + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + - sqflite (0.0.2): + - FlutterMacOS + - FMDB (>= 2.7.5) + - url_launcher_macos (0.0.1): + - FlutterMacOS + - wakelock_plus (0.0.1): + - FlutterMacOS + - window_manager (0.2.0): + - FlutterMacOS + +DEPENDENCIES: + - audio_service (from `Flutter/ephemeral/.symlinks/plugins/audio_service/macos`) + - audio_session (from `Flutter/ephemeral/.symlinks/plugins/audio_session/macos`) + - dynamic_color (from `Flutter/ephemeral/.symlinks/plugins/dynamic_color/macos`) + - FlutterMacOS (from `Flutter/ephemeral`) + - media_kit_libs_macos_video (from `Flutter/ephemeral/.symlinks/plugins/media_kit_libs_macos_video/macos`) + - media_kit_native_event_loop (from `Flutter/ephemeral/.symlinks/plugins/media_kit_native_event_loop/macos`) + - media_kit_video (from `Flutter/ephemeral/.symlinks/plugins/media_kit_video/macos`) + - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) + - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) + - screen_brightness_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_brightness_macos/macos`) + - screen_retriever (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos`) + - share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`) + - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) + - sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/macos`) + - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) + - wakelock_plus (from `Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos`) + - window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`) + +SPEC REPOS: + trunk: + - FMDB + +EXTERNAL SOURCES: + audio_service: + :path: Flutter/ephemeral/.symlinks/plugins/audio_service/macos + audio_session: + :path: Flutter/ephemeral/.symlinks/plugins/audio_session/macos + dynamic_color: + :path: Flutter/ephemeral/.symlinks/plugins/dynamic_color/macos + FlutterMacOS: + :path: Flutter/ephemeral + media_kit_libs_macos_video: + :path: Flutter/ephemeral/.symlinks/plugins/media_kit_libs_macos_video/macos + media_kit_native_event_loop: + :path: Flutter/ephemeral/.symlinks/plugins/media_kit_native_event_loop/macos + media_kit_video: + :path: Flutter/ephemeral/.symlinks/plugins/media_kit_video/macos + package_info_plus: + :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos + path_provider_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin + screen_brightness_macos: + :path: Flutter/ephemeral/.symlinks/plugins/screen_brightness_macos/macos + screen_retriever: + :path: Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos + share_plus: + :path: Flutter/ephemeral/.symlinks/plugins/share_plus/macos + shared_preferences_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin + sqflite: + :path: Flutter/ephemeral/.symlinks/plugins/sqflite/macos + url_launcher_macos: + :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos + wakelock_plus: + :path: Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos + window_manager: + :path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos + +SPEC CHECKSUMS: + audio_service: b88ff778e0e3915efd4cd1a5ad6f0beef0c950a9 + audio_session: dea1f41890dbf1718f04a56f1d6150fd50039b72 + dynamic_color: 2eaa27267de1ca20d879fbd6e01259773fb1670f + FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 + FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a + media_kit_libs_macos_video: b3e2bbec2eef97c285f2b1baa7963c67c753fb82 + media_kit_native_event_loop: 81fd5b45192b72f8b5b69eaf5b540f45777eb8d5 + media_kit_video: c75b07f14d59706c775778e4dd47dd027de8d1e5 + package_info_plus: 02d7a575e80f194102bef286361c6c326e4c29ce + path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 + screen_brightness_macos: 2d6d3af2165592d9a55ffcd95b7550970e41ebda + screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38 + share_plus: 76dd39142738f7a68dd57b05093b5e8193f220f7 + shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126 + sqflite: a5789cceda41d54d23f31d6de539d65bb14100ea + url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95 + wakelock_plus: 4783562c9a43d209c458cb9b30692134af456269 + window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8 + +PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367 + +COCOAPODS: 1.12.1 diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..79a2897 --- /dev/null +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,791 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 5C533CBC420D85EEFDF3D7E6 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24ADB703336BF32A3B186030 /* Pods_RunnerTests.framework */; }; + 65282C83A95EB2A42957BF45 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E27FD4BD14A9CB9C1FF0CEB /* Pods_Runner.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 24ADB703336BF32A3B186030 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* fladder.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = fladder.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 5E27FD4BD14A9CB9C1FF0CEB /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 70CCCB1CEE4EC55B6EC92673 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + A06CB9A73D578A90F1832121 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + BC60ACA46139A237FC0D7796 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + BEF7E92DFCF099E5539E25E2 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + BFCBF943FD504359D4B2498A /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + CA4513CDAF0C75E2FCB2F5F4 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5C533CBC420D85EEFDF3D7E6 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 65282C83A95EB2A42957BF45 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + 9B380A9E9D054B2BBFB7FE5E /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* fladder.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + 9B380A9E9D054B2BBFB7FE5E /* Pods */ = { + isa = PBXGroup; + children = ( + A06CB9A73D578A90F1832121 /* Pods-Runner.debug.xcconfig */, + BFCBF943FD504359D4B2498A /* Pods-Runner.release.xcconfig */, + 70CCCB1CEE4EC55B6EC92673 /* Pods-Runner.profile.xcconfig */, + BEF7E92DFCF099E5539E25E2 /* Pods-RunnerTests.debug.xcconfig */, + BC60ACA46139A237FC0D7796 /* Pods-RunnerTests.release.xcconfig */, + CA4513CDAF0C75E2FCB2F5F4 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 5E27FD4BD14A9CB9C1FF0CEB /* Pods_Runner.framework */, + 24ADB703336BF32A3B186030 /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 29DB63AF8DC60A188C43CE2B /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + A10B438558BAD74F40FF0188 /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + D104E97D065823176A7C7D09 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* fladder.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1430; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 29DB63AF8DC60A188C43CE2B /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + A10B438558BAD74F40FF0188 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + D104E97D065823176A7C7D09 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BEF7E92DFCF099E5539E25E2 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = nl.jknaapen.fladder.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/fladder.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/fladder"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BC60ACA46139A237FC0D7796 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = nl.jknaapen.fladder.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/fladder.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/fladder"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = CA4513CDAF0C75E2FCB2F5F4 /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = nl.jknaapen.fladder.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/fladder.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/fladder"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..2b04679 --- /dev/null +++ b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macos/Runner.xcworkspace/contents.xcworkspacedata b/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..21a3cc1 --- /dev/null +++ b/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/macos/Runner/AppDelegate.swift b/macos/Runner/AppDelegate.swift new file mode 100644 index 0000000..d53ef64 --- /dev/null +++ b/macos/Runner/AppDelegate.swift @@ -0,0 +1,9 @@ +import Cocoa +import FlutterMacOS + +@NSApplicationMain +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..7b4d860 --- /dev/null +++ b/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images": [ + { + "filename": "app_icon_16.png", + "idiom": "mac", + "scale": "1x", + "size": "16x16" + }, + { + "filename": "app_icon_32.png", + "idiom": "mac", + "scale": "2x", + "size": "16x16" + }, + { + "filename": "app_icon_32.png", + "idiom": "mac", + "scale": "1x", + "size": "32x32" + }, + { + "filename": "app_icon_64.png", + "idiom": "mac", + "scale": "2x", + "size": "32x32" + }, + { + "filename": "app_icon_128.png", + "idiom": "mac", + "scale": "1x", + "size": "128x128" + }, + { + "filename": "app_icon_256.png", + "idiom": "mac", + "scale": "2x", + "size": "128x128" + }, + { + "filename": "app_icon_256.png", + "idiom": "mac", + "scale": "1x", + "size": "256x256" + }, + { + "filename": "app_icon_512.png", + "idiom": "mac", + "scale": "2x", + "size": "256x256" + }, + { + "filename": "app_icon_512.png", + "idiom": "mac", + "scale": "1x", + "size": "512x512" + }, + { + "filename": "app_icon_1024.png", + "idiom": "mac", + "scale": "2x", + "size": "512x512" + } + ], + "info": { + "author": "icons_launcher", + "version": 1 + } +} \ No newline at end of file diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon-1024.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon-1024.png new file mode 100644 index 0000000..ad021b8 Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon-1024.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon-128.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon-128.png new file mode 100644 index 0000000..1a1af77 Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon-128.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon-16.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon-16.png new file mode 100644 index 0000000..68098ef Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon-16.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon-256.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon-256.png new file mode 100644 index 0000000..4f0337c Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon-256.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon-32.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon-32.png new file mode 100644 index 0000000..6485db6 Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon-32.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon-512.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon-512.png new file mode 100644 index 0000000..3ebf261 Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon-512.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon-64.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon-64.png new file mode 100644 index 0000000..d34c2d1 Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon-64.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 0000000..9688720 Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 0000000..0996182 Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 0000000..6c91d58 Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 0000000..5a0e4b5 Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 0000000..e1f03e7 Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 0000000..dabc6d3 Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 0000000..b3cc25b Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/macos/Runner/Base.lproj/MainMenu.xib b/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 0000000..80e867a --- /dev/null +++ b/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macos/Runner/Configs/AppInfo.xcconfig b/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 0000000..01d3047 --- /dev/null +++ b/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = Fladder + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = nl.jknaapen.fladder + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2023 com.example. All rights reserved. diff --git a/macos/Runner/Configs/Debug.xcconfig b/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 0000000..36b0fd9 --- /dev/null +++ b/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/macos/Runner/Configs/Release.xcconfig b/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 0000000..dff4f49 --- /dev/null +++ b/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/macos/Runner/Configs/Warnings.xcconfig b/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 0000000..42bcbf4 --- /dev/null +++ b/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/macos/Runner/DebugProfile.entitlements b/macos/Runner/DebugProfile.entitlements new file mode 100644 index 0000000..867a0ba --- /dev/null +++ b/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,14 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + com.apple.security.network.client + + + diff --git a/macos/Runner/Info.plist b/macos/Runner/Info.plist new file mode 100644 index 0000000..4789daa --- /dev/null +++ b/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/macos/Runner/MainFlutterWindow.swift b/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 0000000..3cc05eb --- /dev/null +++ b/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/macos/Runner/Release.entitlements b/macos/Runner/Release.entitlements new file mode 100644 index 0000000..a68a6a2 --- /dev/null +++ b/macos/Runner/Release.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.network.client + + + diff --git a/macos/RunnerTests/RunnerTests.swift b/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..5418c9f --- /dev/null +++ b/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import FlutterMacOS +import Cocoa +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..47c9b00 --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,2159 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a + url: "https://pub.dev" + source: hosted + version: "61.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562 + url: "https://pub.dev" + source: hosted + version: "5.13.0" + analyzer_plugin: + dependency: transitive + description: + name: analyzer_plugin + sha256: c1d5f167683de03d5ab6c3b53fc9aeefc5d59476e7810ba7bbddff50c6f4392d + url: "https://pub.dev" + source: hosted + version: "0.11.2" + animations: + dependency: "direct main" + description: + name: animations + sha256: d3d6dcfb218225bbe68e87ccf6378bbb2e32a94900722c5f81611dad089911cb + url: "https://pub.dev" + source: hosted + version: "2.0.11" + ansicolor: + dependency: transitive + description: + name: ansicolor + sha256: "8bf17a8ff6ea17499e40a2d2542c2f481cd7615760c6d34065cb22bfd22e6880" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + archive: + dependency: "direct main" + description: + name: archive + sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d + url: "https://pub.dev" + source: hosted + version: "3.6.1" + args: + dependency: transitive + description: + name: args + sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" + url: "https://pub.dev" + source: hosted + version: "2.5.0" + async: + dependency: "direct main" + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + audio_service: + dependency: "direct main" + description: + name: audio_service + sha256: "4547c312a94f9cb2c48b60823fb190767cbd63454a83c73049384d5d3cba4650" + url: "https://pub.dev" + source: hosted + version: "0.18.13" + audio_service_platform_interface: + dependency: transitive + description: + name: audio_service_platform_interface + sha256: "8431a455dac9916cc9ee6f7da5620a666436345c906ad2ebb7fa41d18b3c1bf4" + url: "https://pub.dev" + source: hosted + version: "0.1.1" + audio_service_web: + dependency: transitive + description: + name: audio_service_web + sha256: "9d7d5ae5f98a5727f2580fad73062f2484f400eef6cef42919413268e62a363e" + url: "https://pub.dev" + source: hosted + version: "0.1.2" + audio_session: + dependency: transitive + description: + name: audio_session + sha256: a49af9981eec5d7cd73b37bacb6ee73f8143a6a9f9bd5b6021e6c346b9b6cf4e + url: "https://pub.dev" + source: hosted + version: "0.1.19" + automatic_animated_list: + dependency: "direct main" + description: + name: automatic_animated_list + sha256: b119bcde6af33d5c8bd839f9b6d0b6778be90f0ce4b412817bdfcf9f55780645 + url: "https://pub.dev" + source: hosted + version: "1.1.0" + background_downloader: + dependency: "direct main" + description: + name: background_downloader + sha256: "9504093db43da6095c44dd14fc816f3ee8961633ace12340f5d3c4fbfd346e2d" + url: "https://pub.dev" + source: hosted + version: "8.5.2" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + build: + dependency: transitive + description: + name: build + sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + build_cli_annotations: + dependency: transitive + description: + name: build_cli_annotations + sha256: b59d2769769efd6c9ff6d4c4cede0be115a566afc591705c2040b707534b1172 + url: "https://pub.dev" + source: hosted + version: "2.1.0" + build_config: + dependency: transitive + description: + name: build_config + sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + url: "https://pub.dev" + source: hosted + version: "1.1.1" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" + url: "https://pub.dev" + source: hosted + version: "2.4.2" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: "644dc98a0f179b872f612d3eb627924b578897c629788e858157fa5e704ca0c7" + url: "https://pub.dev" + source: hosted + version: "2.4.11" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + sha256: e3c79f69a64bdfcd8a776a3c28db4eb6e3fb5356d013ae5eb2e52007706d5dbe + url: "https://pub.dev" + source: hosted + version: "7.3.1" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb + url: "https://pub.dev" + source: hosted + version: "8.9.2" + cached_network_image: + dependency: "direct main" + description: + name: cached_network_image + sha256: "28ea9690a8207179c319965c13cd8df184d5ee721ae2ce60f398ced1219cea1f" + url: "https://pub.dev" + source: hosted + version: "3.3.1" + cached_network_image_platform_interface: + dependency: transitive + description: + name: cached_network_image_platform_interface + sha256: "9e90e78ae72caa874a323d78fa6301b3fb8fa7ea76a8f96dc5b5bf79f283bf2f" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + cached_network_image_web: + dependency: transitive + description: + name: cached_network_image_web + sha256: "205d6a9f1862de34b93184f22b9d2d94586b2f05c581d546695e3d8f6a805cd7" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + charcode: + dependency: transitive + description: + name: charcode + sha256: fb98c0f6d12c920a02ee2d998da788bca066ca5f148492b7085ee23372b12306 + url: "https://pub.dev" + source: hosted + version: "1.3.1" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" + chewie: + dependency: transitive + description: + name: chewie + sha256: "8bc4ac4cf3f316e50a25958c0f5eb9bb12cf7e8308bb1d74a43b230da2cfc144" + url: "https://pub.dev" + source: hosted + version: "1.7.5" + chopper: + dependency: "direct main" + description: + name: chopper + sha256: "1b6280ec22841b844448bec8ef2644d9cbe9ea8dfce13ec9cab9e8d3aac3830d" + url: "https://pub.dev" + source: hosted + version: "7.4.0" + chopper_generator: + dependency: "direct dev" + description: + name: chopper_generator + sha256: "2984ed8589132aa8fd8225482038cad2bd576405e3751aa237d466870f5dad42" + url: "https://pub.dev" + source: hosted + version: "7.4.0" + ci: + dependency: transitive + description: + name: ci + sha256: "145d095ce05cddac4d797a158bc4cf3b6016d1fe63d8c3d2fbd7212590adca13" + url: "https://pub.dev" + source: hosted + version: "0.1.0" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19 + url: "https://pub.dev" + source: hosted + version: "0.4.1" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37 + url: "https://pub.dev" + source: hosted + version: "4.10.0" + collection: + dependency: "direct main" + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32" + url: "https://pub.dev" + source: hosted + version: "0.3.4+1" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" + csslib: + dependency: transitive + description: + name: csslib + sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 + url: "https://pub.dev" + source: hosted + version: "1.0.8" + custom_lint: + dependency: "direct dev" + description: + name: custom_lint + sha256: "7c0aec12df22f9082146c354692056677f1e70bc43471644d1fdb36c6fdda799" + url: "https://pub.dev" + source: hosted + version: "0.6.4" + custom_lint_core: + dependency: transitive + description: + name: custom_lint_core + sha256: a85e8f78f4c52f6c63cdaf8c872eb573db0231dcdf3c3a5906d493c1f8bc20e6 + url: "https://pub.dev" + source: hosted + version: "0.6.3" + dart_mappable: + dependency: "direct main" + description: + name: dart_mappable + sha256: "47269caf2060533c29b823ff7fa9706502355ffcb61e7f2a374e3a0fb2f2c3f0" + url: "https://pub.dev" + source: hosted + version: "4.2.2" + dart_mappable_builder: + dependency: "direct dev" + description: + name: dart_mappable_builder + sha256: ab5cf9086862d3fceb9773e945b5f95cc5471a28c782a4fc451bd400a4e0c64e + url: "https://pub.dev" + source: hosted + version: "4.2.3" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "1efa911ca7086affd35f463ca2fc1799584fb6aa89883cf0af8e3664d6a02d55" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + dbus: + dependency: transitive + description: + name: dbus + sha256: "365c771ac3b0e58845f39ec6deebc76e3276aa9922b0cc60840712094d9047ac" + url: "https://pub.dev" + source: hosted + version: "0.7.10" + desktop_drop: + dependency: "direct main" + description: + name: desktop_drop + sha256: ebba9c9cb0b54385998a977d741cc06fd8324878c08d5a36e9da61cd56b04cc6 + url: "https://pub.dev" + source: hosted + version: "0.4.3" + diffutil_dart: + dependency: transitive + description: + name: diffutil_dart + sha256: e0297e4600b9797edff228ed60f4169a778ea357691ec98408fa3b72994c7d06 + url: "https://pub.dev" + source: hosted + version: "3.0.0" + drop_shadow: + dependency: "direct main" + description: + name: drop_shadow + sha256: "1fa552baeb7c6a3c36a7ff77186a2302a7bf53c93914f46328a9c4eb68ec6b08" + url: "https://pub.dev" + source: hosted + version: "0.1.0" + dynamic_color: + dependency: "direct main" + description: + name: dynamic_color + sha256: eae98052fa6e2826bdac3dd2e921c6ce2903be15c6b7f8b6d8a5d49b5086298d + url: "https://pub.dev" + source: hosted + version: "1.7.0" + equatable: + dependency: transitive + description: + name: equatable + sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 + url: "https://pub.dev" + source: hosted + version: "2.0.5" + extended_image: + dependency: "direct main" + description: + name: extended_image + sha256: "9786aab821aac117763d6e4419cd49f5031fbaacfe3fd212c5b313d0334c37a9" + url: "https://pub.dev" + source: hosted + version: "8.2.1" + extended_image_library: + dependency: transitive + description: + name: extended_image_library + sha256: c9caee8fe9b6547bd41c960c4f2d1ef8e34321804de6a1777f1d614a24247ad6 + url: "https://pub.dev" + source: hosted + version: "4.0.4" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + ficonsax: + dependency: "direct main" + description: + name: ficonsax + sha256: f7c69817fb4a9a8545ed66656990d4634adad61b2b8d601fb91ba99d389fad47 + url: "https://pub.dev" + source: hosted + version: "0.0.3" + file: + dependency: transitive + description: + name: file + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + file_picker: + dependency: "direct main" + description: + name: file_picker + sha256: "1bbf65dd997458a08b531042ec3794112a6c39c07c37ff22113d2e7e4f81d4e4" + url: "https://pub.dev" + source: hosted + version: "6.2.1" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + flexible_scrollbar: + dependency: "direct main" + description: + name: flexible_scrollbar + sha256: f5b808009624c49929b9a9c19c41c36fefeac7d8f36cb84558fd26614158d6e9 + url: "https://pub.dev" + source: hosted + version: "0.1.3" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_blurhash: + dependency: "direct main" + description: + name: flutter_blurhash + sha256: "5e67678e479ac639069d7af1e133f4a4702311491188ff3e0227486430db0c06" + url: "https://pub.dev" + source: hosted + version: "0.8.2" + flutter_cache_manager: + dependency: "direct main" + description: + name: flutter_cache_manager + sha256: "8207f27539deb83732fdda03e259349046a39a4c767269285f449ade355d54ba" + url: "https://pub.dev" + source: hosted + version: "3.3.1" + flutter_custom_tabs: + dependency: "direct main" + description: + name: flutter_custom_tabs + sha256: e90e5b7cad5648aeb0e1ed04aa3c0cada62d86f3b5d4aaef488ab7de61ec2a9f + url: "https://pub.dev" + source: hosted + version: "1.2.1" + flutter_custom_tabs_platform_interface: + dependency: transitive + description: + name: flutter_custom_tabs_platform_interface + sha256: "1d6b9eb6c5671b21511fdb47babf18aa65982784373986c003aaf67ca78798ad" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + flutter_custom_tabs_web: + dependency: transitive + description: + name: flutter_custom_tabs_web + sha256: dbb5689a97c2398aa5dbcfc9cd59cffea5518ec815e9d23def448dc143cb02be + url: "https://pub.dev" + source: hosted + version: "1.1.0" + flutter_keyboard_visibility: + dependency: transitive + description: + name: flutter_keyboard_visibility + sha256: "98664be7be0e3ffca00de50f7f6a287ab62c763fc8c762e0a21584584a3ff4f8" + url: "https://pub.dev" + source: hosted + version: "6.0.0" + flutter_keyboard_visibility_linux: + dependency: transitive + description: + name: flutter_keyboard_visibility_linux + sha256: "6fba7cd9bb033b6ddd8c2beb4c99ad02d728f1e6e6d9b9446667398b2ac39f08" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + flutter_keyboard_visibility_macos: + dependency: transitive + description: + name: flutter_keyboard_visibility_macos + sha256: c5c49b16fff453dfdafdc16f26bdd8fb8d55812a1d50b0ce25fc8d9f2e53d086 + url: "https://pub.dev" + source: hosted + version: "1.0.0" + flutter_keyboard_visibility_platform_interface: + dependency: transitive + description: + name: flutter_keyboard_visibility_platform_interface + sha256: e43a89845873f7be10cb3884345ceb9aebf00a659f479d1c8f4293fcb37022a4 + url: "https://pub.dev" + source: hosted + version: "2.0.0" + flutter_keyboard_visibility_web: + dependency: transitive + description: + name: flutter_keyboard_visibility_web + sha256: d3771a2e752880c79203f8d80658401d0c998e4183edca05a149f5098ce6e3d1 + url: "https://pub.dev" + source: hosted + version: "2.0.0" + flutter_keyboard_visibility_windows: + dependency: transitive + description: + name: flutter_keyboard_visibility_windows + sha256: fc4b0f0b6be9b93ae527f3d527fb56ee2d918cd88bbca438c478af7bcfd0ef73 + url: "https://pub.dev" + source: hosted + version: "1.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + flutter_localizations: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: c6b0b4c05c458e1c01ad9bcc14041dd7b1f6783d487be4386f793f47a8a4d03e + url: "https://pub.dev" + source: hosted + version: "2.0.20" + flutter_riverpod: + dependency: "direct main" + description: + name: flutter_riverpod + sha256: "0f1974eff5bbe774bf1d870e406fc6f29e3d6f1c46bd9c58e7172ff68a785d7d" + url: "https://pub.dev" + source: hosted + version: "2.5.1" + flutter_rust_bridge: + dependency: transitive + description: + name: flutter_rust_bridge + sha256: "02720226035257ad0b571c1256f43df3e1556a499f6bcb004849a0faaa0e87f0" + url: "https://pub.dev" + source: hosted + version: "1.82.6" + flutter_staggered_animations: + dependency: "direct main" + description: + name: flutter_staggered_animations + sha256: "81d3c816c9bb0dca9e8a5d5454610e21ffb068aedb2bde49d2f8d04f75538351" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + flutter_staggered_grid_view: + dependency: "direct main" + description: + name: flutter_staggered_grid_view + sha256: "19e7abb550c96fbfeb546b23f3ff356ee7c59a019a651f8f102a4ba9b7349395" + url: "https://pub.dev" + source: hosted + version: "0.7.0" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2" + url: "https://pub.dev" + source: hosted + version: "2.0.10+1" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_typeahead: + dependency: "direct main" + description: + name: flutter_typeahead + sha256: d64712c65db240b1057559b952398ebb6e498077baeebf9b0731dade62438a6d + url: "https://pub.dev" + source: hosted + version: "5.2.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + flutter_widget_from_html: + dependency: "direct main" + description: + name: flutter_widget_from_html + sha256: "22c911b6ccf82b83e0c457d987bac4e703440fea0fc88dab24f4dfe995a5f33f" + url: "https://pub.dev" + source: hosted + version: "0.14.11" + flutter_widget_from_html_core: + dependency: transitive + description: + name: flutter_widget_from_html_core + sha256: cc1d9be3d187ce668ee02091cd5442dfb050cdaf98e0ab9a4d12ad008f966979 + url: "https://pub.dev" + source: hosted + version: "0.14.12" + freezed: + dependency: "direct dev" + description: + name: freezed + sha256: a434911f643466d78462625df76fd9eb13e57348ff43fe1f77bbe909522c67a1 + url: "https://pub.dev" + source: hosted + version: "2.5.2" + freezed_annotation: + dependency: "direct main" + description: + name: freezed_annotation + sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d + url: "https://pub.dev" + source: hosted + version: "2.4.1" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 + url: "https://pub.dev" + source: hosted + version: "4.0.0" + fwfh_cached_network_image: + dependency: transitive + description: + name: fwfh_cached_network_image + sha256: "8e44226801bfba27930673953afce8af44da7e92573be93f60385d9865a089dd" + url: "https://pub.dev" + source: hosted + version: "0.14.3" + fwfh_chewie: + dependency: transitive + description: + name: fwfh_chewie + sha256: "37bde9cedfb6dc5546176f7f0c56af1e814966cb33ec58f16c9565ed93ccb704" + url: "https://pub.dev" + source: hosted + version: "0.14.8" + fwfh_just_audio: + dependency: transitive + description: + name: fwfh_just_audio + sha256: "209cf9644599e37b0edb6961c4f30ce80d156f5a53a50355f75fb4a22f9fdb0a" + url: "https://pub.dev" + source: hosted + version: "0.14.3" + fwfh_svg: + dependency: transitive + description: + name: fwfh_svg + sha256: c6bb6b513f7ce2766aba76d7276caf9a96b6fee729ac3a492c366a42f82ef02e + url: "https://pub.dev" + source: hosted + version: "0.8.2" + fwfh_url_launcher: + dependency: transitive + description: + name: fwfh_url_launcher + sha256: b9f5d55a5ae2c2c07243ba33f7ba49ac9544bdb2f4c16d8139df9ccbebe3449c + url: "https://pub.dev" + source: hosted + version: "0.9.1" + fwfh_webview: + dependency: transitive + description: + name: fwfh_webview + sha256: b828bb5ddd4361a866cdb8f1b0de4f3348f332915ecf2f4215ba17e46c656adc + url: "https://pub.dev" + source: hosted + version: "0.14.8" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + go_router: + dependency: "direct main" + description: + name: go_router + sha256: cdae1b9c8bd7efadcef6112e81c903662ef2ce105cbd220a04bbb7c3425b5554 + url: "https://pub.dev" + source: hosted + version: "14.2.0" + google_fonts: + dependency: "direct main" + description: + name: google_fonts + sha256: b1ac0fe2832c9cc95e5e88b57d627c5e68c223b9657f4b96e1487aa9098c7b82 + url: "https://pub.dev" + source: hosted + version: "6.2.1" + graphs: + dependency: transitive + description: + name: graphs + sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + url: "https://pub.dev" + source: hosted + version: "2.3.1" + html: + dependency: transitive + description: + name: html + sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" + url: "https://pub.dev" + source: hosted + version: "0.15.4" + http: + dependency: "direct main" + description: + name: http + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 + url: "https://pub.dev" + source: hosted + version: "1.2.2" + http_client_helper: + dependency: transitive + description: + name: http_client_helper + sha256: "8a9127650734da86b5c73760de2b404494c968a3fd55602045ffec789dac3cb1" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + icons_launcher: + dependency: "direct main" + description: + name: icons_launcher + sha256: "9b514ffed6ed69b232fd2bf34c44878c8526be71fc74129a658f35c04c9d4a9d" + url: "https://pub.dev" + source: hosted + version: "2.1.7" + image: + dependency: transitive + description: + name: image + sha256: "2237616a36c0d69aef7549ab439b833fb7f9fb9fc861af2cc9ac3eedddd69ca8" + url: "https://pub.dev" + source: hosted + version: "4.2.0" + intl: + dependency: "direct main" + description: + name: intl + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf + url: "https://pub.dev" + source: hosted + version: "0.19.0" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + isar: + dependency: "direct main" + description: + name: isar + sha256: ebf74d87c400bd9f7da14acb31932b50c2407edbbd40930da3a6c2a8143f85a8 + url: "https://pub.dev" + source: hosted + version: "4.0.0-dev.14" + isar_flutter_libs: + dependency: "direct main" + description: + name: isar_flutter_libs + sha256: "04a3f4035e213ddb6e78d0132a7c80296a085c2088c2a761b4a42ee5add36983" + url: "https://pub.dev" + source: hosted + version: "4.0.0-dev.14" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" + json_annotation: + dependency: "direct main" + description: + name: json_annotation + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" + source: hosted + version: "4.9.0" + json_serializable: + dependency: "direct dev" + description: + name: json_serializable + sha256: ea1432d167339ea9b5bb153f0571d0039607a873d6e04e0117af043f14a1fd4b + url: "https://pub.dev" + source: hosted + version: "6.8.0" + just_audio: + dependency: transitive + description: + name: just_audio + sha256: "5abfab1d199e01ab5beffa61b3e782350df5dad036cb8c83b79fa45fc656614e" + url: "https://pub.dev" + source: hosted + version: "0.9.38" + just_audio_platform_interface: + dependency: transitive + description: + name: just_audio_platform_interface + sha256: "0243828cce503c8366cc2090cefb2b3c871aa8ed2f520670d76fd47aa1ab2790" + url: "https://pub.dev" + source: hosted + version: "4.3.0" + just_audio_web: + dependency: transitive + description: + name: just_audio_web + sha256: "0edb481ad4aa1ff38f8c40f1a3576013c3420bf6669b686fe661627d49bc606c" + url: "https://pub.dev" + source: hosted + version: "0.4.11" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" + url: "https://pub.dev" + source: hosted + version: "10.0.4" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + url: "https://pub.dev" + source: hosted + version: "3.0.3" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + lints: + dependency: transitive + description: + name: lints + sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + url: "https://pub.dev" + source: hosted + version: "3.0.0" + local_auth: + dependency: "direct main" + description: + name: local_auth + sha256: "280421b416b32de31405b0a25c3bd42dfcef2538dfbb20c03019e02a5ed55ed0" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + local_auth_android: + dependency: transitive + description: + name: local_auth_android + sha256: "6b60f9f545af5b5a11a90af3c2ab4361c47fff170134fa1c6d4c7d52e6537174" + url: "https://pub.dev" + source: hosted + version: "1.0.41" + local_auth_darwin: + dependency: transitive + description: + name: local_auth_darwin + sha256: e424ebf90d5233452be146d4a7da4bcd7a70278b67791592f3fde1bda8eef9e2 + url: "https://pub.dev" + source: hosted + version: "1.3.1" + local_auth_platform_interface: + dependency: transitive + description: + name: local_auth_platform_interface + sha256: "1b842ff177a7068442eae093b64abe3592f816afd2a533c0ebcdbe40f9d2075a" + url: "https://pub.dev" + source: hosted + version: "1.0.10" + local_auth_windows: + dependency: transitive + description: + name: local_auth_windows + sha256: "505ba3367ca781efb1c50d3132e44a2446bccc4163427bc203b9b4d8994d97ea" + url: "https://pub.dev" + source: hosted + version: "1.0.10" + logging: + dependency: "direct main" + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + markdown: + dependency: transitive + description: + name: markdown + sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051 + url: "https://pub.dev" + source: hosted + version: "7.2.2" + matcher: + dependency: transitive + description: + name: matcher + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" + source: hosted + version: "0.12.16+1" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + url: "https://pub.dev" + source: hosted + version: "0.8.0" + media_kit: + dependency: "direct main" + description: + name: media_kit + sha256: "3289062540e3b8b9746e5c50d95bd78a9289826b7227e253dff806d002b9e67a" + url: "https://pub.dev" + source: hosted + version: "1.1.10+1" + media_kit_libs_android_video: + dependency: transitive + description: + name: media_kit_libs_android_video + sha256: "9dd8012572e4aff47516e55f2597998f0a378e3d588d0fad0ca1f11a53ae090c" + url: "https://pub.dev" + source: hosted + version: "1.3.6" + media_kit_libs_ios_video: + dependency: transitive + description: + name: media_kit_libs_ios_video + sha256: b5382994eb37a4564c368386c154ad70ba0cc78dacdd3fb0cd9f30db6d837991 + url: "https://pub.dev" + source: hosted + version: "1.1.4" + media_kit_libs_linux: + dependency: transitive + description: + name: media_kit_libs_linux + sha256: e186891c31daa6bedab4d74dcdb4e8adfccc7d786bfed6ad81fe24a3b3010310 + url: "https://pub.dev" + source: hosted + version: "1.1.3" + media_kit_libs_macos_video: + dependency: transitive + description: + name: media_kit_libs_macos_video + sha256: f26aa1452b665df288e360393758f84b911f70ffb3878032e1aabba23aa1032d + url: "https://pub.dev" + source: hosted + version: "1.1.4" + media_kit_libs_video: + dependency: "direct main" + description: + name: media_kit_libs_video + sha256: "3688e0c31482074578652bf038ce6301a5d21e1eda6b54fc3117ffeb4bdba067" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + media_kit_libs_windows_video: + dependency: transitive + description: + name: media_kit_libs_windows_video + sha256: "7bace5f35d9afcc7f9b5cdadb7541d2191a66bb3fc71bfa11c1395b3360f6122" + url: "https://pub.dev" + source: hosted + version: "1.0.9" + media_kit_native_event_loop: + dependency: transitive + description: + name: media_kit_native_event_loop + sha256: a605cf185499d14d58935b8784955a92a4bf0ff4e19a23de3d17a9106303930e + url: "https://pub.dev" + source: hosted + version: "1.0.8" + media_kit_video: + dependency: "direct main" + description: + name: media_kit_video + sha256: c048d11a19e379aebbe810647636e3fc6d18374637e2ae12def4ff8a4b99a882 + url: "https://pub.dev" + source: hosted + version: "1.2.4" + meta: + dependency: transitive + description: + name: meta + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + url: "https://pub.dev" + source: hosted + version: "1.12.0" + mime: + dependency: transitive + description: + name: mime + sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" + url: "https://pub.dev" + source: hosted + version: "1.0.5" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + octo_image: + dependency: transitive + description: + name: octo_image + sha256: "45b40f99622f11901238e18d48f5f12ea36426d8eced9f4cbf58479c7aa2430d" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + open_app_file: + dependency: "direct main" + description: + name: open_app_file + sha256: "5dd0af054364c12093947ad3e69370bb22ca535ca17f81f7b72444c7be18cc01" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + package_info_plus: + dependency: "direct main" + description: + name: package_info_plus + sha256: b93d8b4d624b4ea19b0a5a208b2d6eff06004bc3ce74c06040b120eeadd00ce0 + url: "https://pub.dev" + source: hosted + version: "8.0.0" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + sha256: f49918f3433a3146047372f9d4f1f847511f2acd5cd030e1f44fe5a50036b70e + url: "https://pub.dev" + source: hosted + version: "3.0.0" + page_transition: + dependency: "direct main" + description: + name: page_transition + sha256: dee976b1f23de9bbef5cd512fe567e9f6278caee11f5eaca9a2115c19dc49ef6 + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path: + dependency: "direct main" + description: + name: path + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" + source: hosted + version: "1.9.0" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf + url: "https://pub.dev" + source: hosted + version: "1.0.1" + path_provider: + dependency: "direct main" + description: + name: path_provider + sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161 + url: "https://pub.dev" + source: hosted + version: "2.1.3" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: bca87b0165ffd7cdb9cad8edd22d18d2201e886d9a9f19b4fb3452ea7df3a72a + url: "https://pub.dev" + source: hosted + version: "2.2.6" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 + url: "https://pub.dev" + source: hosted + version: "2.4.0" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + url: "https://pub.dev" + source: hosted + version: "2.2.1" + permission_handler: + dependency: "direct main" + description: + name: permission_handler + sha256: "18bf33f7fefbd812f37e72091a15575e72d5318854877e0e4035a24ac1113ecb" + url: "https://pub.dev" + source: hosted + version: "11.3.1" + permission_handler_android: + dependency: transitive + description: + name: permission_handler_android + sha256: b29a799ca03be9f999aa6c39f7de5209482d638e6f857f6b93b0875c618b7e54 + url: "https://pub.dev" + source: hosted + version: "12.0.7" + permission_handler_apple: + dependency: transitive + description: + name: permission_handler_apple + sha256: e6f6d73b12438ef13e648c4ae56bd106ec60d17e90a59c4545db6781229082a0 + url: "https://pub.dev" + source: hosted + version: "9.4.5" + permission_handler_html: + dependency: transitive + description: + name: permission_handler_html + sha256: "54bf176b90f6eddd4ece307e2c06cf977fb3973719c35a93b85cc7093eb6070d" + url: "https://pub.dev" + source: hosted + version: "0.1.1" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + sha256: "48d4fcf201a1dad93ee869ab0d4101d084f49136ec82a8a06ed9cfeacab9fd20" + url: "https://pub.dev" + source: hosted + version: "4.2.1" + permission_handler_windows: + dependency: transitive + description: + name: permission_handler_windows + sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e" + url: "https://pub.dev" + source: hosted + version: "0.2.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + url: "https://pub.dev" + source: hosted + version: "6.0.2" + platform: + dependency: transitive + description: + name: platform + sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" + url: "https://pub.dev" + source: hosted + version: "3.1.5" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + pointer_interceptor: + dependency: transitive + description: + name: pointer_interceptor + sha256: d0a8e660d1204eaec5bd34b34cc92174690e076d2e4f893d9d68c486a13b07c4 + url: "https://pub.dev" + source: hosted + version: "0.10.1+1" + pointer_interceptor_ios: + dependency: transitive + description: + name: pointer_interceptor_ios + sha256: a6906772b3205b42c44614fcea28f818b1e5fdad73a4ca742a7bd49818d9c917 + url: "https://pub.dev" + source: hosted + version: "0.10.1" + pointer_interceptor_platform_interface: + dependency: transitive + description: + name: pointer_interceptor_platform_interface + sha256: "0597b0560e14354baeb23f8375cd612e8bd4841bf8306ecb71fcd0bb78552506" + url: "https://pub.dev" + source: hosted + version: "0.10.0+1" + pointer_interceptor_web: + dependency: transitive + description: + name: pointer_interceptor_web + sha256: a6237528b46c411d8d55cdfad8fcb3269fc4cbb26060b14bff94879165887d1e + url: "https://pub.dev" + source: hosted + version: "0.10.2" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + provider: + dependency: transitive + description: + name: provider + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c + url: "https://pub.dev" + source: hosted + version: "6.1.2" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8 + url: "https://pub.dev" + source: hosted + version: "1.3.0" + puppeteer: + dependency: transitive + description: + name: puppeteer + sha256: de3f921154e5d336b14cdc05b674ac3db5701a5338f3cb0042868a5146f16e67 + url: "https://pub.dev" + source: hosted + version: "3.12.0" + qs_dart: + dependency: transitive + description: + name: qs_dart + sha256: "5f1827ccdfa061582c121e7a8fe4a83319fa455bcd1fd6e46ff5b17b57aed680" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + recase: + dependency: transitive + description: + name: recase + sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 + url: "https://pub.dev" + source: hosted + version: "4.1.0" + recursive_regex: + dependency: transitive + description: + name: recursive_regex + sha256: f7252e3d3dfd1665e594d9fe035eca6bc54139b1f2fee38256fa427ea41adc60 + url: "https://pub.dev" + source: hosted + version: "1.0.0" + reorderable_grid: + dependency: "direct main" + description: + name: reorderable_grid + sha256: "0b9cd95ef0f070ef99f92affe9cf85a4aa127099cd1334e5940950ce58cd981d" + url: "https://pub.dev" + source: hosted + version: "1.0.10" + riverpod: + dependency: transitive + description: + name: riverpod + sha256: f21b32ffd26a36555e501b04f4a5dca43ed59e16343f1a30c13632b2351dfa4d + url: "https://pub.dev" + source: hosted + version: "2.5.1" + riverpod_analyzer_utils: + dependency: transitive + description: + name: riverpod_analyzer_utils + sha256: "8b71f03fc47ae27d13769496a1746332df4cec43918aeba9aff1e232783a780f" + url: "https://pub.dev" + source: hosted + version: "0.5.1" + riverpod_annotation: + dependency: "direct main" + description: + name: riverpod_annotation + sha256: e5e796c0eba4030c704e9dae1b834a6541814963292839dcf9638d53eba84f5c + url: "https://pub.dev" + source: hosted + version: "2.3.5" + riverpod_generator: + dependency: "direct dev" + description: + name: riverpod_generator + sha256: d451608bf17a372025fc36058863737636625dfdb7e3cbf6142e0dfeb366ab22 + url: "https://pub.dev" + source: hosted + version: "2.4.0" + rxdart: + dependency: transitive + description: + name: rxdart + sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb" + url: "https://pub.dev" + source: hosted + version: "0.27.7" + safe_local_storage: + dependency: transitive + description: + name: safe_local_storage + sha256: ede4eb6cb7d88a116b3d3bf1df70790b9e2038bc37cb19112e381217c74d9440 + url: "https://pub.dev" + source: hosted + version: "1.0.2" + screen_brightness: + dependency: "direct main" + description: + name: screen_brightness + sha256: ed8da4a4511e79422fc1aa88138e920e4008cd312b72cdaa15ccb426c0faaedd + url: "https://pub.dev" + source: hosted + version: "0.2.2+1" + screen_brightness_android: + dependency: transitive + description: + name: screen_brightness_android + sha256: "3df10961e3a9e968a5e076fe27e7f4741fa8a1d3950bdeb48cf121ed529d0caf" + url: "https://pub.dev" + source: hosted + version: "0.1.0+2" + screen_brightness_ios: + dependency: transitive + description: + name: screen_brightness_ios + sha256: "99adc3ca5490b8294284aad5fcc87f061ad685050e03cf45d3d018fe398fd9a2" + url: "https://pub.dev" + source: hosted + version: "0.1.0" + screen_brightness_macos: + dependency: transitive + description: + name: screen_brightness_macos + sha256: "64b34e7e3f4900d7687c8e8fb514246845a73ecec05ab53483ed025bd4a899fd" + url: "https://pub.dev" + source: hosted + version: "0.1.0+1" + screen_brightness_platform_interface: + dependency: transitive + description: + name: screen_brightness_platform_interface + sha256: b211d07f0c96637a15fb06f6168617e18030d5d74ad03795dd8547a52717c171 + url: "https://pub.dev" + source: hosted + version: "0.1.0" + screen_brightness_windows: + dependency: transitive + description: + name: screen_brightness_windows + sha256: "9261bf33d0fc2707d8cf16339ce25768100a65e70af0fcabaf032fc12408ba86" + url: "https://pub.dev" + source: hosted + version: "0.1.3" + screen_retriever: + dependency: transitive + description: + name: screen_retriever + sha256: "6ee02c8a1158e6dae7ca430da79436e3b1c9563c8cf02f524af997c201ac2b90" + url: "https://pub.dev" + source: hosted + version: "0.1.9" + scrollable_positioned_list: + dependency: "direct main" + description: + name: scrollable_positioned_list + sha256: "1b54d5f1329a1e263269abc9e2543d90806131aa14fe7c6062a8054d57249287" + url: "https://pub.dev" + source: hosted + version: "0.3.8" + share_plus: + dependency: "direct main" + description: + name: share_plus + sha256: "3ef39599b00059db0990ca2e30fca0a29d8b37aae924d60063f8e0184cf20900" + url: "https://pub.dev" + source: hosted + version: "7.2.2" + share_plus_platform_interface: + dependency: transitive + description: + name: share_plus_platform_interface + sha256: "251eb156a8b5fa9ce033747d73535bf53911071f8d3b6f4f0b578505ce0d4496" + url: "https://pub.dev" + source: hosted + version: "3.4.0" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180 + url: "https://pub.dev" + source: hosted + version: "2.2.3" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: "93d0ec9dd902d85f326068e6a899487d1f65ffcd5798721a95330b26c8131577" + url: "https://pub.dev" + source: hosted + version: "2.2.3" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "0a8a893bf4fd1152f93fec03a415d11c27c74454d96e2318a7ac38dd18683ab7" + url: "https://pub.dev" + source: hosted + version: "2.4.0" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e + url: "https://pub.dev" + source: hosted + version: "1.1.2" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + sliver_tools: + dependency: "direct main" + description: + name: sliver_tools + sha256: eae28220badfb9d0559207badcbbc9ad5331aac829a88cb0964d330d2a4636a6 + url: "https://pub.dev" + source: hosted + version: "0.2.12" + smtc_windows: + dependency: "direct main" + description: + name: smtc_windows + sha256: "0fd64d0c6a0c8ea4ea7908d31195eadc8f6d45d5245159fc67259e9e8704100f" + url: "https://pub.dev" + source: hosted + version: "0.1.3" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" + url: "https://pub.dev" + source: hosted + version: "1.5.0" + source_helper: + dependency: transitive + description: + name: source_helper + sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd" + url: "https://pub.dev" + source: hosted + version: "1.3.4" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + sprintf: + dependency: transitive + description: + name: sprintf + sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + sqflite: + dependency: transitive + description: + name: sqflite + sha256: a43e5a27235518c03ca238e7b4732cf35eabe863a369ceba6cbefa537a66f16d + url: "https://pub.dev" + source: hosted + version: "2.3.3+1" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + sha256: "3da423ce7baf868be70e2c0976c28a1bb2f73644268b7ffa7d2e08eab71f16a4" + url: "https://pub.dev" + source: hosted + version: "2.5.4" + square_progress_indicator: + dependency: "direct main" + description: + name: square_progress_indicator + sha256: "10f62bbb759dd07c9879711f965ba35e9b1810d7fd6c1e5152cb517ae89245fa" + url: "https://pub.dev" + source: hosted + version: "0.0.7" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + state_notifier: + dependency: transitive + description: + name: state_notifier + sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb + url: "https://pub.dev" + source: hosted + version: "1.0.0" + sticky_headers: + dependency: "direct main" + description: + name: sticky_headers + sha256: "9b3dd2cb0fd6a7038170af3261f855660cbb241cb56c501452cb8deed7023ede" + url: "https://pub.dev" + source: hosted + version: "0.3.0+2" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + swagger_dart_code_generator: + dependency: "direct dev" + description: + name: swagger_dart_code_generator + sha256: "73dedc94da13ee4c7259cb60411ccf699789eeceb842a493e025afbca808bb99" + url: "https://pub.dev" + source: hosted + version: "2.15.2" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558" + url: "https://pub.dev" + source: hosted + version: "3.1.0+1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + url: "https://pub.dev" + source: hosted + version: "0.7.0" + timing: + dependency: transitive + description: + name: timing + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + transparent_image: + dependency: "direct main" + description: + name: transparent_image + sha256: e8991d955a2094e197ca24c645efec2faf4285772a4746126ca12875e54ca02f + url: "https://pub.dev" + source: hosted + version: "2.0.1" + tuple: + dependency: transitive + description: + name: tuple + sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 + url: "https://pub.dev" + source: hosted + version: "2.0.2" + type_plus: + dependency: transitive + description: + name: type_plus + sha256: d5d1019471f0d38b91603adb9b5fd4ce7ab903c879d2fbf1a3f80a630a03fcc9 + url: "https://pub.dev" + source: hosted + version: "2.1.1" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + universal_html: + dependency: "direct main" + description: + name: universal_html + sha256: "56536254004e24d9d8cfdb7dbbf09b74cf8df96729f38a2f5c238163e3d58971" + url: "https://pub.dev" + source: hosted + version: "2.2.4" + universal_io: + dependency: transitive + description: + name: universal_io + sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + universal_platform: + dependency: transitive + description: + name: universal_platform + sha256: "64e16458a0ea9b99260ceb5467a214c1f298d647c659af1bff6d3bf82536b1ec" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + uri_parser: + dependency: transitive + description: + name: uri_parser + sha256: "6543c9fd86d2862fac55d800a43e67c0dcd1a41677cb69c2f8edfe73bbcf1835" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3" + url: "https://pub.dev" + source: hosted + version: "6.3.0" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + sha256: ceb2625f0c24ade6ef6778d1de0b2e44f2db71fded235eb52295247feba8c5cf + url: "https://pub.dev" + source: hosted + version: "6.3.3" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + sha256: "7068716403343f6ba4969b4173cbf3b84fc768042124bc2c011e5d782b24fe89" + url: "https://pub.dev" + source: hosted + version: "6.3.0" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811 + url: "https://pub.dev" + source: hosted + version: "3.1.1" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a" + url: "https://pub.dev" + source: hosted + version: "2.3.1" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + sha256: ecf9725510600aa2bb6d7ddabe16357691b6d2805f66216a97d1b881e21beff7 + url: "https://pub.dev" + source: hosted + version: "3.1.1" + uuid: + dependency: transitive + description: + name: uuid + sha256: "814e9e88f21a176ae1359149021870e87f7cddaf633ab678a5d2b0bff7fd1ba8" + url: "https://pub.dev" + source: hosted + version: "4.4.0" + validators: + dependency: "direct main" + description: + name: validators + sha256: "884515951f831a9c669a41ed6c4d3c61c2a0e8ec6bca761a4480b28e99cecf5d" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3" + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81" + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + video_player: + dependency: transitive + description: + name: video_player + sha256: e30df0d226c4ef82e2c150ebf6834b3522cf3f654d8e2f9419d376cdc071425d + url: "https://pub.dev" + source: hosted + version: "2.9.1" + video_player_android: + dependency: transitive + description: + name: video_player_android + sha256: fdc0331ce9f808cc2714014cb8126bd6369943affefd54f8fdab0ea0bb617b7f + url: "https://pub.dev" + source: hosted + version: "2.5.2" + video_player_avfoundation: + dependency: transitive + description: + name: video_player_avfoundation + sha256: d1e9a824f2b324000dc8fb2dcb2a3285b6c1c7c487521c63306cc5b394f68a7c + url: "https://pub.dev" + source: hosted + version: "2.6.1" + video_player_platform_interface: + dependency: transitive + description: + name: video_player_platform_interface + sha256: "236454725fafcacf98f0f39af0d7c7ab2ce84762e3b63f2cbb3ef9a7e0550bc6" + url: "https://pub.dev" + source: hosted + version: "6.2.2" + video_player_web: + dependency: transitive + description: + name: video_player_web + sha256: "8e9cb7fe94e49490e67bbc15149691792b58a0ade31b32e3f3688d104a0e057b" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" + url: "https://pub.dev" + source: hosted + version: "14.2.1" + volume_controller: + dependency: transitive + description: + name: volume_controller + sha256: "189bdc7a554f476b412e4c8b2f474562b09d74bc458c23667356bce3ca1d48c9" + url: "https://pub.dev" + source: hosted + version: "2.0.7" + wakelock_plus: + dependency: "direct main" + description: + name: wakelock_plus + sha256: "14758533319a462ffb5aa3b7ddb198e59b29ac3b02da14173a1715d65d4e6e68" + url: "https://pub.dev" + source: hosted + version: "1.2.5" + wakelock_plus_platform_interface: + dependency: transitive + description: + name: wakelock_plus_platform_interface + sha256: "422d1cdbb448079a8a62a5a770b69baa489f8f7ca21aef47800c726d404f9d16" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + weak_map: + dependency: transitive + description: + name: weak_map + sha256: "95ca338f0cdf5f0022cc283dfa4d97f6f6b03752f67eca85ebe6d7a679ffe3ed" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + web: + dependency: transitive + description: + name: web + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" + url: "https://pub.dev" + source: hosted + version: "0.5.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42" + url: "https://pub.dev" + source: hosted + version: "2.4.5" + webview_flutter: + dependency: transitive + description: + name: webview_flutter + sha256: "6869c8786d179f929144b4a1f86e09ac0eddfe475984951ea6c634774c16b522" + url: "https://pub.dev" + source: hosted + version: "4.8.0" + webview_flutter_android: + dependency: transitive + description: + name: webview_flutter_android + sha256: f42447ca49523f11d8f70abea55ea211b3cafe172dd7a0e7ac007bb35dd356dc + url: "https://pub.dev" + source: hosted + version: "3.16.4" + webview_flutter_platform_interface: + dependency: transitive + description: + name: webview_flutter_platform_interface + sha256: d937581d6e558908d7ae3dc1989c4f87b786891ab47bb9df7de548a151779d8d + url: "https://pub.dev" + source: hosted + version: "2.10.0" + webview_flutter_wkwebview: + dependency: transitive + description: + name: webview_flutter_wkwebview + sha256: "7affdf9d680c015b11587181171d3cad8093e449db1f7d9f0f08f4f33d24f9a0" + url: "https://pub.dev" + source: hosted + version: "3.13.1" + win32: + dependency: transitive + description: + name: win32 + sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4 + url: "https://pub.dev" + source: hosted + version: "5.5.1" + window_manager: + dependency: "direct main" + description: + name: window_manager + sha256: "8699323b30da4cdbe2aa2e7c9de567a6abd8a97d9a5c850a3c86dcd0b34bbfbf" + url: "https://pub.dev" + source: hosted + version: "0.3.9" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + url: "https://pub.dev" + source: hosted + version: "1.0.4" + xid: + dependency: "direct main" + description: + name: xid + sha256: "58b61c7c1234810afa500cde7556d7c407ce72154e0d5a8a5618690f03848dbd" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" +sdks: + dart: ">=3.4.0 <4.0.0" + flutter: ">=3.22.0" diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..7696914 --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,165 @@ +name: fladder +description: A simple cross-platform Jellyfin client. +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: "none" # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. +version: 0.2.1+0 + +environment: + sdk: ">=3.1.3 <4.0.0" + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + flutter_localizations: + sdk: flutter + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + # Icons + cupertino_icons: ^1.0.2 + ficonsax: ^0.0.3 + icons_launcher: ^2.1.7 + + # Network and HTTP + chopper: ^7.0.4 + cached_network_image: ^3.2.3 + http: ^1.1.0 + flutter_cache_manager: ^3.3.0 + + # State Management + flutter_riverpod: ^2.5.1 + riverpod_annotation: ^2.3.5 + + # JSON and Serialization + json_annotation: ^4.9.0 + freezed_annotation: ^2.4.1 + + # Logging + logging: ^1.1.0 + + # Internationalization + intl: ^0.19.0 + + # Local Storage + shared_preferences: ^2.1.0 + path_provider: ^2.1.3 + + # Fonts + google_fonts: ^6.1.0 + + # Media + media_kit: ^1.1.10 # Primary package. + media_kit_video: ^1.2.4 # For video rendering. + media_kit_libs_video: ^1.0.4 # Native video dependencies. + audio_service: ^0.18.12 + + # UI Components + dynamic_color: ^1.7.0 + flutter_svg: ^2.0.4 + drop_shadow: ^0.1.0 + animations: ^2.0.7 + automatic_animated_list: ^1.1.0 + page_transition: ^2.0.9 + sticky_headers: ^0.3.0+2 + flutter_staggered_grid_view: ^0.7.0 + flutter_staggered_animations: ^1.1.1 + scrollable_positioned_list: ^0.3.8 + sliver_tools: ^0.2.10 + square_progress_indicator: ^0.0.7 + flutter_blurhash: ^0.8.2 + extended_image: ^8.1.1 + flutter_widget_from_html: ^0.14.11 + + # Navigation + go_router: ^14.2.0 + url_launcher: ^6.1.10 + flutter_custom_tabs: ^1.0.4 + + # Utility + path: ^1.8.3 + validators: ^3.0.0 + file_picker: ^6.1.1 + transparent_image: ^2.0.1 + universal_html: ^2.2.4 + collection: ^1.17.0 + + # Device and System + local_auth: ^2.1.6 + permission_handler: ^11.3.0 + package_info_plus: ^8.0.0 + open_app_file: ^4.0.2 + wakelock_plus: ^1.1.4 + screen_brightness: ^0.2.2+1 + window_manager: ^0.3.9 + smtc_windows: ^0.1.1 + background_downloader: ^8.5.2 + + # Data + isar: ^4.0.0-dev.14 + isar_flutter_libs: ^4.0.0-dev.14 # contains Isar Core + + # Other + async: ^2.10.0 + xid: ^1.0.12 + desktop_drop: 0.4.3 + flexible_scrollbar: ^0.1.3 + flutter_typeahead: ^5.0.2 + share_plus: ^7.1.0 + archive: ^3.4.10 + dart_mappable: ^4.2.2 + reorderable_grid: ^1.0.10 + +dev_dependencies: + flutter_test: + sdk: flutter + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^3.0.0 + build_runner: ^2.4.11 + chopper_generator: ^7.4.0 + json_serializable: ^6.8.0 + custom_lint: ^0.6.4 + freezed: ^2.5.2 + swagger_dart_code_generator: ^2.15.2 + riverpod_generator: ^2.4.0 + dart_mappable_builder: ^4.2.3 + +flutter: + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + generate: true + + assets: + - icons/ + - assets/fonts/ + + fonts: + - family: mp-font + fonts: + - asset: assets/fonts/mp-font.ttf diff --git a/snap/gui/app_icon.desktop b/snap/gui/app_icon.desktop new file mode 100644 index 0000000..92a01f6 --- /dev/null +++ b/snap/gui/app_icon.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Name=Flutter Linux App +Comment=Flutter Linux launcher icon +Exec=app_icon +Icon=app_icon.png +Terminal=false +Type=Application +Categories=Entertainment; diff --git a/snap/gui/app_icon.png b/snap/gui/app_icon.png new file mode 100644 index 0000000..5a0e4b5 Binary files /dev/null and b/snap/gui/app_icon.png differ diff --git a/swagger/jellyfin-open-api.json b/swagger/jellyfin-open-api.json new file mode 100644 index 0000000..15efa10 --- /dev/null +++ b/swagger/jellyfin-open-api.json @@ -0,0 +1,58320 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "Jellyfin API", + "version": "10.9.7", + "x-jellyfin-version": "10.9.7" + }, + "paths": { + "/System/ActivityLog/Entries": { + "get": { + "tags": ["ActivityLog"], + "summary": "Gets activity log entries.", + "operationId": "GetLogEntries", + "parameters": [ + { + "name": "startIndex", + "in": "query", + "description": "Optional. The record index to start at. All items with a lower index will be dropped from the results.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "minDate", + "in": "query", + "description": "Optional. The minimum date. Format = ISO.", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "hasUserId", + "in": "query", + "description": "Optional. Filter log entries if it has user id, or not.", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Activity log returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ActivityLogEntryQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ActivityLogEntryQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ActivityLogEntryQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Auth/Keys": { + "get": { + "tags": ["ApiKey"], + "summary": "Get all keys.", + "operationId": "GetKeys", + "responses": { + "200": { + "description": "Api keys retrieved.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthenticationInfoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/AuthenticationInfoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/AuthenticationInfoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + }, + "post": { + "tags": ["ApiKey"], + "summary": "Create a new api key.", + "operationId": "CreateKey", + "parameters": [ + { + "name": "app", + "in": "query", + "description": "Name of the app using the authentication key.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Api key created." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Auth/Keys/{key}": { + "delete": { + "tags": ["ApiKey"], + "summary": "Remove an api key.", + "operationId": "RevokeKey", + "parameters": [ + { + "name": "key", + "in": "path", + "description": "The access token to delete.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Api key deleted." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Artists": { + "get": { + "tags": ["Artists"], + "summary": "Gets all artists from a given item, folder, or the entire library.", + "operationId": "GetArtists", + "parameters": [ + { + "name": "minCommunityRating", + "in": "query", + "description": "Optional filter by minimum community rating.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "startIndex", + "in": "query", + "description": "Optional. The record index to start at. All items with a lower index will be dropped from the results.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "searchTerm", + "in": "query", + "description": "Optional. Search term.", + "schema": { + "type": "string" + } + }, + { + "name": "parentId", + "in": "query", + "description": "Specify this to localize the search to a specific item or folder. Omit to use the root.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "excludeItemTypes", + "in": "query", + "description": "Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemKind" + } + } + }, + { + "name": "includeItemTypes", + "in": "query", + "description": "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemKind" + } + } + }, + { + "name": "filters", + "in": "query", + "description": "Optional. Specify additional filters to apply.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFilter" + } + } + }, + { + "name": "isFavorite", + "in": "query", + "description": "Optional filter by items that are marked as favorite, or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "mediaTypes", + "in": "query", + "description": "Optional filter by MediaType. Allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MediaType" + } + } + }, + { + "name": "genres", + "in": "query", + "description": "Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "genreIds", + "in": "query", + "description": "Optional. If specified, results will be filtered based on genre id. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "officialRatings", + "in": "query", + "description": "Optional. If specified, results will be filtered based on OfficialRating. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "tags", + "in": "query", + "description": "Optional. If specified, results will be filtered based on tag. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "years", + "in": "query", + "description": "Optional. If specified, results will be filtered based on production year. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + }, + { + "name": "enableUserData", + "in": "query", + "description": "Optional, include user data.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional, the max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + }, + { + "name": "person", + "in": "query", + "description": "Optional. If specified, results will be filtered to include only those containing the specified person.", + "schema": { + "type": "string" + } + }, + { + "name": "personIds", + "in": "query", + "description": "Optional. If specified, results will be filtered to include only those containing the specified person ids.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "personTypes", + "in": "query", + "description": "Optional. If specified, along with Person, results will be filtered to include only those containing the specified person and PersonType. Allows multiple, comma-delimited.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "studios", + "in": "query", + "description": "Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "studioIds", + "in": "query", + "description": "Optional. If specified, results will be filtered based on studio id. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "userId", + "in": "query", + "description": "User id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "nameStartsWithOrGreater", + "in": "query", + "description": "Optional filter by items whose name is sorted equally or greater than a given input string.", + "schema": { + "type": "string" + } + }, + { + "name": "nameStartsWith", + "in": "query", + "description": "Optional filter by items whose name is sorted equally than a given input string.", + "schema": { + "type": "string" + } + }, + { + "name": "nameLessThan", + "in": "query", + "description": "Optional filter by items whose name is equally or lesser than a given input string.", + "schema": { + "type": "string" + } + }, + { + "name": "sortBy", + "in": "query", + "description": "Optional. Specify one or more sort orders, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemSortBy" + } + } + }, + { + "name": "sortOrder", + "in": "query", + "description": "Sort Order - Ascending,Descending.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SortOrder" + } + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional, include image information in output.", + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "enableTotalRecordCount", + "in": "query", + "description": "Total record count.", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Artists returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Artists/{name}": { + "get": { + "tags": ["Artists"], + "summary": "Gets an artist by name.", + "operationId": "GetArtistByName", + "parameters": [ + { + "name": "name", + "in": "path", + "description": "Studio name.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user id, and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Artist returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Artists/AlbumArtists": { + "get": { + "tags": ["Artists"], + "summary": "Gets all album artists from a given item, folder, or the entire library.", + "operationId": "GetAlbumArtists", + "parameters": [ + { + "name": "minCommunityRating", + "in": "query", + "description": "Optional filter by minimum community rating.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "startIndex", + "in": "query", + "description": "Optional. The record index to start at. All items with a lower index will be dropped from the results.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "searchTerm", + "in": "query", + "description": "Optional. Search term.", + "schema": { + "type": "string" + } + }, + { + "name": "parentId", + "in": "query", + "description": "Specify this to localize the search to a specific item or folder. Omit to use the root.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "excludeItemTypes", + "in": "query", + "description": "Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemKind" + } + } + }, + { + "name": "includeItemTypes", + "in": "query", + "description": "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemKind" + } + } + }, + { + "name": "filters", + "in": "query", + "description": "Optional. Specify additional filters to apply.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFilter" + } + } + }, + { + "name": "isFavorite", + "in": "query", + "description": "Optional filter by items that are marked as favorite, or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "mediaTypes", + "in": "query", + "description": "Optional filter by MediaType. Allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MediaType" + } + } + }, + { + "name": "genres", + "in": "query", + "description": "Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "genreIds", + "in": "query", + "description": "Optional. If specified, results will be filtered based on genre id. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "officialRatings", + "in": "query", + "description": "Optional. If specified, results will be filtered based on OfficialRating. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "tags", + "in": "query", + "description": "Optional. If specified, results will be filtered based on tag. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "years", + "in": "query", + "description": "Optional. If specified, results will be filtered based on production year. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + }, + { + "name": "enableUserData", + "in": "query", + "description": "Optional, include user data.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional, the max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + }, + { + "name": "person", + "in": "query", + "description": "Optional. If specified, results will be filtered to include only those containing the specified person.", + "schema": { + "type": "string" + } + }, + { + "name": "personIds", + "in": "query", + "description": "Optional. If specified, results will be filtered to include only those containing the specified person ids.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "personTypes", + "in": "query", + "description": "Optional. If specified, along with Person, results will be filtered to include only those containing the specified person and PersonType. Allows multiple, comma-delimited.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "studios", + "in": "query", + "description": "Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "studioIds", + "in": "query", + "description": "Optional. If specified, results will be filtered based on studio id. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "userId", + "in": "query", + "description": "User id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "nameStartsWithOrGreater", + "in": "query", + "description": "Optional filter by items whose name is sorted equally or greater than a given input string.", + "schema": { + "type": "string" + } + }, + { + "name": "nameStartsWith", + "in": "query", + "description": "Optional filter by items whose name is sorted equally than a given input string.", + "schema": { + "type": "string" + } + }, + { + "name": "nameLessThan", + "in": "query", + "description": "Optional filter by items whose name is equally or lesser than a given input string.", + "schema": { + "type": "string" + } + }, + { + "name": "sortBy", + "in": "query", + "description": "Optional. Specify one or more sort orders, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemSortBy" + } + } + }, + { + "name": "sortOrder", + "in": "query", + "description": "Sort Order - Ascending,Descending.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SortOrder" + } + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional, include image information in output.", + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "enableTotalRecordCount", + "in": "query", + "description": "Total record count.", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Album artists returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Audio/{itemId}/stream": { + "get": { + "tags": ["Audio"], + "summary": "Gets an audio stream.", + "operationId": "GetAudioStream", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "container", + "in": "query", + "description": "The audio container.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "static", + "in": "query", + "description": "Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "params", + "in": "query", + "description": "The streaming parameters.", + "schema": { + "type": "string" + } + }, + { + "name": "tag", + "in": "query", + "description": "The tag.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceProfileId", + "in": "query", + "description": "Optional. The dlna device profile id to utilize.", + "deprecated": true, + "schema": { + "type": "string" + } + }, + { + "name": "playSessionId", + "in": "query", + "description": "The play session id.", + "schema": { + "type": "string" + } + }, + { + "name": "segmentContainer", + "in": "query", + "description": "The segment container.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "segmentLength", + "in": "query", + "description": "The segment length.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "minSegments", + "in": "query", + "description": "The minimum number of segments.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "The media version id, if playing an alternate version.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "The device id of the client requesting. Used to stop encoding processes when needed.", + "schema": { + "type": "string" + } + }, + { + "name": "audioCodec", + "in": "query", + "description": "Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "enableAutoStreamCopy", + "in": "query", + "description": "Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowVideoStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the video stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowAudioStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the audio stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "breakOnNonKeyFrames", + "in": "query", + "description": "Optional. Whether to break on non key frames.", + "schema": { + "type": "boolean" + } + }, + { + "name": "audioSampleRate", + "in": "query", + "description": "Optional. Specify a specific audio sample rate, e.g. 44100.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioBitDepth", + "in": "query", + "description": "Optional. The maximum audio bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioBitRate", + "in": "query", + "description": "Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioChannels", + "in": "query", + "description": "Optional. Specify a specific number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioChannels", + "in": "query", + "description": "Optional. Specify a maximum number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "profile", + "in": "query", + "description": "Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high.", + "schema": { + "type": "string" + } + }, + { + "name": "level", + "in": "query", + "description": "Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1.", + "schema": { + "type": "string" + } + }, + { + "name": "framerate", + "in": "query", + "description": "Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "maxFramerate", + "in": "query", + "description": "Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "copyTimestamps", + "in": "query", + "description": "Whether or not to copy timestamps when transcoding with an offset. Defaults to false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "startTimeTicks", + "in": "query", + "description": "Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "width", + "in": "query", + "description": "Optional. The fixed horizontal resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "Optional. The fixed vertical resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoBitRate", + "in": "query", + "description": "Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleStreamIndex", + "in": "query", + "description": "Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleMethod", + "in": "query", + "description": "Optional. Specify the subtitle delivery method.", + "schema": { + "enum": ["Encode", "Embed", "External", "Hls", "Drop"], + "allOf": [ + { + "$ref": "#/components/schemas/SubtitleDeliveryMethod" + } + ] + } + }, + { + "name": "maxRefFrames", + "in": "query", + "description": "Optional.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxVideoBitDepth", + "in": "query", + "description": "Optional. The maximum video bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "requireAvc", + "in": "query", + "description": "Optional. Whether to require avc.", + "schema": { + "type": "boolean" + } + }, + { + "name": "deInterlace", + "in": "query", + "description": "Optional. Whether to deinterlace the video.", + "schema": { + "type": "boolean" + } + }, + { + "name": "requireNonAnamorphic", + "in": "query", + "description": "Optional. Whether to require a non anamorphic stream.", + "schema": { + "type": "boolean" + } + }, + { + "name": "transcodingMaxAudioChannels", + "in": "query", + "description": "Optional. The maximum number of audio channels to transcode.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "cpuCoreLimit", + "in": "query", + "description": "Optional. The limit of how many cpu cores to use.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "liveStreamId", + "in": "query", + "description": "The live stream id.", + "schema": { + "type": "string" + } + }, + { + "name": "enableMpegtsM2TsMode", + "in": "query", + "description": "Optional. Whether to enable the MpegtsM2Ts mode.", + "schema": { + "type": "boolean" + } + }, + { + "name": "videoCodec", + "in": "query", + "description": "Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "subtitleCodec", + "in": "query", + "description": "Optional. Specify a subtitle codec to encode to.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "transcodeReasons", + "in": "query", + "description": "Optional. The transcoding reason.", + "schema": { + "type": "string" + } + }, + { + "name": "audioStreamIndex", + "in": "query", + "description": "Optional. The index of the audio stream to use. If omitted the first audio stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoStreamIndex", + "in": "query", + "description": "Optional. The index of the video stream to use. If omitted the first video stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "context", + "in": "query", + "description": "Optional. The MediaBrowser.Model.Dlna.EncodingContext.", + "schema": { + "enum": ["Streaming", "Static"], + "allOf": [ + { + "$ref": "#/components/schemas/EncodingContext" + } + ] + } + }, + { + "name": "streamOptions", + "in": "query", + "description": "Optional. The streaming options.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + } + } + } + ], + "responses": { + "200": { + "description": "Audio stream returned.", + "content": { + "audio/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + } + } + }, + "head": { + "tags": ["Audio"], + "summary": "Gets an audio stream.", + "operationId": "HeadAudioStream", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "container", + "in": "query", + "description": "The audio container.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "static", + "in": "query", + "description": "Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "params", + "in": "query", + "description": "The streaming parameters.", + "schema": { + "type": "string" + } + }, + { + "name": "tag", + "in": "query", + "description": "The tag.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceProfileId", + "in": "query", + "description": "Optional. The dlna device profile id to utilize.", + "deprecated": true, + "schema": { + "type": "string" + } + }, + { + "name": "playSessionId", + "in": "query", + "description": "The play session id.", + "schema": { + "type": "string" + } + }, + { + "name": "segmentContainer", + "in": "query", + "description": "The segment container.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "segmentLength", + "in": "query", + "description": "The segment length.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "minSegments", + "in": "query", + "description": "The minimum number of segments.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "The media version id, if playing an alternate version.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "The device id of the client requesting. Used to stop encoding processes when needed.", + "schema": { + "type": "string" + } + }, + { + "name": "audioCodec", + "in": "query", + "description": "Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "enableAutoStreamCopy", + "in": "query", + "description": "Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowVideoStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the video stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowAudioStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the audio stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "breakOnNonKeyFrames", + "in": "query", + "description": "Optional. Whether to break on non key frames.", + "schema": { + "type": "boolean" + } + }, + { + "name": "audioSampleRate", + "in": "query", + "description": "Optional. Specify a specific audio sample rate, e.g. 44100.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioBitDepth", + "in": "query", + "description": "Optional. The maximum audio bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioBitRate", + "in": "query", + "description": "Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioChannels", + "in": "query", + "description": "Optional. Specify a specific number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioChannels", + "in": "query", + "description": "Optional. Specify a maximum number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "profile", + "in": "query", + "description": "Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high.", + "schema": { + "type": "string" + } + }, + { + "name": "level", + "in": "query", + "description": "Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1.", + "schema": { + "type": "string" + } + }, + { + "name": "framerate", + "in": "query", + "description": "Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "maxFramerate", + "in": "query", + "description": "Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "copyTimestamps", + "in": "query", + "description": "Whether or not to copy timestamps when transcoding with an offset. Defaults to false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "startTimeTicks", + "in": "query", + "description": "Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "width", + "in": "query", + "description": "Optional. The fixed horizontal resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "Optional. The fixed vertical resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoBitRate", + "in": "query", + "description": "Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleStreamIndex", + "in": "query", + "description": "Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleMethod", + "in": "query", + "description": "Optional. Specify the subtitle delivery method.", + "schema": { + "enum": ["Encode", "Embed", "External", "Hls", "Drop"], + "allOf": [ + { + "$ref": "#/components/schemas/SubtitleDeliveryMethod" + } + ] + } + }, + { + "name": "maxRefFrames", + "in": "query", + "description": "Optional.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxVideoBitDepth", + "in": "query", + "description": "Optional. The maximum video bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "requireAvc", + "in": "query", + "description": "Optional. Whether to require avc.", + "schema": { + "type": "boolean" + } + }, + { + "name": "deInterlace", + "in": "query", + "description": "Optional. Whether to deinterlace the video.", + "schema": { + "type": "boolean" + } + }, + { + "name": "requireNonAnamorphic", + "in": "query", + "description": "Optional. Whether to require a non anamorphic stream.", + "schema": { + "type": "boolean" + } + }, + { + "name": "transcodingMaxAudioChannels", + "in": "query", + "description": "Optional. The maximum number of audio channels to transcode.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "cpuCoreLimit", + "in": "query", + "description": "Optional. The limit of how many cpu cores to use.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "liveStreamId", + "in": "query", + "description": "The live stream id.", + "schema": { + "type": "string" + } + }, + { + "name": "enableMpegtsM2TsMode", + "in": "query", + "description": "Optional. Whether to enable the MpegtsM2Ts mode.", + "schema": { + "type": "boolean" + } + }, + { + "name": "videoCodec", + "in": "query", + "description": "Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "subtitleCodec", + "in": "query", + "description": "Optional. Specify a subtitle codec to encode to.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "transcodeReasons", + "in": "query", + "description": "Optional. The transcoding reason.", + "schema": { + "type": "string" + } + }, + { + "name": "audioStreamIndex", + "in": "query", + "description": "Optional. The index of the audio stream to use. If omitted the first audio stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoStreamIndex", + "in": "query", + "description": "Optional. The index of the video stream to use. If omitted the first video stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "context", + "in": "query", + "description": "Optional. The MediaBrowser.Model.Dlna.EncodingContext.", + "schema": { + "enum": ["Streaming", "Static"], + "allOf": [ + { + "$ref": "#/components/schemas/EncodingContext" + } + ] + } + }, + { + "name": "streamOptions", + "in": "query", + "description": "Optional. The streaming options.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + } + } + } + ], + "responses": { + "200": { + "description": "Audio stream returned.", + "content": { + "audio/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + } + } + } + }, + "/Audio/{itemId}/stream.{container}": { + "get": { + "tags": ["Audio"], + "summary": "Gets an audio stream.", + "operationId": "GetAudioStreamByContainer", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "container", + "in": "path", + "description": "The audio container.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "static", + "in": "query", + "description": "Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "params", + "in": "query", + "description": "The streaming parameters.", + "schema": { + "type": "string" + } + }, + { + "name": "tag", + "in": "query", + "description": "The tag.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceProfileId", + "in": "query", + "description": "Optional. The dlna device profile id to utilize.", + "deprecated": true, + "schema": { + "type": "string" + } + }, + { + "name": "playSessionId", + "in": "query", + "description": "The play session id.", + "schema": { + "type": "string" + } + }, + { + "name": "segmentContainer", + "in": "query", + "description": "The segment container.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "segmentLength", + "in": "query", + "description": "The segment length.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "minSegments", + "in": "query", + "description": "The minimum number of segments.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "The media version id, if playing an alternate version.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "The device id of the client requesting. Used to stop encoding processes when needed.", + "schema": { + "type": "string" + } + }, + { + "name": "audioCodec", + "in": "query", + "description": "Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "enableAutoStreamCopy", + "in": "query", + "description": "Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowVideoStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the video stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowAudioStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the audio stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "breakOnNonKeyFrames", + "in": "query", + "description": "Optional. Whether to break on non key frames.", + "schema": { + "type": "boolean" + } + }, + { + "name": "audioSampleRate", + "in": "query", + "description": "Optional. Specify a specific audio sample rate, e.g. 44100.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioBitDepth", + "in": "query", + "description": "Optional. The maximum audio bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioBitRate", + "in": "query", + "description": "Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioChannels", + "in": "query", + "description": "Optional. Specify a specific number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioChannels", + "in": "query", + "description": "Optional. Specify a maximum number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "profile", + "in": "query", + "description": "Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high.", + "schema": { + "type": "string" + } + }, + { + "name": "level", + "in": "query", + "description": "Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1.", + "schema": { + "type": "string" + } + }, + { + "name": "framerate", + "in": "query", + "description": "Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "maxFramerate", + "in": "query", + "description": "Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "copyTimestamps", + "in": "query", + "description": "Whether or not to copy timestamps when transcoding with an offset. Defaults to false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "startTimeTicks", + "in": "query", + "description": "Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "width", + "in": "query", + "description": "Optional. The fixed horizontal resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "Optional. The fixed vertical resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoBitRate", + "in": "query", + "description": "Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleStreamIndex", + "in": "query", + "description": "Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleMethod", + "in": "query", + "description": "Optional. Specify the subtitle delivery method.", + "schema": { + "enum": ["Encode", "Embed", "External", "Hls", "Drop"], + "allOf": [ + { + "$ref": "#/components/schemas/SubtitleDeliveryMethod" + } + ] + } + }, + { + "name": "maxRefFrames", + "in": "query", + "description": "Optional.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxVideoBitDepth", + "in": "query", + "description": "Optional. The maximum video bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "requireAvc", + "in": "query", + "description": "Optional. Whether to require avc.", + "schema": { + "type": "boolean" + } + }, + { + "name": "deInterlace", + "in": "query", + "description": "Optional. Whether to deinterlace the video.", + "schema": { + "type": "boolean" + } + }, + { + "name": "requireNonAnamorphic", + "in": "query", + "description": "Optional. Whether to require a non anamporphic stream.", + "schema": { + "type": "boolean" + } + }, + { + "name": "transcodingMaxAudioChannels", + "in": "query", + "description": "Optional. The maximum number of audio channels to transcode.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "cpuCoreLimit", + "in": "query", + "description": "Optional. The limit of how many cpu cores to use.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "liveStreamId", + "in": "query", + "description": "The live stream id.", + "schema": { + "type": "string" + } + }, + { + "name": "enableMpegtsM2TsMode", + "in": "query", + "description": "Optional. Whether to enable the MpegtsM2Ts mode.", + "schema": { + "type": "boolean" + } + }, + { + "name": "videoCodec", + "in": "query", + "description": "Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "subtitleCodec", + "in": "query", + "description": "Optional. Specify a subtitle codec to encode to.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "transcodeReasons", + "in": "query", + "description": "Optional. The transcoding reason.", + "schema": { + "type": "string" + } + }, + { + "name": "audioStreamIndex", + "in": "query", + "description": "Optional. The index of the audio stream to use. If omitted the first audio stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoStreamIndex", + "in": "query", + "description": "Optional. The index of the video stream to use. If omitted the first video stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "context", + "in": "query", + "description": "Optional. The MediaBrowser.Model.Dlna.EncodingContext.", + "schema": { + "enum": ["Streaming", "Static"], + "allOf": [ + { + "$ref": "#/components/schemas/EncodingContext" + } + ] + } + }, + { + "name": "streamOptions", + "in": "query", + "description": "Optional. The streaming options.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + } + } + } + ], + "responses": { + "200": { + "description": "Audio stream returned.", + "content": { + "audio/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + } + } + }, + "head": { + "tags": ["Audio"], + "summary": "Gets an audio stream.", + "operationId": "HeadAudioStreamByContainer", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "container", + "in": "path", + "description": "The audio container.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "static", + "in": "query", + "description": "Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "params", + "in": "query", + "description": "The streaming parameters.", + "schema": { + "type": "string" + } + }, + { + "name": "tag", + "in": "query", + "description": "The tag.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceProfileId", + "in": "query", + "description": "Optional. The dlna device profile id to utilize.", + "deprecated": true, + "schema": { + "type": "string" + } + }, + { + "name": "playSessionId", + "in": "query", + "description": "The play session id.", + "schema": { + "type": "string" + } + }, + { + "name": "segmentContainer", + "in": "query", + "description": "The segment container.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "segmentLength", + "in": "query", + "description": "The segment length.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "minSegments", + "in": "query", + "description": "The minimum number of segments.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "The media version id, if playing an alternate version.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "The device id of the client requesting. Used to stop encoding processes when needed.", + "schema": { + "type": "string" + } + }, + { + "name": "audioCodec", + "in": "query", + "description": "Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "enableAutoStreamCopy", + "in": "query", + "description": "Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowVideoStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the video stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowAudioStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the audio stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "breakOnNonKeyFrames", + "in": "query", + "description": "Optional. Whether to break on non key frames.", + "schema": { + "type": "boolean" + } + }, + { + "name": "audioSampleRate", + "in": "query", + "description": "Optional. Specify a specific audio sample rate, e.g. 44100.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioBitDepth", + "in": "query", + "description": "Optional. The maximum audio bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioBitRate", + "in": "query", + "description": "Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioChannels", + "in": "query", + "description": "Optional. Specify a specific number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioChannels", + "in": "query", + "description": "Optional. Specify a maximum number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "profile", + "in": "query", + "description": "Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high.", + "schema": { + "type": "string" + } + }, + { + "name": "level", + "in": "query", + "description": "Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1.", + "schema": { + "type": "string" + } + }, + { + "name": "framerate", + "in": "query", + "description": "Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "maxFramerate", + "in": "query", + "description": "Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "copyTimestamps", + "in": "query", + "description": "Whether or not to copy timestamps when transcoding with an offset. Defaults to false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "startTimeTicks", + "in": "query", + "description": "Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "width", + "in": "query", + "description": "Optional. The fixed horizontal resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "Optional. The fixed vertical resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoBitRate", + "in": "query", + "description": "Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleStreamIndex", + "in": "query", + "description": "Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleMethod", + "in": "query", + "description": "Optional. Specify the subtitle delivery method.", + "schema": { + "enum": ["Encode", "Embed", "External", "Hls", "Drop"], + "allOf": [ + { + "$ref": "#/components/schemas/SubtitleDeliveryMethod" + } + ] + } + }, + { + "name": "maxRefFrames", + "in": "query", + "description": "Optional.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxVideoBitDepth", + "in": "query", + "description": "Optional. The maximum video bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "requireAvc", + "in": "query", + "description": "Optional. Whether to require avc.", + "schema": { + "type": "boolean" + } + }, + { + "name": "deInterlace", + "in": "query", + "description": "Optional. Whether to deinterlace the video.", + "schema": { + "type": "boolean" + } + }, + { + "name": "requireNonAnamorphic", + "in": "query", + "description": "Optional. Whether to require a non anamporphic stream.", + "schema": { + "type": "boolean" + } + }, + { + "name": "transcodingMaxAudioChannels", + "in": "query", + "description": "Optional. The maximum number of audio channels to transcode.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "cpuCoreLimit", + "in": "query", + "description": "Optional. The limit of how many cpu cores to use.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "liveStreamId", + "in": "query", + "description": "The live stream id.", + "schema": { + "type": "string" + } + }, + { + "name": "enableMpegtsM2TsMode", + "in": "query", + "description": "Optional. Whether to enable the MpegtsM2Ts mode.", + "schema": { + "type": "boolean" + } + }, + { + "name": "videoCodec", + "in": "query", + "description": "Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "subtitleCodec", + "in": "query", + "description": "Optional. Specify a subtitle codec to encode to.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "transcodeReasons", + "in": "query", + "description": "Optional. The transcoding reason.", + "schema": { + "type": "string" + } + }, + { + "name": "audioStreamIndex", + "in": "query", + "description": "Optional. The index of the audio stream to use. If omitted the first audio stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoStreamIndex", + "in": "query", + "description": "Optional. The index of the video stream to use. If omitted the first video stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "context", + "in": "query", + "description": "Optional. The MediaBrowser.Model.Dlna.EncodingContext.", + "schema": { + "enum": ["Streaming", "Static"], + "allOf": [ + { + "$ref": "#/components/schemas/EncodingContext" + } + ] + } + }, + { + "name": "streamOptions", + "in": "query", + "description": "Optional. The streaming options.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + } + } + } + ], + "responses": { + "200": { + "description": "Audio stream returned.", + "content": { + "audio/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + } + } + } + }, + "/Branding/Configuration": { + "get": { + "tags": ["Branding"], + "summary": "Gets branding configuration.", + "operationId": "GetBrandingOptions", + "responses": { + "200": { + "description": "Branding configuration returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BrandingOptions" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BrandingOptions" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BrandingOptions" + } + } + } + } + } + } + }, + "/Branding/Css": { + "get": { + "tags": ["Branding"], + "summary": "Gets branding css.", + "operationId": "GetBrandingCss", + "responses": { + "200": { + "description": "Branding css returned.", + "content": { + "text/css": { + "schema": { + "type": "string" + } + }, + "application/json": { + "schema": { + "type": "string" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "string" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "string" + } + } + } + }, + "204": { + "description": "No branding css configured." + } + } + } + }, + "/Branding/Css.css": { + "get": { + "tags": ["Branding"], + "summary": "Gets branding css.", + "operationId": "GetBrandingCss_2", + "responses": { + "200": { + "description": "Branding css returned.", + "content": { + "text/css": { + "schema": { + "type": "string" + } + }, + "application/json": { + "schema": { + "type": "string" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "string" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "string" + } + } + } + }, + "204": { + "description": "No branding css configured." + } + } + } + }, + "/Channels": { + "get": { + "tags": ["Channels"], + "summary": "Gets available channels.", + "operationId": "GetChannels", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "User Id to filter by. Use System.Guid.Empty to not filter by user.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "startIndex", + "in": "query", + "description": "Optional. The record index to start at. All items with a lower index will be dropped from the results.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "supportsLatestItems", + "in": "query", + "description": "Optional. Filter by channels that support getting latest items.", + "schema": { + "type": "boolean" + } + }, + { + "name": "supportsMediaDeletion", + "in": "query", + "description": "Optional. Filter by channels that support media deletion.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isFavorite", + "in": "query", + "description": "Optional. Filter by channels that are favorite.", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Channels returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Channels/{channelId}/Features": { + "get": { + "tags": ["Channels"], + "summary": "Get channel features.", + "operationId": "GetChannelFeatures", + "parameters": [ + { + "name": "channelId", + "in": "path", + "description": "Channel id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Channel features returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChannelFeatures" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ChannelFeatures" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ChannelFeatures" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Channels/{channelId}/Items": { + "get": { + "tags": ["Channels"], + "summary": "Get channel items.", + "operationId": "GetChannelItems", + "parameters": [ + { + "name": "channelId", + "in": "path", + "description": "Channel Id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "folderId", + "in": "query", + "description": "Optional. Folder Id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. User Id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "startIndex", + "in": "query", + "description": "Optional. The record index to start at. All items with a lower index will be dropped from the results.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "sortOrder", + "in": "query", + "description": "Optional. Sort Order - Ascending,Descending.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SortOrder" + } + } + }, + { + "name": "filters", + "in": "query", + "description": "Optional. Specify additional filters to apply.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFilter" + } + } + }, + { + "name": "sortBy", + "in": "query", + "description": "Optional. Specify one or more sort orders, comma delimited. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemSortBy" + } + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + } + ], + "responses": { + "200": { + "description": "Channel items returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Channels/Features": { + "get": { + "tags": ["Channels"], + "summary": "Get all channel features.", + "operationId": "GetAllChannelFeatures", + "responses": { + "200": { + "description": "All channel features returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ChannelFeatures" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ChannelFeatures" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ChannelFeatures" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Channels/Items/Latest": { + "get": { + "tags": ["Channels"], + "summary": "Gets latest channel items.", + "operationId": "GetLatestChannelItems", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "Optional. User Id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "startIndex", + "in": "query", + "description": "Optional. The record index to start at. All items with a lower index will be dropped from the results.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "filters", + "in": "query", + "description": "Optional. Specify additional filters to apply.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFilter" + } + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "channelIds", + "in": "query", + "description": "Optional. Specify one or more channel id's, comma delimited.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + } + ], + "responses": { + "200": { + "description": "Latest channel items returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/ClientLog/Document": { + "post": { + "tags": ["ClientLog"], + "summary": "Upload a document.", + "operationId": "LogFile", + "requestBody": { + "content": { + "text/plain": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "responses": { + "200": { + "description": "Document saved.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClientLogDocumentResponseDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ClientLogDocumentResponseDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ClientLogDocumentResponseDto" + } + } + } + }, + "403": { + "description": "Event logging disabled.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "413": { + "description": "Upload size too large.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Collections": { + "post": { + "tags": ["Collection"], + "summary": "Creates a new collection.", + "operationId": "CreateCollection", + "parameters": [ + { + "name": "name", + "in": "query", + "description": "The name of the collection.", + "schema": { + "type": "string" + } + }, + { + "name": "ids", + "in": "query", + "description": "Item Ids to add to the collection.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "parentId", + "in": "query", + "description": "Optional. Create the collection within a specific folder.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "isLocked", + "in": "query", + "description": "Whether or not to lock the new collection.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Collection created.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CollectionCreationResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/CollectionCreationResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/CollectionCreationResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "CollectionManagement", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Collections/{collectionId}/Items": { + "post": { + "tags": ["Collection"], + "summary": "Adds items to a collection.", + "operationId": "AddToCollection", + "parameters": [ + { + "name": "collectionId", + "in": "path", + "description": "The collection id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "ids", + "in": "query", + "description": "Item ids, comma delimited.", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + } + ], + "responses": { + "204": { + "description": "Items added to collection." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "CollectionManagement", + "DefaultAuthorization" + ] + } + ] + }, + "delete": { + "tags": ["Collection"], + "summary": "Removes items from a collection.", + "operationId": "RemoveFromCollection", + "parameters": [ + { + "name": "collectionId", + "in": "path", + "description": "The collection id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "ids", + "in": "query", + "description": "Item ids, comma delimited.", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + } + ], + "responses": { + "204": { + "description": "Items removed from collection." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "CollectionManagement", + "DefaultAuthorization" + ] + } + ] + } + }, + "/System/Configuration": { + "get": { + "tags": ["Configuration"], + "summary": "Gets application configuration.", + "operationId": "GetConfiguration", + "responses": { + "200": { + "description": "Application configuration returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServerConfiguration" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ServerConfiguration" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ServerConfiguration" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + }, + "post": { + "tags": ["Configuration"], + "summary": "Updates application configuration.", + "operationId": "UpdateConfiguration", + "requestBody": { + "description": "Configuration.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ServerConfiguration" + } + ], + "description": "Represents the server configuration." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ServerConfiguration" + } + ], + "description": "Represents the server configuration." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ServerConfiguration" + } + ], + "description": "Represents the server configuration." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Configuration updated." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "RequiresElevation", + "DefaultAuthorization" + ] + } + ] + } + }, + "/System/Configuration/{key}": { + "get": { + "tags": ["Configuration"], + "summary": "Gets a named configuration.", + "operationId": "GetNamedConfiguration", + "parameters": [ + { + "name": "key", + "in": "path", + "description": "Configuration key.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Configuration returned.", + "content": { + "application/json": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + }, + "post": { + "tags": ["Configuration"], + "summary": "Updates named configuration.", + "operationId": "UpdateNamedConfiguration", + "parameters": [ + { + "name": "key", + "in": "path", + "description": "Configuration key.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "Configuration.", + "content": { + "application/json": { + "schema": {} + }, + "text/json": { + "schema": {} + }, + "application/*+json": { + "schema": {} + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Named configuration updated." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "RequiresElevation", + "DefaultAuthorization" + ] + } + ] + } + }, + "/System/Configuration/MetadataOptions/Default": { + "get": { + "tags": ["Configuration"], + "summary": "Gets a default MetadataOptions object.", + "operationId": "GetDefaultMetadataOptions", + "responses": { + "200": { + "description": "Metadata options returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetadataOptions" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/MetadataOptions" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/MetadataOptions" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "RequiresElevation", + "DefaultAuthorization" + ] + } + ] + } + }, + "/web/ConfigurationPage": { + "get": { + "tags": ["Dashboard"], + "summary": "Gets a dashboard configuration page.", + "operationId": "GetDashboardConfigurationPage", + "parameters": [ + { + "name": "name", + "in": "query", + "description": "The name of the page.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "ConfigurationPage returned.", + "content": { + "text/html": { + "schema": { + "type": "string", + "format": "binary" + } + }, + "application/x-javascript": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Plugin configuration page not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + } + }, + "/web/ConfigurationPages": { + "get": { + "tags": ["Dashboard"], + "summary": "Gets the configuration pages.", + "operationId": "GetConfigurationPages", + "parameters": [ + { + "name": "enableInMainMenu", + "in": "query", + "description": "Whether to enable in the main menu.", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "ConfigurationPages returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConfigurationPageInfo" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConfigurationPageInfo" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConfigurationPageInfo" + } + } + } + } + }, + "404": { + "description": "Server still loading.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Devices": { + "get": { + "tags": ["Devices"], + "summary": "Get Devices.", + "operationId": "GetDevices", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "Gets or sets the user identifier.", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Devices retrieved.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeviceInfoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/DeviceInfoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/DeviceInfoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + }, + "delete": { + "tags": ["Devices"], + "summary": "Deletes a device.", + "operationId": "DeleteDevice", + "parameters": [ + { + "name": "id", + "in": "query", + "description": "Device Id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Device deleted." + }, + "404": { + "description": "Device not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Devices/Info": { + "get": { + "tags": ["Devices"], + "summary": "Get info for a device.", + "operationId": "GetDeviceInfo", + "parameters": [ + { + "name": "id", + "in": "query", + "description": "Device Id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Device info retrieved.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeviceInfo" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/DeviceInfo" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/DeviceInfo" + } + } + } + }, + "404": { + "description": "Device not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Devices/Options": { + "get": { + "tags": ["Devices"], + "summary": "Get options for a device.", + "operationId": "GetDeviceOptions", + "parameters": [ + { + "name": "id", + "in": "query", + "description": "Device Id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Device options retrieved.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeviceOptions" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/DeviceOptions" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/DeviceOptions" + } + } + } + }, + "404": { + "description": "Device not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + }, + "post": { + "tags": ["Devices"], + "summary": "Update device options.", + "operationId": "UpdateDeviceOptions", + "parameters": [ + { + "name": "id", + "in": "query", + "description": "Device Id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "Device Options.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/DeviceOptionsDto" + } + ], + "description": "A dto representing custom options for a device." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/DeviceOptionsDto" + } + ], + "description": "A dto representing custom options for a device." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/DeviceOptionsDto" + } + ], + "description": "A dto representing custom options for a device." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Device options updated." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/DisplayPreferences/{displayPreferencesId}": { + "get": { + "tags": ["DisplayPreferences"], + "summary": "Get Display Preferences.", + "operationId": "GetDisplayPreferences", + "parameters": [ + { + "name": "displayPreferencesId", + "in": "path", + "description": "Display preferences id.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "userId", + "in": "query", + "description": "User id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "client", + "in": "query", + "description": "Client.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Display preferences retrieved.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DisplayPreferencesDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/DisplayPreferencesDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/DisplayPreferencesDto" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + }, + "post": { + "tags": ["DisplayPreferences"], + "summary": "Update Display Preferences.", + "operationId": "UpdateDisplayPreferences", + "parameters": [ + { + "name": "displayPreferencesId", + "in": "path", + "description": "Display preferences id.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "userId", + "in": "query", + "description": "User Id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "client", + "in": "query", + "description": "Client.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "New Display Preferences object.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/DisplayPreferencesDto" + } + ], + "description": "Defines the display preferences for any item that supports them (usually Folders)." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/DisplayPreferencesDto" + } + ], + "description": "Defines the display preferences for any item that supports them (usually Folders)." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/DisplayPreferencesDto" + } + ], + "description": "Defines the display preferences for any item that supports them (usually Folders)." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Display preferences updated." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Audio/{itemId}/hls1/{playlistId}/{segmentId}.{container}": { + "get": { + "tags": ["DynamicHls"], + "summary": "Gets a video stream using HTTP live streaming.", + "operationId": "GetHlsAudioSegment", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "playlistId", + "in": "path", + "description": "The playlist id.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "segmentId", + "in": "path", + "description": "The segment id.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "container", + "in": "path", + "description": "The video container. Possible values are: ts, webm, asf, wmv, ogv, mp4, m4v, mkv, mpeg, mpg, avi, 3gp, wmv, wtv, m2ts, mov, iso, flv.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "runtimeTicks", + "in": "query", + "description": "The position of the requested segment in ticks.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "actualSegmentLengthTicks", + "in": "query", + "description": "The length of the requested segment in ticks.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "static", + "in": "query", + "description": "Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "params", + "in": "query", + "description": "The streaming parameters.", + "schema": { + "type": "string" + } + }, + { + "name": "tag", + "in": "query", + "description": "The tag.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceProfileId", + "in": "query", + "description": "Optional. The dlna device profile id to utilize.", + "deprecated": true, + "schema": { + "type": "string" + } + }, + { + "name": "playSessionId", + "in": "query", + "description": "The play session id.", + "schema": { + "type": "string" + } + }, + { + "name": "segmentContainer", + "in": "query", + "description": "The segment container.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "segmentLength", + "in": "query", + "description": "The segment length.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "minSegments", + "in": "query", + "description": "The minimum number of segments.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "The media version id, if playing an alternate version.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "The device id of the client requesting. Used to stop encoding processes when needed.", + "schema": { + "type": "string" + } + }, + { + "name": "audioCodec", + "in": "query", + "description": "Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "enableAutoStreamCopy", + "in": "query", + "description": "Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowVideoStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the video stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowAudioStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the audio stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "breakOnNonKeyFrames", + "in": "query", + "description": "Optional. Whether to break on non key frames.", + "schema": { + "type": "boolean" + } + }, + { + "name": "audioSampleRate", + "in": "query", + "description": "Optional. Specify a specific audio sample rate, e.g. 44100.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioBitDepth", + "in": "query", + "description": "Optional. The maximum audio bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxStreamingBitrate", + "in": "query", + "description": "Optional. The maximum streaming bitrate.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioBitRate", + "in": "query", + "description": "Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioChannels", + "in": "query", + "description": "Optional. Specify a specific number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioChannels", + "in": "query", + "description": "Optional. Specify a maximum number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "profile", + "in": "query", + "description": "Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high.", + "schema": { + "type": "string" + } + }, + { + "name": "level", + "in": "query", + "description": "Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1.", + "schema": { + "type": "string" + } + }, + { + "name": "framerate", + "in": "query", + "description": "Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "maxFramerate", + "in": "query", + "description": "Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "copyTimestamps", + "in": "query", + "description": "Whether or not to copy timestamps when transcoding with an offset. Defaults to false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "startTimeTicks", + "in": "query", + "description": "Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "width", + "in": "query", + "description": "Optional. The fixed horizontal resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "Optional. The fixed vertical resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoBitRate", + "in": "query", + "description": "Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleStreamIndex", + "in": "query", + "description": "Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleMethod", + "in": "query", + "description": "Optional. Specify the subtitle delivery method.", + "schema": { + "enum": ["Encode", "Embed", "External", "Hls", "Drop"], + "allOf": [ + { + "$ref": "#/components/schemas/SubtitleDeliveryMethod" + } + ] + } + }, + { + "name": "maxRefFrames", + "in": "query", + "description": "Optional.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxVideoBitDepth", + "in": "query", + "description": "Optional. The maximum video bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "requireAvc", + "in": "query", + "description": "Optional. Whether to require avc.", + "schema": { + "type": "boolean" + } + }, + { + "name": "deInterlace", + "in": "query", + "description": "Optional. Whether to deinterlace the video.", + "schema": { + "type": "boolean" + } + }, + { + "name": "requireNonAnamorphic", + "in": "query", + "description": "Optional. Whether to require a non anamorphic stream.", + "schema": { + "type": "boolean" + } + }, + { + "name": "transcodingMaxAudioChannels", + "in": "query", + "description": "Optional. The maximum number of audio channels to transcode.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "cpuCoreLimit", + "in": "query", + "description": "Optional. The limit of how many cpu cores to use.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "liveStreamId", + "in": "query", + "description": "The live stream id.", + "schema": { + "type": "string" + } + }, + { + "name": "enableMpegtsM2TsMode", + "in": "query", + "description": "Optional. Whether to enable the MpegtsM2Ts mode.", + "schema": { + "type": "boolean" + } + }, + { + "name": "videoCodec", + "in": "query", + "description": "Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vpx, wmv.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "subtitleCodec", + "in": "query", + "description": "Optional. Specify a subtitle codec to encode to.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "transcodeReasons", + "in": "query", + "description": "Optional. The transcoding reason.", + "schema": { + "type": "string" + } + }, + { + "name": "audioStreamIndex", + "in": "query", + "description": "Optional. The index of the audio stream to use. If omitted the first audio stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoStreamIndex", + "in": "query", + "description": "Optional. The index of the video stream to use. If omitted the first video stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "context", + "in": "query", + "description": "Optional. The MediaBrowser.Model.Dlna.EncodingContext.", + "schema": { + "enum": ["Streaming", "Static"], + "allOf": [ + { + "$ref": "#/components/schemas/EncodingContext" + } + ] + } + }, + { + "name": "streamOptions", + "in": "query", + "description": "Optional. The streaming options.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + } + } + } + ], + "responses": { + "200": { + "description": "Video stream returned.", + "content": { + "audio/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Audio/{itemId}/main.m3u8": { + "get": { + "tags": ["DynamicHls"], + "summary": "Gets an audio stream using HTTP live streaming.", + "operationId": "GetVariantHlsAudioPlaylist", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "static", + "in": "query", + "description": "Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "params", + "in": "query", + "description": "The streaming parameters.", + "schema": { + "type": "string" + } + }, + { + "name": "tag", + "in": "query", + "description": "The tag.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceProfileId", + "in": "query", + "description": "Optional. The dlna device profile id to utilize.", + "deprecated": true, + "schema": { + "type": "string" + } + }, + { + "name": "playSessionId", + "in": "query", + "description": "The play session id.", + "schema": { + "type": "string" + } + }, + { + "name": "segmentContainer", + "in": "query", + "description": "The segment container.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "segmentLength", + "in": "query", + "description": "The segment length.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "minSegments", + "in": "query", + "description": "The minimum number of segments.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "The media version id, if playing an alternate version.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "The device id of the client requesting. Used to stop encoding processes when needed.", + "schema": { + "type": "string" + } + }, + { + "name": "audioCodec", + "in": "query", + "description": "Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "enableAutoStreamCopy", + "in": "query", + "description": "Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowVideoStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the video stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowAudioStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the audio stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "breakOnNonKeyFrames", + "in": "query", + "description": "Optional. Whether to break on non key frames.", + "schema": { + "type": "boolean" + } + }, + { + "name": "audioSampleRate", + "in": "query", + "description": "Optional. Specify a specific audio sample rate, e.g. 44100.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioBitDepth", + "in": "query", + "description": "Optional. The maximum audio bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxStreamingBitrate", + "in": "query", + "description": "Optional. The maximum streaming bitrate.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioBitRate", + "in": "query", + "description": "Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioChannels", + "in": "query", + "description": "Optional. Specify a specific number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioChannels", + "in": "query", + "description": "Optional. Specify a maximum number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "profile", + "in": "query", + "description": "Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high.", + "schema": { + "type": "string" + } + }, + { + "name": "level", + "in": "query", + "description": "Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1.", + "schema": { + "type": "string" + } + }, + { + "name": "framerate", + "in": "query", + "description": "Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "maxFramerate", + "in": "query", + "description": "Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "copyTimestamps", + "in": "query", + "description": "Whether or not to copy timestamps when transcoding with an offset. Defaults to false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "startTimeTicks", + "in": "query", + "description": "Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "width", + "in": "query", + "description": "Optional. The fixed horizontal resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "Optional. The fixed vertical resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoBitRate", + "in": "query", + "description": "Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleStreamIndex", + "in": "query", + "description": "Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleMethod", + "in": "query", + "description": "Optional. Specify the subtitle delivery method.", + "schema": { + "enum": ["Encode", "Embed", "External", "Hls", "Drop"], + "allOf": [ + { + "$ref": "#/components/schemas/SubtitleDeliveryMethod" + } + ] + } + }, + { + "name": "maxRefFrames", + "in": "query", + "description": "Optional.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxVideoBitDepth", + "in": "query", + "description": "Optional. The maximum video bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "requireAvc", + "in": "query", + "description": "Optional. Whether to require avc.", + "schema": { + "type": "boolean" + } + }, + { + "name": "deInterlace", + "in": "query", + "description": "Optional. Whether to deinterlace the video.", + "schema": { + "type": "boolean" + } + }, + { + "name": "requireNonAnamorphic", + "in": "query", + "description": "Optional. Whether to require a non anamorphic stream.", + "schema": { + "type": "boolean" + } + }, + { + "name": "transcodingMaxAudioChannels", + "in": "query", + "description": "Optional. The maximum number of audio channels to transcode.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "cpuCoreLimit", + "in": "query", + "description": "Optional. The limit of how many cpu cores to use.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "liveStreamId", + "in": "query", + "description": "The live stream id.", + "schema": { + "type": "string" + } + }, + { + "name": "enableMpegtsM2TsMode", + "in": "query", + "description": "Optional. Whether to enable the MpegtsM2Ts mode.", + "schema": { + "type": "boolean" + } + }, + { + "name": "videoCodec", + "in": "query", + "description": "Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vpx, wmv.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "subtitleCodec", + "in": "query", + "description": "Optional. Specify a subtitle codec to encode to.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "transcodeReasons", + "in": "query", + "description": "Optional. The transcoding reason.", + "schema": { + "type": "string" + } + }, + { + "name": "audioStreamIndex", + "in": "query", + "description": "Optional. The index of the audio stream to use. If omitted the first audio stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoStreamIndex", + "in": "query", + "description": "Optional. The index of the video stream to use. If omitted the first video stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "context", + "in": "query", + "description": "Optional. The MediaBrowser.Model.Dlna.EncodingContext.", + "schema": { + "enum": ["Streaming", "Static"], + "allOf": [ + { + "$ref": "#/components/schemas/EncodingContext" + } + ] + } + }, + { + "name": "streamOptions", + "in": "query", + "description": "Optional. The streaming options.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + } + } + } + ], + "responses": { + "200": { + "description": "Audio stream returned.", + "content": { + "application/x-mpegURL": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Audio/{itemId}/master.m3u8": { + "get": { + "tags": ["DynamicHls"], + "summary": "Gets an audio hls playlist stream.", + "operationId": "GetMasterHlsAudioPlaylist", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "static", + "in": "query", + "description": "Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "params", + "in": "query", + "description": "The streaming parameters.", + "schema": { + "type": "string" + } + }, + { + "name": "tag", + "in": "query", + "description": "The tag.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceProfileId", + "in": "query", + "description": "Optional. The dlna device profile id to utilize.", + "deprecated": true, + "schema": { + "type": "string" + } + }, + { + "name": "playSessionId", + "in": "query", + "description": "The play session id.", + "schema": { + "type": "string" + } + }, + { + "name": "segmentContainer", + "in": "query", + "description": "The segment container.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "segmentLength", + "in": "query", + "description": "The segment length.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "minSegments", + "in": "query", + "description": "The minimum number of segments.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "The media version id, if playing an alternate version.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "The device id of the client requesting. Used to stop encoding processes when needed.", + "schema": { + "type": "string" + } + }, + { + "name": "audioCodec", + "in": "query", + "description": "Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "enableAutoStreamCopy", + "in": "query", + "description": "Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowVideoStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the video stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowAudioStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the audio stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "breakOnNonKeyFrames", + "in": "query", + "description": "Optional. Whether to break on non key frames.", + "schema": { + "type": "boolean" + } + }, + { + "name": "audioSampleRate", + "in": "query", + "description": "Optional. Specify a specific audio sample rate, e.g. 44100.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioBitDepth", + "in": "query", + "description": "Optional. The maximum audio bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxStreamingBitrate", + "in": "query", + "description": "Optional. The maximum streaming bitrate.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioBitRate", + "in": "query", + "description": "Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioChannels", + "in": "query", + "description": "Optional. Specify a specific number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioChannels", + "in": "query", + "description": "Optional. Specify a maximum number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "profile", + "in": "query", + "description": "Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high.", + "schema": { + "type": "string" + } + }, + { + "name": "level", + "in": "query", + "description": "Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1.", + "schema": { + "type": "string" + } + }, + { + "name": "framerate", + "in": "query", + "description": "Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "maxFramerate", + "in": "query", + "description": "Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "copyTimestamps", + "in": "query", + "description": "Whether or not to copy timestamps when transcoding with an offset. Defaults to false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "startTimeTicks", + "in": "query", + "description": "Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "width", + "in": "query", + "description": "Optional. The fixed horizontal resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "Optional. The fixed vertical resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoBitRate", + "in": "query", + "description": "Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleStreamIndex", + "in": "query", + "description": "Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleMethod", + "in": "query", + "description": "Optional. Specify the subtitle delivery method.", + "schema": { + "enum": ["Encode", "Embed", "External", "Hls", "Drop"], + "allOf": [ + { + "$ref": "#/components/schemas/SubtitleDeliveryMethod" + } + ] + } + }, + { + "name": "maxRefFrames", + "in": "query", + "description": "Optional.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxVideoBitDepth", + "in": "query", + "description": "Optional. The maximum video bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "requireAvc", + "in": "query", + "description": "Optional. Whether to require avc.", + "schema": { + "type": "boolean" + } + }, + { + "name": "deInterlace", + "in": "query", + "description": "Optional. Whether to deinterlace the video.", + "schema": { + "type": "boolean" + } + }, + { + "name": "requireNonAnamorphic", + "in": "query", + "description": "Optional. Whether to require a non anamorphic stream.", + "schema": { + "type": "boolean" + } + }, + { + "name": "transcodingMaxAudioChannels", + "in": "query", + "description": "Optional. The maximum number of audio channels to transcode.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "cpuCoreLimit", + "in": "query", + "description": "Optional. The limit of how many cpu cores to use.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "liveStreamId", + "in": "query", + "description": "The live stream id.", + "schema": { + "type": "string" + } + }, + { + "name": "enableMpegtsM2TsMode", + "in": "query", + "description": "Optional. Whether to enable the MpegtsM2Ts mode.", + "schema": { + "type": "boolean" + } + }, + { + "name": "videoCodec", + "in": "query", + "description": "Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "subtitleCodec", + "in": "query", + "description": "Optional. Specify a subtitle codec to encode to.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "transcodeReasons", + "in": "query", + "description": "Optional. The transcoding reason.", + "schema": { + "type": "string" + } + }, + { + "name": "audioStreamIndex", + "in": "query", + "description": "Optional. The index of the audio stream to use. If omitted the first audio stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoStreamIndex", + "in": "query", + "description": "Optional. The index of the video stream to use. If omitted the first video stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "context", + "in": "query", + "description": "Optional. The MediaBrowser.Model.Dlna.EncodingContext.", + "schema": { + "enum": ["Streaming", "Static"], + "allOf": [ + { + "$ref": "#/components/schemas/EncodingContext" + } + ] + } + }, + { + "name": "streamOptions", + "in": "query", + "description": "Optional. The streaming options.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + } + } + }, + { + "name": "enableAdaptiveBitrateStreaming", + "in": "query", + "description": "Enable adaptive bitrate streaming.", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Audio stream returned.", + "content": { + "application/x-mpegURL": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + }, + "head": { + "tags": ["DynamicHls"], + "summary": "Gets an audio hls playlist stream.", + "operationId": "HeadMasterHlsAudioPlaylist", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "static", + "in": "query", + "description": "Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "params", + "in": "query", + "description": "The streaming parameters.", + "schema": { + "type": "string" + } + }, + { + "name": "tag", + "in": "query", + "description": "The tag.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceProfileId", + "in": "query", + "description": "Optional. The dlna device profile id to utilize.", + "deprecated": true, + "schema": { + "type": "string" + } + }, + { + "name": "playSessionId", + "in": "query", + "description": "The play session id.", + "schema": { + "type": "string" + } + }, + { + "name": "segmentContainer", + "in": "query", + "description": "The segment container.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "segmentLength", + "in": "query", + "description": "The segment length.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "minSegments", + "in": "query", + "description": "The minimum number of segments.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "The media version id, if playing an alternate version.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "The device id of the client requesting. Used to stop encoding processes when needed.", + "schema": { + "type": "string" + } + }, + { + "name": "audioCodec", + "in": "query", + "description": "Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "enableAutoStreamCopy", + "in": "query", + "description": "Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowVideoStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the video stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowAudioStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the audio stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "breakOnNonKeyFrames", + "in": "query", + "description": "Optional. Whether to break on non key frames.", + "schema": { + "type": "boolean" + } + }, + { + "name": "audioSampleRate", + "in": "query", + "description": "Optional. Specify a specific audio sample rate, e.g. 44100.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioBitDepth", + "in": "query", + "description": "Optional. The maximum audio bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxStreamingBitrate", + "in": "query", + "description": "Optional. The maximum streaming bitrate.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioBitRate", + "in": "query", + "description": "Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioChannels", + "in": "query", + "description": "Optional. Specify a specific number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioChannels", + "in": "query", + "description": "Optional. Specify a maximum number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "profile", + "in": "query", + "description": "Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high.", + "schema": { + "type": "string" + } + }, + { + "name": "level", + "in": "query", + "description": "Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1.", + "schema": { + "type": "string" + } + }, + { + "name": "framerate", + "in": "query", + "description": "Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "maxFramerate", + "in": "query", + "description": "Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "copyTimestamps", + "in": "query", + "description": "Whether or not to copy timestamps when transcoding with an offset. Defaults to false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "startTimeTicks", + "in": "query", + "description": "Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "width", + "in": "query", + "description": "Optional. The fixed horizontal resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "Optional. The fixed vertical resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoBitRate", + "in": "query", + "description": "Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleStreamIndex", + "in": "query", + "description": "Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleMethod", + "in": "query", + "description": "Optional. Specify the subtitle delivery method.", + "schema": { + "enum": ["Encode", "Embed", "External", "Hls", "Drop"], + "allOf": [ + { + "$ref": "#/components/schemas/SubtitleDeliveryMethod" + } + ] + } + }, + { + "name": "maxRefFrames", + "in": "query", + "description": "Optional.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxVideoBitDepth", + "in": "query", + "description": "Optional. The maximum video bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "requireAvc", + "in": "query", + "description": "Optional. Whether to require avc.", + "schema": { + "type": "boolean" + } + }, + { + "name": "deInterlace", + "in": "query", + "description": "Optional. Whether to deinterlace the video.", + "schema": { + "type": "boolean" + } + }, + { + "name": "requireNonAnamorphic", + "in": "query", + "description": "Optional. Whether to require a non anamorphic stream.", + "schema": { + "type": "boolean" + } + }, + { + "name": "transcodingMaxAudioChannels", + "in": "query", + "description": "Optional. The maximum number of audio channels to transcode.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "cpuCoreLimit", + "in": "query", + "description": "Optional. The limit of how many cpu cores to use.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "liveStreamId", + "in": "query", + "description": "The live stream id.", + "schema": { + "type": "string" + } + }, + { + "name": "enableMpegtsM2TsMode", + "in": "query", + "description": "Optional. Whether to enable the MpegtsM2Ts mode.", + "schema": { + "type": "boolean" + } + }, + { + "name": "videoCodec", + "in": "query", + "description": "Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "subtitleCodec", + "in": "query", + "description": "Optional. Specify a subtitle codec to encode to.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "transcodeReasons", + "in": "query", + "description": "Optional. The transcoding reason.", + "schema": { + "type": "string" + } + }, + { + "name": "audioStreamIndex", + "in": "query", + "description": "Optional. The index of the audio stream to use. If omitted the first audio stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoStreamIndex", + "in": "query", + "description": "Optional. The index of the video stream to use. If omitted the first video stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "context", + "in": "query", + "description": "Optional. The MediaBrowser.Model.Dlna.EncodingContext.", + "schema": { + "enum": ["Streaming", "Static"], + "allOf": [ + { + "$ref": "#/components/schemas/EncodingContext" + } + ] + } + }, + { + "name": "streamOptions", + "in": "query", + "description": "Optional. The streaming options.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + } + } + }, + { + "name": "enableAdaptiveBitrateStreaming", + "in": "query", + "description": "Enable adaptive bitrate streaming.", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Audio stream returned.", + "content": { + "application/x-mpegURL": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Videos/{itemId}/hls1/{playlistId}/{segmentId}.{container}": { + "get": { + "tags": ["DynamicHls"], + "summary": "Gets a video stream using HTTP live streaming.", + "operationId": "GetHlsVideoSegment", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "playlistId", + "in": "path", + "description": "The playlist id.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "segmentId", + "in": "path", + "description": "The segment id.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "container", + "in": "path", + "description": "The video container. Possible values are: ts, webm, asf, wmv, ogv, mp4, m4v, mkv, mpeg, mpg, avi, 3gp, wmv, wtv, m2ts, mov, iso, flv.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "runtimeTicks", + "in": "query", + "description": "The position of the requested segment in ticks.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "actualSegmentLengthTicks", + "in": "query", + "description": "The length of the requested segment in ticks.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "static", + "in": "query", + "description": "Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "params", + "in": "query", + "description": "The streaming parameters.", + "schema": { + "type": "string" + } + }, + { + "name": "tag", + "in": "query", + "description": "The tag.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceProfileId", + "in": "query", + "description": "Optional. The dlna device profile id to utilize.", + "deprecated": true, + "schema": { + "type": "string" + } + }, + { + "name": "playSessionId", + "in": "query", + "description": "The play session id.", + "schema": { + "type": "string" + } + }, + { + "name": "segmentContainer", + "in": "query", + "description": "The segment container.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "segmentLength", + "in": "query", + "description": "The desired segment length.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "minSegments", + "in": "query", + "description": "The minimum number of segments.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "The media version id, if playing an alternate version.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "The device id of the client requesting. Used to stop encoding processes when needed.", + "schema": { + "type": "string" + } + }, + { + "name": "audioCodec", + "in": "query", + "description": "Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "enableAutoStreamCopy", + "in": "query", + "description": "Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowVideoStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the video stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowAudioStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the audio stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "breakOnNonKeyFrames", + "in": "query", + "description": "Optional. Whether to break on non key frames.", + "schema": { + "type": "boolean" + } + }, + { + "name": "audioSampleRate", + "in": "query", + "description": "Optional. Specify a specific audio sample rate, e.g. 44100.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioBitDepth", + "in": "query", + "description": "Optional. The maximum audio bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioBitRate", + "in": "query", + "description": "Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioChannels", + "in": "query", + "description": "Optional. Specify a specific number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioChannels", + "in": "query", + "description": "Optional. Specify a maximum number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "profile", + "in": "query", + "description": "Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high.", + "schema": { + "type": "string" + } + }, + { + "name": "level", + "in": "query", + "description": "Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1.", + "schema": { + "type": "string" + } + }, + { + "name": "framerate", + "in": "query", + "description": "Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "maxFramerate", + "in": "query", + "description": "Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "copyTimestamps", + "in": "query", + "description": "Whether or not to copy timestamps when transcoding with an offset. Defaults to false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "startTimeTicks", + "in": "query", + "description": "Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "width", + "in": "query", + "description": "Optional. The fixed horizontal resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "Optional. The fixed vertical resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "Optional. The maximum horizontal resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "Optional. The maximum vertical resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoBitRate", + "in": "query", + "description": "Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleStreamIndex", + "in": "query", + "description": "Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleMethod", + "in": "query", + "description": "Optional. Specify the subtitle delivery method.", + "schema": { + "enum": ["Encode", "Embed", "External", "Hls", "Drop"], + "allOf": [ + { + "$ref": "#/components/schemas/SubtitleDeliveryMethod" + } + ] + } + }, + { + "name": "maxRefFrames", + "in": "query", + "description": "Optional.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxVideoBitDepth", + "in": "query", + "description": "Optional. The maximum video bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "requireAvc", + "in": "query", + "description": "Optional. Whether to require avc.", + "schema": { + "type": "boolean" + } + }, + { + "name": "deInterlace", + "in": "query", + "description": "Optional. Whether to deinterlace the video.", + "schema": { + "type": "boolean" + } + }, + { + "name": "requireNonAnamorphic", + "in": "query", + "description": "Optional. Whether to require a non anamorphic stream.", + "schema": { + "type": "boolean" + } + }, + { + "name": "transcodingMaxAudioChannels", + "in": "query", + "description": "Optional. The maximum number of audio channels to transcode.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "cpuCoreLimit", + "in": "query", + "description": "Optional. The limit of how many cpu cores to use.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "liveStreamId", + "in": "query", + "description": "The live stream id.", + "schema": { + "type": "string" + } + }, + { + "name": "enableMpegtsM2TsMode", + "in": "query", + "description": "Optional. Whether to enable the MpegtsM2Ts mode.", + "schema": { + "type": "boolean" + } + }, + { + "name": "videoCodec", + "in": "query", + "description": "Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "subtitleCodec", + "in": "query", + "description": "Optional. Specify a subtitle codec to encode to.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "transcodeReasons", + "in": "query", + "description": "Optional. The transcoding reason.", + "schema": { + "type": "string" + } + }, + { + "name": "audioStreamIndex", + "in": "query", + "description": "Optional. The index of the audio stream to use. If omitted the first audio stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoStreamIndex", + "in": "query", + "description": "Optional. The index of the video stream to use. If omitted the first video stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "context", + "in": "query", + "description": "Optional. The MediaBrowser.Model.Dlna.EncodingContext.", + "schema": { + "enum": ["Streaming", "Static"], + "allOf": [ + { + "$ref": "#/components/schemas/EncodingContext" + } + ] + } + }, + { + "name": "streamOptions", + "in": "query", + "description": "Optional. The streaming options.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + } + } + } + ], + "responses": { + "200": { + "description": "Video stream returned.", + "content": { + "video/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Videos/{itemId}/live.m3u8": { + "get": { + "tags": ["DynamicHls"], + "summary": "Gets a hls live stream.", + "operationId": "GetLiveHlsStream", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "container", + "in": "query", + "description": "The audio container.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "static", + "in": "query", + "description": "Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "params", + "in": "query", + "description": "The streaming parameters.", + "schema": { + "type": "string" + } + }, + { + "name": "tag", + "in": "query", + "description": "The tag.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceProfileId", + "in": "query", + "description": "Optional. The dlna device profile id to utilize.", + "deprecated": true, + "schema": { + "type": "string" + } + }, + { + "name": "playSessionId", + "in": "query", + "description": "The play session id.", + "schema": { + "type": "string" + } + }, + { + "name": "segmentContainer", + "in": "query", + "description": "The segment container.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "segmentLength", + "in": "query", + "description": "The segment length.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "minSegments", + "in": "query", + "description": "The minimum number of segments.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "The media version id, if playing an alternate version.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "The device id of the client requesting. Used to stop encoding processes when needed.", + "schema": { + "type": "string" + } + }, + { + "name": "audioCodec", + "in": "query", + "description": "Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "enableAutoStreamCopy", + "in": "query", + "description": "Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowVideoStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the video stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowAudioStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the audio stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "breakOnNonKeyFrames", + "in": "query", + "description": "Optional. Whether to break on non key frames.", + "schema": { + "type": "boolean" + } + }, + { + "name": "audioSampleRate", + "in": "query", + "description": "Optional. Specify a specific audio sample rate, e.g. 44100.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioBitDepth", + "in": "query", + "description": "Optional. The maximum audio bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioBitRate", + "in": "query", + "description": "Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioChannels", + "in": "query", + "description": "Optional. Specify a specific number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioChannels", + "in": "query", + "description": "Optional. Specify a maximum number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "profile", + "in": "query", + "description": "Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high.", + "schema": { + "type": "string" + } + }, + { + "name": "level", + "in": "query", + "description": "Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1.", + "schema": { + "type": "string" + } + }, + { + "name": "framerate", + "in": "query", + "description": "Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "maxFramerate", + "in": "query", + "description": "Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "copyTimestamps", + "in": "query", + "description": "Whether or not to copy timestamps when transcoding with an offset. Defaults to false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "startTimeTicks", + "in": "query", + "description": "Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "width", + "in": "query", + "description": "Optional. The fixed horizontal resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "Optional. The fixed vertical resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoBitRate", + "in": "query", + "description": "Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleStreamIndex", + "in": "query", + "description": "Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleMethod", + "in": "query", + "description": "Optional. Specify the subtitle delivery method.", + "schema": { + "enum": ["Encode", "Embed", "External", "Hls", "Drop"], + "allOf": [ + { + "$ref": "#/components/schemas/SubtitleDeliveryMethod" + } + ] + } + }, + { + "name": "maxRefFrames", + "in": "query", + "description": "Optional.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxVideoBitDepth", + "in": "query", + "description": "Optional. The maximum video bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "requireAvc", + "in": "query", + "description": "Optional. Whether to require avc.", + "schema": { + "type": "boolean" + } + }, + { + "name": "deInterlace", + "in": "query", + "description": "Optional. Whether to deinterlace the video.", + "schema": { + "type": "boolean" + } + }, + { + "name": "requireNonAnamorphic", + "in": "query", + "description": "Optional. Whether to require a non anamorphic stream.", + "schema": { + "type": "boolean" + } + }, + { + "name": "transcodingMaxAudioChannels", + "in": "query", + "description": "Optional. The maximum number of audio channels to transcode.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "cpuCoreLimit", + "in": "query", + "description": "Optional. The limit of how many cpu cores to use.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "liveStreamId", + "in": "query", + "description": "The live stream id.", + "schema": { + "type": "string" + } + }, + { + "name": "enableMpegtsM2TsMode", + "in": "query", + "description": "Optional. Whether to enable the MpegtsM2Ts mode.", + "schema": { + "type": "boolean" + } + }, + { + "name": "videoCodec", + "in": "query", + "description": "Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "subtitleCodec", + "in": "query", + "description": "Optional. Specify a subtitle codec to encode to.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "transcodeReasons", + "in": "query", + "description": "Optional. The transcoding reason.", + "schema": { + "type": "string" + } + }, + { + "name": "audioStreamIndex", + "in": "query", + "description": "Optional. The index of the audio stream to use. If omitted the first audio stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoStreamIndex", + "in": "query", + "description": "Optional. The index of the video stream to use. If omitted the first video stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "context", + "in": "query", + "description": "Optional. The MediaBrowser.Model.Dlna.EncodingContext.", + "schema": { + "enum": ["Streaming", "Static"], + "allOf": [ + { + "$ref": "#/components/schemas/EncodingContext" + } + ] + } + }, + { + "name": "streamOptions", + "in": "query", + "description": "Optional. The streaming options.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + } + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "Optional. The max width.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "Optional. The max height.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableSubtitlesInManifest", + "in": "query", + "description": "Optional. Whether to enable subtitles in the manifest.", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Hls live stream retrieved.", + "content": { + "application/x-mpegURL": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Videos/{itemId}/main.m3u8": { + "get": { + "tags": ["DynamicHls"], + "summary": "Gets a video stream using HTTP live streaming.", + "operationId": "GetVariantHlsVideoPlaylist", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "static", + "in": "query", + "description": "Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "params", + "in": "query", + "description": "The streaming parameters.", + "schema": { + "type": "string" + } + }, + { + "name": "tag", + "in": "query", + "description": "The tag.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceProfileId", + "in": "query", + "description": "Optional. The dlna device profile id to utilize.", + "deprecated": true, + "schema": { + "type": "string" + } + }, + { + "name": "playSessionId", + "in": "query", + "description": "The play session id.", + "schema": { + "type": "string" + } + }, + { + "name": "segmentContainer", + "in": "query", + "description": "The segment container.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "segmentLength", + "in": "query", + "description": "The segment length.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "minSegments", + "in": "query", + "description": "The minimum number of segments.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "The media version id, if playing an alternate version.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "The device id of the client requesting. Used to stop encoding processes when needed.", + "schema": { + "type": "string" + } + }, + { + "name": "audioCodec", + "in": "query", + "description": "Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "enableAutoStreamCopy", + "in": "query", + "description": "Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowVideoStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the video stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowAudioStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the audio stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "breakOnNonKeyFrames", + "in": "query", + "description": "Optional. Whether to break on non key frames.", + "schema": { + "type": "boolean" + } + }, + { + "name": "audioSampleRate", + "in": "query", + "description": "Optional. Specify a specific audio sample rate, e.g. 44100.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioBitDepth", + "in": "query", + "description": "Optional. The maximum audio bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioBitRate", + "in": "query", + "description": "Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioChannels", + "in": "query", + "description": "Optional. Specify a specific number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioChannels", + "in": "query", + "description": "Optional. Specify a maximum number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "profile", + "in": "query", + "description": "Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high.", + "schema": { + "type": "string" + } + }, + { + "name": "level", + "in": "query", + "description": "Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1.", + "schema": { + "type": "string" + } + }, + { + "name": "framerate", + "in": "query", + "description": "Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "maxFramerate", + "in": "query", + "description": "Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "copyTimestamps", + "in": "query", + "description": "Whether or not to copy timestamps when transcoding with an offset. Defaults to false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "startTimeTicks", + "in": "query", + "description": "Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "width", + "in": "query", + "description": "Optional. The fixed horizontal resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "Optional. The fixed vertical resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "Optional. The maximum horizontal resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "Optional. The maximum vertical resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoBitRate", + "in": "query", + "description": "Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleStreamIndex", + "in": "query", + "description": "Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleMethod", + "in": "query", + "description": "Optional. Specify the subtitle delivery method.", + "schema": { + "enum": ["Encode", "Embed", "External", "Hls", "Drop"], + "allOf": [ + { + "$ref": "#/components/schemas/SubtitleDeliveryMethod" + } + ] + } + }, + { + "name": "maxRefFrames", + "in": "query", + "description": "Optional.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxVideoBitDepth", + "in": "query", + "description": "Optional. The maximum video bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "requireAvc", + "in": "query", + "description": "Optional. Whether to require avc.", + "schema": { + "type": "boolean" + } + }, + { + "name": "deInterlace", + "in": "query", + "description": "Optional. Whether to deinterlace the video.", + "schema": { + "type": "boolean" + } + }, + { + "name": "requireNonAnamorphic", + "in": "query", + "description": "Optional. Whether to require a non anamorphic stream.", + "schema": { + "type": "boolean" + } + }, + { + "name": "transcodingMaxAudioChannels", + "in": "query", + "description": "Optional. The maximum number of audio channels to transcode.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "cpuCoreLimit", + "in": "query", + "description": "Optional. The limit of how many cpu cores to use.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "liveStreamId", + "in": "query", + "description": "The live stream id.", + "schema": { + "type": "string" + } + }, + { + "name": "enableMpegtsM2TsMode", + "in": "query", + "description": "Optional. Whether to enable the MpegtsM2Ts mode.", + "schema": { + "type": "boolean" + } + }, + { + "name": "videoCodec", + "in": "query", + "description": "Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "subtitleCodec", + "in": "query", + "description": "Optional. Specify a subtitle codec to encode to.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "transcodeReasons", + "in": "query", + "description": "Optional. The transcoding reason.", + "schema": { + "type": "string" + } + }, + { + "name": "audioStreamIndex", + "in": "query", + "description": "Optional. The index of the audio stream to use. If omitted the first audio stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoStreamIndex", + "in": "query", + "description": "Optional. The index of the video stream to use. If omitted the first video stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "context", + "in": "query", + "description": "Optional. The MediaBrowser.Model.Dlna.EncodingContext.", + "schema": { + "enum": ["Streaming", "Static"], + "allOf": [ + { + "$ref": "#/components/schemas/EncodingContext" + } + ] + } + }, + { + "name": "streamOptions", + "in": "query", + "description": "Optional. The streaming options.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + } + } + } + ], + "responses": { + "200": { + "description": "Video stream returned.", + "content": { + "application/x-mpegURL": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Videos/{itemId}/master.m3u8": { + "get": { + "tags": ["DynamicHls"], + "summary": "Gets a video hls playlist stream.", + "operationId": "GetMasterHlsVideoPlaylist", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "static", + "in": "query", + "description": "Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "params", + "in": "query", + "description": "The streaming parameters.", + "schema": { + "type": "string" + } + }, + { + "name": "tag", + "in": "query", + "description": "The tag.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceProfileId", + "in": "query", + "description": "Optional. The dlna device profile id to utilize.", + "deprecated": true, + "schema": { + "type": "string" + } + }, + { + "name": "playSessionId", + "in": "query", + "description": "The play session id.", + "schema": { + "type": "string" + } + }, + { + "name": "segmentContainer", + "in": "query", + "description": "The segment container.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "segmentLength", + "in": "query", + "description": "The segment length.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "minSegments", + "in": "query", + "description": "The minimum number of segments.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "The media version id, if playing an alternate version.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "The device id of the client requesting. Used to stop encoding processes when needed.", + "schema": { + "type": "string" + } + }, + { + "name": "audioCodec", + "in": "query", + "description": "Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "enableAutoStreamCopy", + "in": "query", + "description": "Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowVideoStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the video stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowAudioStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the audio stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "breakOnNonKeyFrames", + "in": "query", + "description": "Optional. Whether to break on non key frames.", + "schema": { + "type": "boolean" + } + }, + { + "name": "audioSampleRate", + "in": "query", + "description": "Optional. Specify a specific audio sample rate, e.g. 44100.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioBitDepth", + "in": "query", + "description": "Optional. The maximum audio bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioBitRate", + "in": "query", + "description": "Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioChannels", + "in": "query", + "description": "Optional. Specify a specific number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioChannels", + "in": "query", + "description": "Optional. Specify a maximum number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "profile", + "in": "query", + "description": "Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high.", + "schema": { + "type": "string" + } + }, + { + "name": "level", + "in": "query", + "description": "Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1.", + "schema": { + "type": "string" + } + }, + { + "name": "framerate", + "in": "query", + "description": "Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "maxFramerate", + "in": "query", + "description": "Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "copyTimestamps", + "in": "query", + "description": "Whether or not to copy timestamps when transcoding with an offset. Defaults to false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "startTimeTicks", + "in": "query", + "description": "Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "width", + "in": "query", + "description": "Optional. The fixed horizontal resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "Optional. The fixed vertical resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "Optional. The maximum horizontal resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "Optional. The maximum vertical resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoBitRate", + "in": "query", + "description": "Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleStreamIndex", + "in": "query", + "description": "Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleMethod", + "in": "query", + "description": "Optional. Specify the subtitle delivery method.", + "schema": { + "enum": ["Encode", "Embed", "External", "Hls", "Drop"], + "allOf": [ + { + "$ref": "#/components/schemas/SubtitleDeliveryMethod" + } + ] + } + }, + { + "name": "maxRefFrames", + "in": "query", + "description": "Optional.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxVideoBitDepth", + "in": "query", + "description": "Optional. The maximum video bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "requireAvc", + "in": "query", + "description": "Optional. Whether to require avc.", + "schema": { + "type": "boolean" + } + }, + { + "name": "deInterlace", + "in": "query", + "description": "Optional. Whether to deinterlace the video.", + "schema": { + "type": "boolean" + } + }, + { + "name": "requireNonAnamorphic", + "in": "query", + "description": "Optional. Whether to require a non anamorphic stream.", + "schema": { + "type": "boolean" + } + }, + { + "name": "transcodingMaxAudioChannels", + "in": "query", + "description": "Optional. The maximum number of audio channels to transcode.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "cpuCoreLimit", + "in": "query", + "description": "Optional. The limit of how many cpu cores to use.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "liveStreamId", + "in": "query", + "description": "The live stream id.", + "schema": { + "type": "string" + } + }, + { + "name": "enableMpegtsM2TsMode", + "in": "query", + "description": "Optional. Whether to enable the MpegtsM2Ts mode.", + "schema": { + "type": "boolean" + } + }, + { + "name": "videoCodec", + "in": "query", + "description": "Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "subtitleCodec", + "in": "query", + "description": "Optional. Specify a subtitle codec to encode to.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "transcodeReasons", + "in": "query", + "description": "Optional. The transcoding reason.", + "schema": { + "type": "string" + } + }, + { + "name": "audioStreamIndex", + "in": "query", + "description": "Optional. The index of the audio stream to use. If omitted the first audio stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoStreamIndex", + "in": "query", + "description": "Optional. The index of the video stream to use. If omitted the first video stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "context", + "in": "query", + "description": "Optional. The MediaBrowser.Model.Dlna.EncodingContext.", + "schema": { + "enum": ["Streaming", "Static"], + "allOf": [ + { + "$ref": "#/components/schemas/EncodingContext" + } + ] + } + }, + { + "name": "streamOptions", + "in": "query", + "description": "Optional. The streaming options.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + } + } + }, + { + "name": "enableAdaptiveBitrateStreaming", + "in": "query", + "description": "Enable adaptive bitrate streaming.", + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "enableTrickplay", + "in": "query", + "description": "Enable trickplay image playlists being added to master playlist.", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Video stream returned.", + "content": { + "application/x-mpegURL": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + }, + "head": { + "tags": ["DynamicHls"], + "summary": "Gets a video hls playlist stream.", + "operationId": "HeadMasterHlsVideoPlaylist", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "static", + "in": "query", + "description": "Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "params", + "in": "query", + "description": "The streaming parameters.", + "schema": { + "type": "string" + } + }, + { + "name": "tag", + "in": "query", + "description": "The tag.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceProfileId", + "in": "query", + "description": "Optional. The dlna device profile id to utilize.", + "deprecated": true, + "schema": { + "type": "string" + } + }, + { + "name": "playSessionId", + "in": "query", + "description": "The play session id.", + "schema": { + "type": "string" + } + }, + { + "name": "segmentContainer", + "in": "query", + "description": "The segment container.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "segmentLength", + "in": "query", + "description": "The segment length.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "minSegments", + "in": "query", + "description": "The minimum number of segments.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "The media version id, if playing an alternate version.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "The device id of the client requesting. Used to stop encoding processes when needed.", + "schema": { + "type": "string" + } + }, + { + "name": "audioCodec", + "in": "query", + "description": "Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "enableAutoStreamCopy", + "in": "query", + "description": "Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowVideoStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the video stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowAudioStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the audio stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "breakOnNonKeyFrames", + "in": "query", + "description": "Optional. Whether to break on non key frames.", + "schema": { + "type": "boolean" + } + }, + { + "name": "audioSampleRate", + "in": "query", + "description": "Optional. Specify a specific audio sample rate, e.g. 44100.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioBitDepth", + "in": "query", + "description": "Optional. The maximum audio bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioBitRate", + "in": "query", + "description": "Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioChannels", + "in": "query", + "description": "Optional. Specify a specific number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioChannels", + "in": "query", + "description": "Optional. Specify a maximum number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "profile", + "in": "query", + "description": "Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high.", + "schema": { + "type": "string" + } + }, + { + "name": "level", + "in": "query", + "description": "Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1.", + "schema": { + "type": "string" + } + }, + { + "name": "framerate", + "in": "query", + "description": "Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "maxFramerate", + "in": "query", + "description": "Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "copyTimestamps", + "in": "query", + "description": "Whether or not to copy timestamps when transcoding with an offset. Defaults to false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "startTimeTicks", + "in": "query", + "description": "Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "width", + "in": "query", + "description": "Optional. The fixed horizontal resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "Optional. The fixed vertical resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "Optional. The maximum horizontal resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "Optional. The maximum vertical resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoBitRate", + "in": "query", + "description": "Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleStreamIndex", + "in": "query", + "description": "Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleMethod", + "in": "query", + "description": "Optional. Specify the subtitle delivery method.", + "schema": { + "enum": ["Encode", "Embed", "External", "Hls", "Drop"], + "allOf": [ + { + "$ref": "#/components/schemas/SubtitleDeliveryMethod" + } + ] + } + }, + { + "name": "maxRefFrames", + "in": "query", + "description": "Optional.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxVideoBitDepth", + "in": "query", + "description": "Optional. The maximum video bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "requireAvc", + "in": "query", + "description": "Optional. Whether to require avc.", + "schema": { + "type": "boolean" + } + }, + { + "name": "deInterlace", + "in": "query", + "description": "Optional. Whether to deinterlace the video.", + "schema": { + "type": "boolean" + } + }, + { + "name": "requireNonAnamorphic", + "in": "query", + "description": "Optional. Whether to require a non anamorphic stream.", + "schema": { + "type": "boolean" + } + }, + { + "name": "transcodingMaxAudioChannels", + "in": "query", + "description": "Optional. The maximum number of audio channels to transcode.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "cpuCoreLimit", + "in": "query", + "description": "Optional. The limit of how many cpu cores to use.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "liveStreamId", + "in": "query", + "description": "The live stream id.", + "schema": { + "type": "string" + } + }, + { + "name": "enableMpegtsM2TsMode", + "in": "query", + "description": "Optional. Whether to enable the MpegtsM2Ts mode.", + "schema": { + "type": "boolean" + } + }, + { + "name": "videoCodec", + "in": "query", + "description": "Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "subtitleCodec", + "in": "query", + "description": "Optional. Specify a subtitle codec to encode to.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "transcodeReasons", + "in": "query", + "description": "Optional. The transcoding reason.", + "schema": { + "type": "string" + } + }, + { + "name": "audioStreamIndex", + "in": "query", + "description": "Optional. The index of the audio stream to use. If omitted the first audio stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoStreamIndex", + "in": "query", + "description": "Optional. The index of the video stream to use. If omitted the first video stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "context", + "in": "query", + "description": "Optional. The MediaBrowser.Model.Dlna.EncodingContext.", + "schema": { + "enum": ["Streaming", "Static"], + "allOf": [ + { + "$ref": "#/components/schemas/EncodingContext" + } + ] + } + }, + { + "name": "streamOptions", + "in": "query", + "description": "Optional. The streaming options.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + } + } + }, + { + "name": "enableAdaptiveBitrateStreaming", + "in": "query", + "description": "Enable adaptive bitrate streaming.", + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "enableTrickplay", + "in": "query", + "description": "Enable trickplay image playlists being added to master playlist.", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Video stream returned.", + "content": { + "application/x-mpegURL": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Environment/DefaultDirectoryBrowser": { + "get": { + "tags": ["Environment"], + "summary": "Get Default directory browser.", + "operationId": "GetDefaultDirectoryBrowser", + "responses": { + "200": { + "description": "Default directory browser returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DefaultDirectoryBrowserInfoDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/DefaultDirectoryBrowserInfoDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/DefaultDirectoryBrowserInfoDto" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "FirstTimeSetupOrElevated", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Environment/DirectoryContents": { + "get": { + "tags": ["Environment"], + "summary": "Gets the contents of a given directory in the file system.", + "operationId": "GetDirectoryContents", + "parameters": [ + { + "name": "path", + "in": "query", + "description": "The path.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "includeFiles", + "in": "query", + "description": "An optional filter to include or exclude files from the results. true/false.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "includeDirectories", + "in": "query", + "description": "An optional filter to include or exclude folders from the results. true/false.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Directory contents returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileSystemEntryInfo" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileSystemEntryInfo" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileSystemEntryInfo" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "FirstTimeSetupOrElevated", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Environment/Drives": { + "get": { + "tags": ["Environment"], + "summary": "Gets available drives from the server's file system.", + "operationId": "GetDrives", + "responses": { + "200": { + "description": "List of entries returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileSystemEntryInfo" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileSystemEntryInfo" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileSystemEntryInfo" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "FirstTimeSetupOrElevated", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Environment/NetworkShares": { + "get": { + "tags": ["Environment"], + "summary": "Gets network paths.", + "operationId": "GetNetworkShares", + "responses": { + "200": { + "description": "Empty array returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileSystemEntryInfo" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileSystemEntryInfo" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileSystemEntryInfo" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "deprecated": true, + "security": [ + { + "CustomAuthentication": [ + "FirstTimeSetupOrElevated", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Environment/ParentPath": { + "get": { + "tags": ["Environment"], + "summary": "Gets the parent path of a given path.", + "operationId": "GetParentPath", + "parameters": [ + { + "name": "path", + "in": "query", + "description": "The path.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "string" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "string" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "string" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "FirstTimeSetupOrElevated", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Environment/ValidatePath": { + "post": { + "tags": ["Environment"], + "summary": "Validates path.", + "operationId": "ValidatePath", + "requestBody": { + "description": "Validate request object.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ValidatePathDto" + } + ], + "description": "Validate path object." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ValidatePathDto" + } + ], + "description": "Validate path object." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ValidatePathDto" + } + ], + "description": "Validate path object." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Path validated." + }, + "404": { + "description": "Path not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "FirstTimeSetupOrElevated", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Items/Filters": { + "get": { + "tags": ["Filter"], + "summary": "Gets legacy query filters.", + "operationId": "GetQueryFiltersLegacy", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "Optional. User id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "parentId", + "in": "query", + "description": "Optional. Parent id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "includeItemTypes", + "in": "query", + "description": "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemKind" + } + } + }, + { + "name": "mediaTypes", + "in": "query", + "description": "Optional. Filter by MediaType. Allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MediaType" + } + } + } + ], + "responses": { + "200": { + "description": "Legacy filters retrieved.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueryFiltersLegacy" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/QueryFiltersLegacy" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/QueryFiltersLegacy" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/Filters2": { + "get": { + "tags": ["Filter"], + "summary": "Gets query filters.", + "operationId": "GetQueryFilters", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "Optional. User id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "parentId", + "in": "query", + "description": "Optional. Specify this to localize the search to a specific item or folder. Omit to use the root.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "includeItemTypes", + "in": "query", + "description": "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemKind" + } + } + }, + { + "name": "isAiring", + "in": "query", + "description": "Optional. Is item airing.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isMovie", + "in": "query", + "description": "Optional. Is item movie.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isSports", + "in": "query", + "description": "Optional. Is item sports.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isKids", + "in": "query", + "description": "Optional. Is item kids.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isNews", + "in": "query", + "description": "Optional. Is item news.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isSeries", + "in": "query", + "description": "Optional. Is item series.", + "schema": { + "type": "boolean" + } + }, + { + "name": "recursive", + "in": "query", + "description": "Optional. Search recursive.", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Filters retrieved.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueryFilters" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/QueryFilters" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/QueryFilters" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Genres": { + "get": { + "tags": ["Genres"], + "summary": "Gets all genres from a given item, folder, or the entire library.", + "operationId": "GetGenres", + "parameters": [ + { + "name": "startIndex", + "in": "query", + "description": "Optional. The record index to start at. All items with a lower index will be dropped from the results.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "searchTerm", + "in": "query", + "description": "The search term.", + "schema": { + "type": "string" + } + }, + { + "name": "parentId", + "in": "query", + "description": "Specify this to localize the search to a specific item or folder. Omit to use the root.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "excludeItemTypes", + "in": "query", + "description": "Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemKind" + } + } + }, + { + "name": "includeItemTypes", + "in": "query", + "description": "Optional. If specified, results will be filtered in based on item type. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemKind" + } + } + }, + { + "name": "isFavorite", + "in": "query", + "description": "Optional filter by items that are marked as favorite, or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional, the max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + }, + { + "name": "userId", + "in": "query", + "description": "User id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "nameStartsWithOrGreater", + "in": "query", + "description": "Optional filter by items whose name is sorted equally or greater than a given input string.", + "schema": { + "type": "string" + } + }, + { + "name": "nameStartsWith", + "in": "query", + "description": "Optional filter by items whose name is sorted equally than a given input string.", + "schema": { + "type": "string" + } + }, + { + "name": "nameLessThan", + "in": "query", + "description": "Optional filter by items whose name is equally or lesser than a given input string.", + "schema": { + "type": "string" + } + }, + { + "name": "sortBy", + "in": "query", + "description": "Optional. Specify one or more sort orders, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemSortBy" + } + } + }, + { + "name": "sortOrder", + "in": "query", + "description": "Sort Order - Ascending,Descending.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SortOrder" + } + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional, include image information in output.", + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "enableTotalRecordCount", + "in": "query", + "description": "Optional. Include total record count.", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Genres returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Genres/{genreName}": { + "get": { + "tags": ["Genres"], + "summary": "Gets a genre, by name.", + "operationId": "GetGenre", + "parameters": [ + { + "name": "genreName", + "in": "path", + "description": "The genre name.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "userId", + "in": "query", + "description": "The user id.", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Genres returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Audio/{itemId}/hls/{segmentId}/stream.aac": { + "get": { + "tags": ["HlsSegment"], + "summary": "Gets the specified audio segment for an audio item.", + "operationId": "GetHlsAudioSegmentLegacyAac", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "segmentId", + "in": "path", + "description": "The segment id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Hls audio segment returned.", + "content": { + "audio/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + } + } + } + }, + "/Audio/{itemId}/hls/{segmentId}/stream.mp3": { + "get": { + "tags": ["HlsSegment"], + "summary": "Gets the specified audio segment for an audio item.", + "operationId": "GetHlsAudioSegmentLegacyMp3", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "segmentId", + "in": "path", + "description": "The segment id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Hls audio segment returned.", + "content": { + "audio/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + } + } + } + }, + "/Videos/{itemId}/hls/{playlistId}/{segmentId}.{segmentContainer}": { + "get": { + "tags": ["HlsSegment"], + "summary": "Gets a hls video segment.", + "operationId": "GetHlsVideoSegmentLegacy", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "playlistId", + "in": "path", + "description": "The playlist id.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "segmentId", + "in": "path", + "description": "The segment id.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "segmentContainer", + "in": "path", + "description": "The segment container.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Hls video segment returned.", + "content": { + "video/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Hls segment not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + } + }, + "/Videos/{itemId}/hls/{playlistId}/stream.m3u8": { + "get": { + "tags": ["HlsSegment"], + "summary": "Gets a hls video playlist.", + "operationId": "GetHlsPlaylistLegacy", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The video id.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "playlistId", + "in": "path", + "description": "The playlist id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Hls video playlist returned.", + "content": { + "application/x-mpegURL": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Videos/ActiveEncodings": { + "delete": { + "tags": ["HlsSegment"], + "summary": "Stops an active encoding.", + "operationId": "StopEncodingProcess", + "parameters": [ + { + "name": "deviceId", + "in": "query", + "description": "The device id of the client requesting. Used to stop encoding processes when needed.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "playSessionId", + "in": "query", + "description": "The play session id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Encoding stopped successfully." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Artists/{name}/Images/{imageType}/{imageIndex}": { + "get": { + "tags": ["Image"], + "summary": "Get artist image by name.", + "operationId": "GetArtistImage", + "parameters": [ + { + "name": "name", + "in": "path", + "description": "Artist name.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "tag", + "in": "query", + "description": "Optional. Supply the cache tag from the item object to receive strong caching headers.", + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "query", + "description": "Determines the output format of the image - original,gif,jpg,png.", + "schema": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageFormat" + } + ] + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "The maximum image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "The maximum image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "percentPlayed", + "in": "query", + "description": "Optional. Percent to render for the percent played overlay.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "unplayedCount", + "in": "query", + "description": "Optional. Unplayed count overlay to render.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "width", + "in": "query", + "description": "The fixed image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "The fixed image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "quality", + "in": "query", + "description": "Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillWidth", + "in": "query", + "description": "Width of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillHeight", + "in": "query", + "description": "Height of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "blur", + "in": "query", + "description": "Optional. Blur image.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "backgroundColor", + "in": "query", + "description": "Optional. Apply a background color for transparent images.", + "schema": { + "type": "string" + } + }, + { + "name": "foregroundLayer", + "in": "query", + "description": "Optional. Apply a foreground layer on top of the image.", + "schema": { + "type": "string" + } + }, + { + "name": "imageIndex", + "in": "path", + "description": "Image index.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Image stream returned.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + }, + "head": { + "tags": ["Image"], + "summary": "Get artist image by name.", + "operationId": "HeadArtistImage", + "parameters": [ + { + "name": "name", + "in": "path", + "description": "Artist name.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "tag", + "in": "query", + "description": "Optional. Supply the cache tag from the item object to receive strong caching headers.", + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "query", + "description": "Determines the output format of the image - original,gif,jpg,png.", + "schema": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageFormat" + } + ] + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "The maximum image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "The maximum image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "percentPlayed", + "in": "query", + "description": "Optional. Percent to render for the percent played overlay.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "unplayedCount", + "in": "query", + "description": "Optional. Unplayed count overlay to render.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "width", + "in": "query", + "description": "The fixed image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "The fixed image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "quality", + "in": "query", + "description": "Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillWidth", + "in": "query", + "description": "Width of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillHeight", + "in": "query", + "description": "Height of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "blur", + "in": "query", + "description": "Optional. Blur image.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "backgroundColor", + "in": "query", + "description": "Optional. Apply a background color for transparent images.", + "schema": { + "type": "string" + } + }, + { + "name": "foregroundLayer", + "in": "query", + "description": "Optional. Apply a foreground layer on top of the image.", + "schema": { + "type": "string" + } + }, + { + "name": "imageIndex", + "in": "path", + "description": "Image index.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Image stream returned.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + } + }, + "/Branding/Splashscreen": { + "get": { + "tags": ["Image"], + "summary": "Generates or gets the splashscreen.", + "operationId": "GetSplashscreen", + "parameters": [ + { + "name": "tag", + "in": "query", + "description": "Supply the cache tag from the item object to receive strong caching headers.", + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "query", + "description": "Determines the output format of the image - original,gif,jpg,png.", + "schema": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageFormat" + } + ] + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "The maximum image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "The maximum image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "width", + "in": "query", + "description": "The fixed image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "The fixed image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillWidth", + "in": "query", + "description": "Width of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillHeight", + "in": "query", + "description": "Height of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "blur", + "in": "query", + "description": "Blur image.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "backgroundColor", + "in": "query", + "description": "Apply a background color for transparent images.", + "schema": { + "type": "string" + } + }, + { + "name": "foregroundLayer", + "in": "query", + "description": "Apply a foreground layer on top of the image.", + "schema": { + "type": "string" + } + }, + { + "name": "quality", + "in": "query", + "description": "Quality setting, from 0-100.", + "schema": { + "maximum": 100, + "minimum": 0, + "type": "integer", + "format": "int32", + "default": 90 + } + } + ], + "responses": { + "200": { + "description": "Splashscreen returned successfully.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + } + } + }, + "post": { + "tags": ["Image"], + "summary": "Uploads a custom splashscreen.\r\nThe body is expected to the image contents base64 encoded.", + "operationId": "UploadCustomSplashscreen", + "requestBody": { + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "responses": { + "204": { + "description": "Successfully uploaded new splashscreen." + }, + "400": { + "description": "Error reading MimeType from uploaded image.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "User does not have permission to upload splashscreen..", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + }, + "delete": { + "tags": ["Image"], + "summary": "Delete a custom splashscreen.", + "operationId": "DeleteCustomSplashscreen", + "responses": { + "204": { + "description": "Successfully deleted the custom splashscreen." + }, + "403": { + "description": "User does not have permission to delete splashscreen.." + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Genres/{name}/Images/{imageType}": { + "get": { + "tags": ["Image"], + "summary": "Get genre image by name.", + "operationId": "GetGenreImage", + "parameters": [ + { + "name": "name", + "in": "path", + "description": "Genre name.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "tag", + "in": "query", + "description": "Optional. Supply the cache tag from the item object to receive strong caching headers.", + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "query", + "description": "Determines the output format of the image - original,gif,jpg,png.", + "schema": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageFormat" + } + ] + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "The maximum image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "The maximum image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "percentPlayed", + "in": "query", + "description": "Optional. Percent to render for the percent played overlay.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "unplayedCount", + "in": "query", + "description": "Optional. Unplayed count overlay to render.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "width", + "in": "query", + "description": "The fixed image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "The fixed image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "quality", + "in": "query", + "description": "Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillWidth", + "in": "query", + "description": "Width of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillHeight", + "in": "query", + "description": "Height of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "blur", + "in": "query", + "description": "Optional. Blur image.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "backgroundColor", + "in": "query", + "description": "Optional. Apply a background color for transparent images.", + "schema": { + "type": "string" + } + }, + { + "name": "foregroundLayer", + "in": "query", + "description": "Optional. Apply a foreground layer on top of the image.", + "schema": { + "type": "string" + } + }, + { + "name": "imageIndex", + "in": "query", + "description": "Image index.", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Image stream returned.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + }, + "head": { + "tags": ["Image"], + "summary": "Get genre image by name.", + "operationId": "HeadGenreImage", + "parameters": [ + { + "name": "name", + "in": "path", + "description": "Genre name.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "tag", + "in": "query", + "description": "Optional. Supply the cache tag from the item object to receive strong caching headers.", + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "query", + "description": "Determines the output format of the image - original,gif,jpg,png.", + "schema": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageFormat" + } + ] + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "The maximum image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "The maximum image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "percentPlayed", + "in": "query", + "description": "Optional. Percent to render for the percent played overlay.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "unplayedCount", + "in": "query", + "description": "Optional. Unplayed count overlay to render.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "width", + "in": "query", + "description": "The fixed image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "The fixed image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "quality", + "in": "query", + "description": "Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillWidth", + "in": "query", + "description": "Width of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillHeight", + "in": "query", + "description": "Height of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "blur", + "in": "query", + "description": "Optional. Blur image.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "backgroundColor", + "in": "query", + "description": "Optional. Apply a background color for transparent images.", + "schema": { + "type": "string" + } + }, + { + "name": "foregroundLayer", + "in": "query", + "description": "Optional. Apply a foreground layer on top of the image.", + "schema": { + "type": "string" + } + }, + { + "name": "imageIndex", + "in": "query", + "description": "Image index.", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Image stream returned.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + } + }, + "/Genres/{name}/Images/{imageType}/{imageIndex}": { + "get": { + "tags": ["Image"], + "summary": "Get genre image by name.", + "operationId": "GetGenreImageByIndex", + "parameters": [ + { + "name": "name", + "in": "path", + "description": "Genre name.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "imageIndex", + "in": "path", + "description": "Image index.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tag", + "in": "query", + "description": "Optional. Supply the cache tag from the item object to receive strong caching headers.", + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "query", + "description": "Determines the output format of the image - original,gif,jpg,png.", + "schema": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageFormat" + } + ] + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "The maximum image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "The maximum image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "percentPlayed", + "in": "query", + "description": "Optional. Percent to render for the percent played overlay.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "unplayedCount", + "in": "query", + "description": "Optional. Unplayed count overlay to render.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "width", + "in": "query", + "description": "The fixed image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "The fixed image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "quality", + "in": "query", + "description": "Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillWidth", + "in": "query", + "description": "Width of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillHeight", + "in": "query", + "description": "Height of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "blur", + "in": "query", + "description": "Optional. Blur image.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "backgroundColor", + "in": "query", + "description": "Optional. Apply a background color for transparent images.", + "schema": { + "type": "string" + } + }, + { + "name": "foregroundLayer", + "in": "query", + "description": "Optional. Apply a foreground layer on top of the image.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Image stream returned.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + }, + "head": { + "tags": ["Image"], + "summary": "Get genre image by name.", + "operationId": "HeadGenreImageByIndex", + "parameters": [ + { + "name": "name", + "in": "path", + "description": "Genre name.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "imageIndex", + "in": "path", + "description": "Image index.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tag", + "in": "query", + "description": "Optional. Supply the cache tag from the item object to receive strong caching headers.", + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "query", + "description": "Determines the output format of the image - original,gif,jpg,png.", + "schema": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageFormat" + } + ] + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "The maximum image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "The maximum image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "percentPlayed", + "in": "query", + "description": "Optional. Percent to render for the percent played overlay.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "unplayedCount", + "in": "query", + "description": "Optional. Unplayed count overlay to render.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "width", + "in": "query", + "description": "The fixed image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "The fixed image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "quality", + "in": "query", + "description": "Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillWidth", + "in": "query", + "description": "Width of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillHeight", + "in": "query", + "description": "Height of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "blur", + "in": "query", + "description": "Optional. Blur image.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "backgroundColor", + "in": "query", + "description": "Optional. Apply a background color for transparent images.", + "schema": { + "type": "string" + } + }, + { + "name": "foregroundLayer", + "in": "query", + "description": "Optional. Apply a foreground layer on top of the image.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Image stream returned.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + } + }, + "/Items/{itemId}/Images": { + "get": { + "tags": ["Image"], + "summary": "Get item image infos.", + "operationId": "GetItemImageInfos", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Item images returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageInfo" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageInfo" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageInfo" + } + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/{itemId}/Images/{imageType}": { + "delete": { + "tags": ["Image"], + "summary": "Delete an item's image.", + "operationId": "DeleteItemImage", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "imageIndex", + "in": "query", + "description": "The image index.", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Image deleted." + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + }, + "post": { + "tags": ["Image"], + "summary": "Set item image.", + "operationId": "SetItemImage", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + } + ], + "requestBody": { + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "responses": { + "204": { + "description": "Image saved." + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + }, + "get": { + "tags": ["Image"], + "summary": "Gets the item's image.", + "operationId": "GetItemImage", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "The maximum image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "The maximum image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "width", + "in": "query", + "description": "The fixed image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "The fixed image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "quality", + "in": "query", + "description": "Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillWidth", + "in": "query", + "description": "Width of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillHeight", + "in": "query", + "description": "Height of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tag", + "in": "query", + "description": "Optional. Supply the cache tag from the item object to receive strong caching headers.", + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "query", + "description": "Optional. The MediaBrowser.Model.Drawing.ImageFormat of the returned image.", + "schema": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageFormat" + } + ] + } + }, + { + "name": "percentPlayed", + "in": "query", + "description": "Optional. Percent to render for the percent played overlay.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "unplayedCount", + "in": "query", + "description": "Optional. Unplayed count overlay to render.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "blur", + "in": "query", + "description": "Optional. Blur image.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "backgroundColor", + "in": "query", + "description": "Optional. Apply a background color for transparent images.", + "schema": { + "type": "string" + } + }, + { + "name": "foregroundLayer", + "in": "query", + "description": "Optional. Apply a foreground layer on top of the image.", + "schema": { + "type": "string" + } + }, + { + "name": "imageIndex", + "in": "query", + "description": "Image index.", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Image stream returned.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + }, + "head": { + "tags": ["Image"], + "summary": "Gets the item's image.", + "operationId": "HeadItemImage", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "The maximum image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "The maximum image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "width", + "in": "query", + "description": "The fixed image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "The fixed image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "quality", + "in": "query", + "description": "Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillWidth", + "in": "query", + "description": "Width of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillHeight", + "in": "query", + "description": "Height of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tag", + "in": "query", + "description": "Optional. Supply the cache tag from the item object to receive strong caching headers.", + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "query", + "description": "Optional. The MediaBrowser.Model.Drawing.ImageFormat of the returned image.", + "schema": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageFormat" + } + ] + } + }, + { + "name": "percentPlayed", + "in": "query", + "description": "Optional. Percent to render for the percent played overlay.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "unplayedCount", + "in": "query", + "description": "Optional. Unplayed count overlay to render.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "blur", + "in": "query", + "description": "Optional. Blur image.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "backgroundColor", + "in": "query", + "description": "Optional. Apply a background color for transparent images.", + "schema": { + "type": "string" + } + }, + { + "name": "foregroundLayer", + "in": "query", + "description": "Optional. Apply a foreground layer on top of the image.", + "schema": { + "type": "string" + } + }, + { + "name": "imageIndex", + "in": "query", + "description": "Image index.", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Image stream returned.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + } + }, + "/Items/{itemId}/Images/{imageType}/{imageIndex}": { + "delete": { + "tags": ["Image"], + "summary": "Delete an item's image.", + "operationId": "DeleteItemImageByIndex", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "imageIndex", + "in": "path", + "description": "The image index.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Image deleted." + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + }, + "post": { + "tags": ["Image"], + "summary": "Set item image.", + "operationId": "SetItemImageByIndex", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "imageIndex", + "in": "path", + "description": "(Unused) Image index.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "responses": { + "204": { + "description": "Image saved." + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + }, + "get": { + "tags": ["Image"], + "summary": "Gets the item's image.", + "operationId": "GetItemImageByIndex", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "imageIndex", + "in": "path", + "description": "Image index.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "The maximum image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "The maximum image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "width", + "in": "query", + "description": "The fixed image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "The fixed image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "quality", + "in": "query", + "description": "Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillWidth", + "in": "query", + "description": "Width of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillHeight", + "in": "query", + "description": "Height of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tag", + "in": "query", + "description": "Optional. Supply the cache tag from the item object to receive strong caching headers.", + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "query", + "description": "Optional. The MediaBrowser.Model.Drawing.ImageFormat of the returned image.", + "schema": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageFormat" + } + ] + } + }, + { + "name": "percentPlayed", + "in": "query", + "description": "Optional. Percent to render for the percent played overlay.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "unplayedCount", + "in": "query", + "description": "Optional. Unplayed count overlay to render.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "blur", + "in": "query", + "description": "Optional. Blur image.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "backgroundColor", + "in": "query", + "description": "Optional. Apply a background color for transparent images.", + "schema": { + "type": "string" + } + }, + { + "name": "foregroundLayer", + "in": "query", + "description": "Optional. Apply a foreground layer on top of the image.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Image stream returned.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + }, + "head": { + "tags": ["Image"], + "summary": "Gets the item's image.", + "operationId": "HeadItemImageByIndex", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "imageIndex", + "in": "path", + "description": "Image index.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "The maximum image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "The maximum image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "width", + "in": "query", + "description": "The fixed image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "The fixed image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "quality", + "in": "query", + "description": "Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillWidth", + "in": "query", + "description": "Width of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillHeight", + "in": "query", + "description": "Height of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tag", + "in": "query", + "description": "Optional. Supply the cache tag from the item object to receive strong caching headers.", + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "query", + "description": "Optional. The MediaBrowser.Model.Drawing.ImageFormat of the returned image.", + "schema": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageFormat" + } + ] + } + }, + { + "name": "percentPlayed", + "in": "query", + "description": "Optional. Percent to render for the percent played overlay.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "unplayedCount", + "in": "query", + "description": "Optional. Unplayed count overlay to render.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "blur", + "in": "query", + "description": "Optional. Blur image.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "backgroundColor", + "in": "query", + "description": "Optional. Apply a background color for transparent images.", + "schema": { + "type": "string" + } + }, + { + "name": "foregroundLayer", + "in": "query", + "description": "Optional. Apply a foreground layer on top of the image.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Image stream returned.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + } + }, + "/Items/{itemId}/Images/{imageType}/{imageIndex}/{tag}/{format}/{maxWidth}/{maxHeight}/{percentPlayed}/{unplayedCount}": { + "get": { + "tags": ["Image"], + "summary": "Gets the item's image.", + "operationId": "GetItemImage2", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "maxWidth", + "in": "path", + "description": "The maximum image width to return.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "path", + "description": "The maximum image height to return.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "width", + "in": "query", + "description": "The fixed image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "The fixed image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "quality", + "in": "query", + "description": "Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillWidth", + "in": "query", + "description": "Width of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillHeight", + "in": "query", + "description": "Height of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tag", + "in": "path", + "description": "Optional. Supply the cache tag from the item object to receive strong caching headers.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "path", + "description": "Determines the output format of the image - original,gif,jpg,png.", + "required": true, + "schema": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageFormat" + } + ], + "description": "Enum ImageOutputFormat." + } + }, + { + "name": "percentPlayed", + "in": "path", + "description": "Optional. Percent to render for the percent played overlay.", + "required": true, + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "unplayedCount", + "in": "path", + "description": "Optional. Unplayed count overlay to render.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "blur", + "in": "query", + "description": "Optional. Blur image.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "backgroundColor", + "in": "query", + "description": "Optional. Apply a background color for transparent images.", + "schema": { + "type": "string" + } + }, + { + "name": "foregroundLayer", + "in": "query", + "description": "Optional. Apply a foreground layer on top of the image.", + "schema": { + "type": "string" + } + }, + { + "name": "imageIndex", + "in": "path", + "description": "Image index.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Image stream returned.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + }, + "head": { + "tags": ["Image"], + "summary": "Gets the item's image.", + "operationId": "HeadItemImage2", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "maxWidth", + "in": "path", + "description": "The maximum image width to return.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "path", + "description": "The maximum image height to return.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "width", + "in": "query", + "description": "The fixed image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "The fixed image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "quality", + "in": "query", + "description": "Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillWidth", + "in": "query", + "description": "Width of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillHeight", + "in": "query", + "description": "Height of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tag", + "in": "path", + "description": "Optional. Supply the cache tag from the item object to receive strong caching headers.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "path", + "description": "Determines the output format of the image - original,gif,jpg,png.", + "required": true, + "schema": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageFormat" + } + ], + "description": "Enum ImageOutputFormat." + } + }, + { + "name": "percentPlayed", + "in": "path", + "description": "Optional. Percent to render for the percent played overlay.", + "required": true, + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "unplayedCount", + "in": "path", + "description": "Optional. Unplayed count overlay to render.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "blur", + "in": "query", + "description": "Optional. Blur image.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "backgroundColor", + "in": "query", + "description": "Optional. Apply a background color for transparent images.", + "schema": { + "type": "string" + } + }, + { + "name": "foregroundLayer", + "in": "query", + "description": "Optional. Apply a foreground layer on top of the image.", + "schema": { + "type": "string" + } + }, + { + "name": "imageIndex", + "in": "path", + "description": "Image index.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Image stream returned.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + } + }, + "/Items/{itemId}/Images/{imageType}/{imageIndex}/Index": { + "post": { + "tags": ["Image"], + "summary": "Updates the index for an item image.", + "operationId": "UpdateItemImageIndex", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "imageIndex", + "in": "path", + "description": "Old image index.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "newIndex", + "in": "query", + "description": "New image index.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Image index updated." + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/MusicGenres/{name}/Images/{imageType}": { + "get": { + "tags": ["Image"], + "summary": "Get music genre image by name.", + "operationId": "GetMusicGenreImage", + "parameters": [ + { + "name": "name", + "in": "path", + "description": "Music genre name.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "tag", + "in": "query", + "description": "Optional. Supply the cache tag from the item object to receive strong caching headers.", + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "query", + "description": "Determines the output format of the image - original,gif,jpg,png.", + "schema": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageFormat" + } + ] + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "The maximum image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "The maximum image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "percentPlayed", + "in": "query", + "description": "Optional. Percent to render for the percent played overlay.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "unplayedCount", + "in": "query", + "description": "Optional. Unplayed count overlay to render.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "width", + "in": "query", + "description": "The fixed image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "The fixed image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "quality", + "in": "query", + "description": "Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillWidth", + "in": "query", + "description": "Width of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillHeight", + "in": "query", + "description": "Height of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "blur", + "in": "query", + "description": "Optional. Blur image.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "backgroundColor", + "in": "query", + "description": "Optional. Apply a background color for transparent images.", + "schema": { + "type": "string" + } + }, + { + "name": "foregroundLayer", + "in": "query", + "description": "Optional. Apply a foreground layer on top of the image.", + "schema": { + "type": "string" + } + }, + { + "name": "imageIndex", + "in": "query", + "description": "Image index.", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Image stream returned.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + }, + "head": { + "tags": ["Image"], + "summary": "Get music genre image by name.", + "operationId": "HeadMusicGenreImage", + "parameters": [ + { + "name": "name", + "in": "path", + "description": "Music genre name.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "tag", + "in": "query", + "description": "Optional. Supply the cache tag from the item object to receive strong caching headers.", + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "query", + "description": "Determines the output format of the image - original,gif,jpg,png.", + "schema": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageFormat" + } + ] + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "The maximum image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "The maximum image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "percentPlayed", + "in": "query", + "description": "Optional. Percent to render for the percent played overlay.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "unplayedCount", + "in": "query", + "description": "Optional. Unplayed count overlay to render.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "width", + "in": "query", + "description": "The fixed image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "The fixed image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "quality", + "in": "query", + "description": "Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillWidth", + "in": "query", + "description": "Width of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillHeight", + "in": "query", + "description": "Height of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "blur", + "in": "query", + "description": "Optional. Blur image.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "backgroundColor", + "in": "query", + "description": "Optional. Apply a background color for transparent images.", + "schema": { + "type": "string" + } + }, + { + "name": "foregroundLayer", + "in": "query", + "description": "Optional. Apply a foreground layer on top of the image.", + "schema": { + "type": "string" + } + }, + { + "name": "imageIndex", + "in": "query", + "description": "Image index.", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Image stream returned.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + } + }, + "/MusicGenres/{name}/Images/{imageType}/{imageIndex}": { + "get": { + "tags": ["Image"], + "summary": "Get music genre image by name.", + "operationId": "GetMusicGenreImageByIndex", + "parameters": [ + { + "name": "name", + "in": "path", + "description": "Music genre name.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "imageIndex", + "in": "path", + "description": "Image index.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tag", + "in": "query", + "description": "Optional. Supply the cache tag from the item object to receive strong caching headers.", + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "query", + "description": "Determines the output format of the image - original,gif,jpg,png.", + "schema": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageFormat" + } + ] + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "The maximum image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "The maximum image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "percentPlayed", + "in": "query", + "description": "Optional. Percent to render for the percent played overlay.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "unplayedCount", + "in": "query", + "description": "Optional. Unplayed count overlay to render.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "width", + "in": "query", + "description": "The fixed image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "The fixed image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "quality", + "in": "query", + "description": "Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillWidth", + "in": "query", + "description": "Width of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillHeight", + "in": "query", + "description": "Height of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "blur", + "in": "query", + "description": "Optional. Blur image.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "backgroundColor", + "in": "query", + "description": "Optional. Apply a background color for transparent images.", + "schema": { + "type": "string" + } + }, + { + "name": "foregroundLayer", + "in": "query", + "description": "Optional. Apply a foreground layer on top of the image.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Image stream returned.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + }, + "head": { + "tags": ["Image"], + "summary": "Get music genre image by name.", + "operationId": "HeadMusicGenreImageByIndex", + "parameters": [ + { + "name": "name", + "in": "path", + "description": "Music genre name.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "imageIndex", + "in": "path", + "description": "Image index.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tag", + "in": "query", + "description": "Optional. Supply the cache tag from the item object to receive strong caching headers.", + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "query", + "description": "Determines the output format of the image - original,gif,jpg,png.", + "schema": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageFormat" + } + ] + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "The maximum image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "The maximum image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "percentPlayed", + "in": "query", + "description": "Optional. Percent to render for the percent played overlay.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "unplayedCount", + "in": "query", + "description": "Optional. Unplayed count overlay to render.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "width", + "in": "query", + "description": "The fixed image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "The fixed image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "quality", + "in": "query", + "description": "Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillWidth", + "in": "query", + "description": "Width of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillHeight", + "in": "query", + "description": "Height of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "blur", + "in": "query", + "description": "Optional. Blur image.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "backgroundColor", + "in": "query", + "description": "Optional. Apply a background color for transparent images.", + "schema": { + "type": "string" + } + }, + { + "name": "foregroundLayer", + "in": "query", + "description": "Optional. Apply a foreground layer on top of the image.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Image stream returned.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + } + }, + "/Persons/{name}/Images/{imageType}": { + "get": { + "tags": ["Image"], + "summary": "Get person image by name.", + "operationId": "GetPersonImage", + "parameters": [ + { + "name": "name", + "in": "path", + "description": "Person name.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "tag", + "in": "query", + "description": "Optional. Supply the cache tag from the item object to receive strong caching headers.", + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "query", + "description": "Determines the output format of the image - original,gif,jpg,png.", + "schema": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageFormat" + } + ] + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "The maximum image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "The maximum image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "percentPlayed", + "in": "query", + "description": "Optional. Percent to render for the percent played overlay.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "unplayedCount", + "in": "query", + "description": "Optional. Unplayed count overlay to render.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "width", + "in": "query", + "description": "The fixed image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "The fixed image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "quality", + "in": "query", + "description": "Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillWidth", + "in": "query", + "description": "Width of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillHeight", + "in": "query", + "description": "Height of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "blur", + "in": "query", + "description": "Optional. Blur image.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "backgroundColor", + "in": "query", + "description": "Optional. Apply a background color for transparent images.", + "schema": { + "type": "string" + } + }, + { + "name": "foregroundLayer", + "in": "query", + "description": "Optional. Apply a foreground layer on top of the image.", + "schema": { + "type": "string" + } + }, + { + "name": "imageIndex", + "in": "query", + "description": "Image index.", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Image stream returned.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + }, + "head": { + "tags": ["Image"], + "summary": "Get person image by name.", + "operationId": "HeadPersonImage", + "parameters": [ + { + "name": "name", + "in": "path", + "description": "Person name.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "tag", + "in": "query", + "description": "Optional. Supply the cache tag from the item object to receive strong caching headers.", + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "query", + "description": "Determines the output format of the image - original,gif,jpg,png.", + "schema": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageFormat" + } + ] + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "The maximum image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "The maximum image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "percentPlayed", + "in": "query", + "description": "Optional. Percent to render for the percent played overlay.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "unplayedCount", + "in": "query", + "description": "Optional. Unplayed count overlay to render.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "width", + "in": "query", + "description": "The fixed image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "The fixed image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "quality", + "in": "query", + "description": "Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillWidth", + "in": "query", + "description": "Width of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillHeight", + "in": "query", + "description": "Height of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "blur", + "in": "query", + "description": "Optional. Blur image.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "backgroundColor", + "in": "query", + "description": "Optional. Apply a background color for transparent images.", + "schema": { + "type": "string" + } + }, + { + "name": "foregroundLayer", + "in": "query", + "description": "Optional. Apply a foreground layer on top of the image.", + "schema": { + "type": "string" + } + }, + { + "name": "imageIndex", + "in": "query", + "description": "Image index.", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Image stream returned.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + } + }, + "/Persons/{name}/Images/{imageType}/{imageIndex}": { + "get": { + "tags": ["Image"], + "summary": "Get person image by name.", + "operationId": "GetPersonImageByIndex", + "parameters": [ + { + "name": "name", + "in": "path", + "description": "Person name.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "imageIndex", + "in": "path", + "description": "Image index.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tag", + "in": "query", + "description": "Optional. Supply the cache tag from the item object to receive strong caching headers.", + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "query", + "description": "Determines the output format of the image - original,gif,jpg,png.", + "schema": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageFormat" + } + ] + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "The maximum image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "The maximum image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "percentPlayed", + "in": "query", + "description": "Optional. Percent to render for the percent played overlay.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "unplayedCount", + "in": "query", + "description": "Optional. Unplayed count overlay to render.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "width", + "in": "query", + "description": "The fixed image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "The fixed image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "quality", + "in": "query", + "description": "Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillWidth", + "in": "query", + "description": "Width of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillHeight", + "in": "query", + "description": "Height of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "blur", + "in": "query", + "description": "Optional. Blur image.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "backgroundColor", + "in": "query", + "description": "Optional. Apply a background color for transparent images.", + "schema": { + "type": "string" + } + }, + { + "name": "foregroundLayer", + "in": "query", + "description": "Optional. Apply a foreground layer on top of the image.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Image stream returned.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + }, + "head": { + "tags": ["Image"], + "summary": "Get person image by name.", + "operationId": "HeadPersonImageByIndex", + "parameters": [ + { + "name": "name", + "in": "path", + "description": "Person name.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "imageIndex", + "in": "path", + "description": "Image index.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tag", + "in": "query", + "description": "Optional. Supply the cache tag from the item object to receive strong caching headers.", + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "query", + "description": "Determines the output format of the image - original,gif,jpg,png.", + "schema": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageFormat" + } + ] + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "The maximum image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "The maximum image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "percentPlayed", + "in": "query", + "description": "Optional. Percent to render for the percent played overlay.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "unplayedCount", + "in": "query", + "description": "Optional. Unplayed count overlay to render.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "width", + "in": "query", + "description": "The fixed image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "The fixed image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "quality", + "in": "query", + "description": "Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillWidth", + "in": "query", + "description": "Width of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillHeight", + "in": "query", + "description": "Height of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "blur", + "in": "query", + "description": "Optional. Blur image.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "backgroundColor", + "in": "query", + "description": "Optional. Apply a background color for transparent images.", + "schema": { + "type": "string" + } + }, + { + "name": "foregroundLayer", + "in": "query", + "description": "Optional. Apply a foreground layer on top of the image.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Image stream returned.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + } + }, + "/Studios/{name}/Images/{imageType}": { + "get": { + "tags": ["Image"], + "summary": "Get studio image by name.", + "operationId": "GetStudioImage", + "parameters": [ + { + "name": "name", + "in": "path", + "description": "Studio name.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "tag", + "in": "query", + "description": "Optional. Supply the cache tag from the item object to receive strong caching headers.", + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "query", + "description": "Determines the output format of the image - original,gif,jpg,png.", + "schema": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageFormat" + } + ] + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "The maximum image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "The maximum image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "percentPlayed", + "in": "query", + "description": "Optional. Percent to render for the percent played overlay.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "unplayedCount", + "in": "query", + "description": "Optional. Unplayed count overlay to render.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "width", + "in": "query", + "description": "The fixed image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "The fixed image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "quality", + "in": "query", + "description": "Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillWidth", + "in": "query", + "description": "Width of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillHeight", + "in": "query", + "description": "Height of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "blur", + "in": "query", + "description": "Optional. Blur image.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "backgroundColor", + "in": "query", + "description": "Optional. Apply a background color for transparent images.", + "schema": { + "type": "string" + } + }, + { + "name": "foregroundLayer", + "in": "query", + "description": "Optional. Apply a foreground layer on top of the image.", + "schema": { + "type": "string" + } + }, + { + "name": "imageIndex", + "in": "query", + "description": "Image index.", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Image stream returned.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + }, + "head": { + "tags": ["Image"], + "summary": "Get studio image by name.", + "operationId": "HeadStudioImage", + "parameters": [ + { + "name": "name", + "in": "path", + "description": "Studio name.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "tag", + "in": "query", + "description": "Optional. Supply the cache tag from the item object to receive strong caching headers.", + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "query", + "description": "Determines the output format of the image - original,gif,jpg,png.", + "schema": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageFormat" + } + ] + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "The maximum image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "The maximum image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "percentPlayed", + "in": "query", + "description": "Optional. Percent to render for the percent played overlay.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "unplayedCount", + "in": "query", + "description": "Optional. Unplayed count overlay to render.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "width", + "in": "query", + "description": "The fixed image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "The fixed image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "quality", + "in": "query", + "description": "Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillWidth", + "in": "query", + "description": "Width of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillHeight", + "in": "query", + "description": "Height of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "blur", + "in": "query", + "description": "Optional. Blur image.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "backgroundColor", + "in": "query", + "description": "Optional. Apply a background color for transparent images.", + "schema": { + "type": "string" + } + }, + { + "name": "foregroundLayer", + "in": "query", + "description": "Optional. Apply a foreground layer on top of the image.", + "schema": { + "type": "string" + } + }, + { + "name": "imageIndex", + "in": "query", + "description": "Image index.", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Image stream returned.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + } + }, + "/Studios/{name}/Images/{imageType}/{imageIndex}": { + "get": { + "tags": ["Image"], + "summary": "Get studio image by name.", + "operationId": "GetStudioImageByIndex", + "parameters": [ + { + "name": "name", + "in": "path", + "description": "Studio name.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "imageIndex", + "in": "path", + "description": "Image index.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tag", + "in": "query", + "description": "Optional. Supply the cache tag from the item object to receive strong caching headers.", + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "query", + "description": "Determines the output format of the image - original,gif,jpg,png.", + "schema": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageFormat" + } + ] + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "The maximum image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "The maximum image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "percentPlayed", + "in": "query", + "description": "Optional. Percent to render for the percent played overlay.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "unplayedCount", + "in": "query", + "description": "Optional. Unplayed count overlay to render.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "width", + "in": "query", + "description": "The fixed image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "The fixed image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "quality", + "in": "query", + "description": "Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillWidth", + "in": "query", + "description": "Width of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillHeight", + "in": "query", + "description": "Height of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "blur", + "in": "query", + "description": "Optional. Blur image.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "backgroundColor", + "in": "query", + "description": "Optional. Apply a background color for transparent images.", + "schema": { + "type": "string" + } + }, + { + "name": "foregroundLayer", + "in": "query", + "description": "Optional. Apply a foreground layer on top of the image.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Image stream returned.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + }, + "head": { + "tags": ["Image"], + "summary": "Get studio image by name.", + "operationId": "HeadStudioImageByIndex", + "parameters": [ + { + "name": "name", + "in": "path", + "description": "Studio name.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "imageType", + "in": "path", + "description": "Image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "imageIndex", + "in": "path", + "description": "Image index.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tag", + "in": "query", + "description": "Optional. Supply the cache tag from the item object to receive strong caching headers.", + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "query", + "description": "Determines the output format of the image - original,gif,jpg,png.", + "schema": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageFormat" + } + ] + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "The maximum image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "The maximum image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "percentPlayed", + "in": "query", + "description": "Optional. Percent to render for the percent played overlay.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "unplayedCount", + "in": "query", + "description": "Optional. Unplayed count overlay to render.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "width", + "in": "query", + "description": "The fixed image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "The fixed image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "quality", + "in": "query", + "description": "Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillWidth", + "in": "query", + "description": "Width of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillHeight", + "in": "query", + "description": "Height of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "blur", + "in": "query", + "description": "Optional. Blur image.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "backgroundColor", + "in": "query", + "description": "Optional. Apply a background color for transparent images.", + "schema": { + "type": "string" + } + }, + { + "name": "foregroundLayer", + "in": "query", + "description": "Optional. Apply a foreground layer on top of the image.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Image stream returned.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + } + }, + "/UserImage": { + "post": { + "tags": ["Image"], + "summary": "Sets the user image.", + "operationId": "PostUserImage", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "User Id.", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "responses": { + "204": { + "description": "Image updated." + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "User does not have permission to delete the image.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + }, + "delete": { + "tags": ["Image"], + "summary": "Delete the user's image.", + "operationId": "DeleteUserImage", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "User Id.", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "204": { + "description": "Image deleted." + }, + "403": { + "description": "User does not have permission to delete the image.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + }, + "get": { + "tags": ["Image"], + "summary": "Get user profile image.", + "operationId": "GetUserImage", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "User id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "tag", + "in": "query", + "description": "Optional. Supply the cache tag from the item object to receive strong caching headers.", + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "query", + "description": "Determines the output format of the image - original,gif,jpg,png.", + "schema": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageFormat" + } + ] + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "The maximum image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "The maximum image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "percentPlayed", + "in": "query", + "description": "Optional. Percent to render for the percent played overlay.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "unplayedCount", + "in": "query", + "description": "Optional. Unplayed count overlay to render.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "width", + "in": "query", + "description": "The fixed image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "The fixed image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "quality", + "in": "query", + "description": "Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillWidth", + "in": "query", + "description": "Width of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillHeight", + "in": "query", + "description": "Height of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "blur", + "in": "query", + "description": "Optional. Blur image.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "backgroundColor", + "in": "query", + "description": "Optional. Apply a background color for transparent images.", + "schema": { + "type": "string" + } + }, + { + "name": "foregroundLayer", + "in": "query", + "description": "Optional. Apply a foreground layer on top of the image.", + "schema": { + "type": "string" + } + }, + { + "name": "imageIndex", + "in": "query", + "description": "Image index.", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Image stream returned.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "User id not provided.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + }, + "head": { + "tags": ["Image"], + "summary": "Get user profile image.", + "operationId": "HeadUserImage", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "User id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "tag", + "in": "query", + "description": "Optional. Supply the cache tag from the item object to receive strong caching headers.", + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "query", + "description": "Determines the output format of the image - original,gif,jpg,png.", + "schema": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageFormat" + } + ] + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "The maximum image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "The maximum image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "percentPlayed", + "in": "query", + "description": "Optional. Percent to render for the percent played overlay.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "unplayedCount", + "in": "query", + "description": "Optional. Unplayed count overlay to render.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "width", + "in": "query", + "description": "The fixed image width to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "The fixed image height to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "quality", + "in": "query", + "description": "Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillWidth", + "in": "query", + "description": "Width of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fillHeight", + "in": "query", + "description": "Height of box to fill.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "blur", + "in": "query", + "description": "Optional. Blur image.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "backgroundColor", + "in": "query", + "description": "Optional. Apply a background color for transparent images.", + "schema": { + "type": "string" + } + }, + { + "name": "foregroundLayer", + "in": "query", + "description": "Optional. Apply a foreground layer on top of the image.", + "schema": { + "type": "string" + } + }, + { + "name": "imageIndex", + "in": "query", + "description": "Image index.", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Image stream returned.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "User id not provided.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + } + }, + "/Albums/{itemId}/InstantMix": { + "get": { + "tags": ["InstantMix"], + "summary": "Creates an instant playlist based on a given album.", + "operationId": "GetInstantMixFromAlbum", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user id, and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional. Include image information in output.", + "schema": { + "type": "boolean" + } + }, + { + "name": "enableUserData", + "in": "query", + "description": "Optional. Include user data.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional. The max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + } + ], + "responses": { + "200": { + "description": "Instant playlist returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Artists/{itemId}/InstantMix": { + "get": { + "tags": ["InstantMix"], + "summary": "Creates an instant playlist based on a given artist.", + "operationId": "GetInstantMixFromArtists", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user id, and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional. Include image information in output.", + "schema": { + "type": "boolean" + } + }, + { + "name": "enableUserData", + "in": "query", + "description": "Optional. Include user data.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional. The max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + } + ], + "responses": { + "200": { + "description": "Instant playlist returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Artists/InstantMix": { + "get": { + "tags": ["InstantMix"], + "summary": "Creates an instant playlist based on a given artist.", + "operationId": "GetInstantMixFromArtists2", + "parameters": [ + { + "name": "id", + "in": "query", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user id, and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional. Include image information in output.", + "schema": { + "type": "boolean" + } + }, + { + "name": "enableUserData", + "in": "query", + "description": "Optional. Include user data.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional. The max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + } + ], + "responses": { + "200": { + "description": "Instant playlist returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "deprecated": true, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/{itemId}/InstantMix": { + "get": { + "tags": ["InstantMix"], + "summary": "Creates an instant playlist based on a given item.", + "operationId": "GetInstantMixFromItem", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user id, and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional. Include image information in output.", + "schema": { + "type": "boolean" + } + }, + { + "name": "enableUserData", + "in": "query", + "description": "Optional. Include user data.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional. The max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + } + ], + "responses": { + "200": { + "description": "Instant playlist returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/MusicGenres/{name}/InstantMix": { + "get": { + "tags": ["InstantMix"], + "summary": "Creates an instant playlist based on a given genre.", + "operationId": "GetInstantMixFromMusicGenreByName", + "parameters": [ + { + "name": "name", + "in": "path", + "description": "The genre name.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user id, and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional. Include image information in output.", + "schema": { + "type": "boolean" + } + }, + { + "name": "enableUserData", + "in": "query", + "description": "Optional. Include user data.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional. The max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + } + ], + "responses": { + "200": { + "description": "Instant playlist returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/MusicGenres/InstantMix": { + "get": { + "tags": ["InstantMix"], + "summary": "Creates an instant playlist based on a given genre.", + "operationId": "GetInstantMixFromMusicGenreById", + "parameters": [ + { + "name": "id", + "in": "query", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user id, and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional. Include image information in output.", + "schema": { + "type": "boolean" + } + }, + { + "name": "enableUserData", + "in": "query", + "description": "Optional. Include user data.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional. The max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + } + ], + "responses": { + "200": { + "description": "Instant playlist returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Playlists/{itemId}/InstantMix": { + "get": { + "tags": ["InstantMix"], + "summary": "Creates an instant playlist based on a given playlist.", + "operationId": "GetInstantMixFromPlaylist", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user id, and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional. Include image information in output.", + "schema": { + "type": "boolean" + } + }, + { + "name": "enableUserData", + "in": "query", + "description": "Optional. Include user data.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional. The max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + } + ], + "responses": { + "200": { + "description": "Instant playlist returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Songs/{itemId}/InstantMix": { + "get": { + "tags": ["InstantMix"], + "summary": "Creates an instant playlist based on a given song.", + "operationId": "GetInstantMixFromSong", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user id, and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional. Include image information in output.", + "schema": { + "type": "boolean" + } + }, + { + "name": "enableUserData", + "in": "query", + "description": "Optional. Include user data.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional. The max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + } + ], + "responses": { + "200": { + "description": "Instant playlist returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/{itemId}/ExternalIdInfos": { + "get": { + "tags": ["ItemLookup"], + "summary": "Get the item's external id info.", + "operationId": "GetExternalIdInfos", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "External id info retrieved.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ExternalIdInfo" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ExternalIdInfo" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ExternalIdInfo" + } + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "RequiresElevation", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Items/RemoteSearch/Apply/{itemId}": { + "post": { + "tags": ["ItemLookup"], + "summary": "Applies search criteria to an item and refreshes metadata.", + "operationId": "ApplySearchCriteria", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "replaceAllImages", + "in": "query", + "description": "Optional. Whether or not to replace all images. Default: True.", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "requestBody": { + "description": "The remote search result.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/RemoteSearchResult" + } + ] + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/RemoteSearchResult" + } + ] + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/RemoteSearchResult" + } + ] + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Item metadata refreshed." + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "RequiresElevation", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Items/RemoteSearch/Book": { + "post": { + "tags": ["ItemLookup"], + "summary": "Get book remote search.", + "operationId": "GetBookRemoteSearchResults", + "requestBody": { + "description": "Remote search query.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/BookInfoRemoteSearchQuery" + } + ] + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/BookInfoRemoteSearchQuery" + } + ] + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/BookInfoRemoteSearchQuery" + } + ] + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Book remote search executed.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/RemoteSearch/BoxSet": { + "post": { + "tags": ["ItemLookup"], + "summary": "Get box set remote search.", + "operationId": "GetBoxSetRemoteSearchResults", + "requestBody": { + "description": "Remote search query.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/BoxSetInfoRemoteSearchQuery" + } + ] + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/BoxSetInfoRemoteSearchQuery" + } + ] + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/BoxSetInfoRemoteSearchQuery" + } + ] + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Box set remote search executed.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/RemoteSearch/Movie": { + "post": { + "tags": ["ItemLookup"], + "summary": "Get movie remote search.", + "operationId": "GetMovieRemoteSearchResults", + "requestBody": { + "description": "Remote search query.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/MovieInfoRemoteSearchQuery" + } + ] + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/MovieInfoRemoteSearchQuery" + } + ] + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/MovieInfoRemoteSearchQuery" + } + ] + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Movie remote search executed.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/RemoteSearch/MusicAlbum": { + "post": { + "tags": ["ItemLookup"], + "summary": "Get music album remote search.", + "operationId": "GetMusicAlbumRemoteSearchResults", + "requestBody": { + "description": "Remote search query.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/AlbumInfoRemoteSearchQuery" + } + ] + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/AlbumInfoRemoteSearchQuery" + } + ] + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/AlbumInfoRemoteSearchQuery" + } + ] + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Music album remote search executed.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/RemoteSearch/MusicArtist": { + "post": { + "tags": ["ItemLookup"], + "summary": "Get music artist remote search.", + "operationId": "GetMusicArtistRemoteSearchResults", + "requestBody": { + "description": "Remote search query.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ArtistInfoRemoteSearchQuery" + } + ] + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ArtistInfoRemoteSearchQuery" + } + ] + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ArtistInfoRemoteSearchQuery" + } + ] + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Music artist remote search executed.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/RemoteSearch/MusicVideo": { + "post": { + "tags": ["ItemLookup"], + "summary": "Get music video remote search.", + "operationId": "GetMusicVideoRemoteSearchResults", + "requestBody": { + "description": "Remote search query.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/MusicVideoInfoRemoteSearchQuery" + } + ] + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/MusicVideoInfoRemoteSearchQuery" + } + ] + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/MusicVideoInfoRemoteSearchQuery" + } + ] + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Music video remote search executed.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/RemoteSearch/Person": { + "post": { + "tags": ["ItemLookup"], + "summary": "Get person remote search.", + "operationId": "GetPersonRemoteSearchResults", + "requestBody": { + "description": "Remote search query.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PersonLookupInfoRemoteSearchQuery" + } + ] + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PersonLookupInfoRemoteSearchQuery" + } + ] + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PersonLookupInfoRemoteSearchQuery" + } + ] + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Person remote search executed.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "RequiresElevation", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Items/RemoteSearch/Series": { + "post": { + "tags": ["ItemLookup"], + "summary": "Get series remote search.", + "operationId": "GetSeriesRemoteSearchResults", + "requestBody": { + "description": "Remote search query.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SeriesInfoRemoteSearchQuery" + } + ] + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SeriesInfoRemoteSearchQuery" + } + ] + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SeriesInfoRemoteSearchQuery" + } + ] + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Series remote search executed.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/RemoteSearch/Trailer": { + "post": { + "tags": ["ItemLookup"], + "summary": "Get trailer remote search.", + "operationId": "GetTrailerRemoteSearchResults", + "requestBody": { + "description": "Remote search query.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/TrailerInfoRemoteSearchQuery" + } + ] + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/TrailerInfoRemoteSearchQuery" + } + ] + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/TrailerInfoRemoteSearchQuery" + } + ] + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Trailer remote search executed.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/{itemId}/Refresh": { + "post": { + "tags": ["ItemRefresh"], + "summary": "Refreshes metadata for an item.", + "operationId": "RefreshItem", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "metadataRefreshMode", + "in": "query", + "description": "(Optional) Specifies the metadata refresh mode.", + "schema": { + "enum": ["None", "ValidationOnly", "Default", "FullRefresh"], + "allOf": [ + { + "$ref": "#/components/schemas/MetadataRefreshMode" + } + ], + "default": "None" + } + }, + { + "name": "imageRefreshMode", + "in": "query", + "description": "(Optional) Specifies the image refresh mode.", + "schema": { + "enum": ["None", "ValidationOnly", "Default", "FullRefresh"], + "allOf": [ + { + "$ref": "#/components/schemas/MetadataRefreshMode" + } + ], + "default": "None" + } + }, + { + "name": "replaceAllMetadata", + "in": "query", + "description": "(Optional) Determines if metadata should be replaced. Only applicable if mode is FullRefresh.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "replaceAllImages", + "in": "query", + "description": "(Optional) Determines if images should be replaced. Only applicable if mode is FullRefresh.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "204": { + "description": "Item metadata refresh queued." + }, + "404": { + "description": "Item to refresh not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Items": { + "get": { + "tags": ["Items"], + "summary": "Gets items based on a query.", + "operationId": "GetItems", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "The user id supplied as query parameter; this is required when not using an API key.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "maxOfficialRating", + "in": "query", + "description": "Optional filter by maximum official rating (PG, PG-13, TV-MA, etc).", + "schema": { + "type": "string" + } + }, + { + "name": "hasThemeSong", + "in": "query", + "description": "Optional filter by items with theme songs.", + "schema": { + "type": "boolean" + } + }, + { + "name": "hasThemeVideo", + "in": "query", + "description": "Optional filter by items with theme videos.", + "schema": { + "type": "boolean" + } + }, + { + "name": "hasSubtitles", + "in": "query", + "description": "Optional filter by items with subtitles.", + "schema": { + "type": "boolean" + } + }, + { + "name": "hasSpecialFeature", + "in": "query", + "description": "Optional filter by items with special features.", + "schema": { + "type": "boolean" + } + }, + { + "name": "hasTrailer", + "in": "query", + "description": "Optional filter by items with trailers.", + "schema": { + "type": "boolean" + } + }, + { + "name": "adjacentTo", + "in": "query", + "description": "Optional. Return items that are siblings of a supplied item.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "parentIndexNumber", + "in": "query", + "description": "Optional filter by parent index number.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "hasParentalRating", + "in": "query", + "description": "Optional filter by items that have or do not have a parental rating.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isHd", + "in": "query", + "description": "Optional filter by items that are HD or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "is4K", + "in": "query", + "description": "Optional filter by items that are 4K or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "locationTypes", + "in": "query", + "description": "Optional. If specified, results will be filtered based on LocationType. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LocationType" + } + } + }, + { + "name": "excludeLocationTypes", + "in": "query", + "description": "Optional. If specified, results will be filtered based on the LocationType. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LocationType" + } + } + }, + { + "name": "isMissing", + "in": "query", + "description": "Optional filter by items that are missing episodes or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isUnaired", + "in": "query", + "description": "Optional filter by items that are unaired episodes or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "minCommunityRating", + "in": "query", + "description": "Optional filter by minimum community rating.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "minCriticRating", + "in": "query", + "description": "Optional filter by minimum critic rating.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "minPremiereDate", + "in": "query", + "description": "Optional. The minimum premiere date. Format = ISO.", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "minDateLastSaved", + "in": "query", + "description": "Optional. The minimum last saved date. Format = ISO.", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "minDateLastSavedForUser", + "in": "query", + "description": "Optional. The minimum last saved date for the current user. Format = ISO.", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "maxPremiereDate", + "in": "query", + "description": "Optional. The maximum premiere date. Format = ISO.", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "hasOverview", + "in": "query", + "description": "Optional filter by items that have an overview or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "hasImdbId", + "in": "query", + "description": "Optional filter by items that have an IMDb id or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "hasTmdbId", + "in": "query", + "description": "Optional filter by items that have a TMDb id or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "hasTvdbId", + "in": "query", + "description": "Optional filter by items that have a TVDb id or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isMovie", + "in": "query", + "description": "Optional filter for live tv movies.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isSeries", + "in": "query", + "description": "Optional filter for live tv series.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isNews", + "in": "query", + "description": "Optional filter for live tv news.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isKids", + "in": "query", + "description": "Optional filter for live tv kids.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isSports", + "in": "query", + "description": "Optional filter for live tv sports.", + "schema": { + "type": "boolean" + } + }, + { + "name": "excludeItemIds", + "in": "query", + "description": "Optional. If specified, results will be filtered by excluding item ids. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "startIndex", + "in": "query", + "description": "Optional. The record index to start at. All items with a lower index will be dropped from the results.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "recursive", + "in": "query", + "description": "When searching within folders, this determines whether or not the search will be recursive. true/false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "searchTerm", + "in": "query", + "description": "Optional. Filter based on a search term.", + "schema": { + "type": "string" + } + }, + { + "name": "sortOrder", + "in": "query", + "description": "Sort Order - Ascending, Descending.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SortOrder" + } + } + }, + { + "name": "parentId", + "in": "query", + "description": "Specify this to localize the search to a specific item or folder. Omit to use the root.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "excludeItemTypes", + "in": "query", + "description": "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemKind" + } + } + }, + { + "name": "includeItemTypes", + "in": "query", + "description": "Optional. If specified, results will be filtered based on the item type. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemKind" + } + } + }, + { + "name": "filters", + "in": "query", + "description": "Optional. Specify additional filters to apply. This allows multiple, comma delimited. Options: IsFolder, IsNotFolder, IsUnplayed, IsPlayed, IsFavorite, IsResumable, Likes, Dislikes.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFilter" + } + } + }, + { + "name": "isFavorite", + "in": "query", + "description": "Optional filter by items that are marked as favorite, or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "mediaTypes", + "in": "query", + "description": "Optional filter by MediaType. Allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MediaType" + } + } + }, + { + "name": "imageTypes", + "in": "query", + "description": "Optional. If specified, results will be filtered based on those containing image types. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + }, + { + "name": "sortBy", + "in": "query", + "description": "Optional. Specify one or more sort orders, comma delimited. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemSortBy" + } + } + }, + { + "name": "isPlayed", + "in": "query", + "description": "Optional filter by items that are played, or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "genres", + "in": "query", + "description": "Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "officialRatings", + "in": "query", + "description": "Optional. If specified, results will be filtered based on OfficialRating. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "tags", + "in": "query", + "description": "Optional. If specified, results will be filtered based on tag. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "years", + "in": "query", + "description": "Optional. If specified, results will be filtered based on production year. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + }, + { + "name": "enableUserData", + "in": "query", + "description": "Optional, include user data.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional, the max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + }, + { + "name": "person", + "in": "query", + "description": "Optional. If specified, results will be filtered to include only those containing the specified person.", + "schema": { + "type": "string" + } + }, + { + "name": "personIds", + "in": "query", + "description": "Optional. If specified, results will be filtered to include only those containing the specified person id.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "personTypes", + "in": "query", + "description": "Optional. If specified, along with Person, results will be filtered to include only those containing the specified person and PersonType. Allows multiple, comma-delimited.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "studios", + "in": "query", + "description": "Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "artists", + "in": "query", + "description": "Optional. If specified, results will be filtered based on artists. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "excludeArtistIds", + "in": "query", + "description": "Optional. If specified, results will be filtered based on artist id. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "artistIds", + "in": "query", + "description": "Optional. If specified, results will be filtered to include only those containing the specified artist id.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "albumArtistIds", + "in": "query", + "description": "Optional. If specified, results will be filtered to include only those containing the specified album artist id.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "contributingArtistIds", + "in": "query", + "description": "Optional. If specified, results will be filtered to include only those containing the specified contributing artist id.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "albums", + "in": "query", + "description": "Optional. If specified, results will be filtered based on album. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "albumIds", + "in": "query", + "description": "Optional. If specified, results will be filtered based on album id. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "ids", + "in": "query", + "description": "Optional. If specific items are needed, specify a list of item id's to retrieve. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "videoTypes", + "in": "query", + "description": "Optional filter by VideoType (videofile, dvd, bluray, iso). Allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VideoType" + } + } + }, + { + "name": "minOfficialRating", + "in": "query", + "description": "Optional filter by minimum official rating (PG, PG-13, TV-MA, etc).", + "schema": { + "type": "string" + } + }, + { + "name": "isLocked", + "in": "query", + "description": "Optional filter by items that are locked.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isPlaceHolder", + "in": "query", + "description": "Optional filter by items that are placeholders.", + "schema": { + "type": "boolean" + } + }, + { + "name": "hasOfficialRating", + "in": "query", + "description": "Optional filter by items that have official ratings.", + "schema": { + "type": "boolean" + } + }, + { + "name": "collapseBoxSetItems", + "in": "query", + "description": "Whether or not to hide items behind their boxsets.", + "schema": { + "type": "boolean" + } + }, + { + "name": "minWidth", + "in": "query", + "description": "Optional. Filter by the minimum width of the item.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "minHeight", + "in": "query", + "description": "Optional. Filter by the minimum height of the item.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "Optional. Filter by the maximum width of the item.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "Optional. Filter by the maximum height of the item.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "is3D", + "in": "query", + "description": "Optional filter by items that are 3D, or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "seriesStatus", + "in": "query", + "description": "Optional filter by Series Status. Allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SeriesStatus" + } + } + }, + { + "name": "nameStartsWithOrGreater", + "in": "query", + "description": "Optional filter by items whose name is sorted equally or greater than a given input string.", + "schema": { + "type": "string" + } + }, + { + "name": "nameStartsWith", + "in": "query", + "description": "Optional filter by items whose name is sorted equally than a given input string.", + "schema": { + "type": "string" + } + }, + { + "name": "nameLessThan", + "in": "query", + "description": "Optional filter by items whose name is equally or lesser than a given input string.", + "schema": { + "type": "string" + } + }, + { + "name": "studioIds", + "in": "query", + "description": "Optional. If specified, results will be filtered based on studio id. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "genreIds", + "in": "query", + "description": "Optional. If specified, results will be filtered based on genre id. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "enableTotalRecordCount", + "in": "query", + "description": "Optional. Enable the total record count.", + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional, include image information in output.", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + }, + "delete": { + "tags": ["Library"], + "summary": "Deletes items from the library and filesystem.", + "operationId": "DeleteItems", + "parameters": [ + { + "name": "ids", + "in": "query", + "description": "The item ids.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + } + ], + "responses": { + "204": { + "description": "Items deleted." + }, + "401": { + "description": "Unauthorized access.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/UserItems/{itemId}/UserData": { + "get": { + "tags": ["Items"], + "summary": "Get Item User Data.", + "operationId": "GetItemUserData", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "The user id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "return item user data.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserItemDataDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/UserItemDataDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/UserItemDataDto" + } + } + } + }, + "404": { + "description": "Item is not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + }, + "post": { + "tags": ["Items"], + "summary": "Update Item User Data.", + "operationId": "UpdateItemUserData", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "The user id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "description": "New user data object.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UpdateUserItemDataDto" + } + ], + "description": "This is used by the api to get information about a item user data." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UpdateUserItemDataDto" + } + ], + "description": "This is used by the api to get information about a item user data." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UpdateUserItemDataDto" + } + ], + "description": "This is used by the api to get information about a item user data." + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "return updated user item data.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserItemDataDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/UserItemDataDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/UserItemDataDto" + } + } + } + }, + "404": { + "description": "Item is not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/UserItems/Resume": { + "get": { + "tags": ["Items"], + "summary": "Gets items based on a query.", + "operationId": "GetResumeItems", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "The user id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "startIndex", + "in": "query", + "description": "The start index.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "The item limit.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "searchTerm", + "in": "query", + "description": "The search term.", + "schema": { + "type": "string" + } + }, + { + "name": "parentId", + "in": "query", + "description": "Specify this to localize the search to a specific item or folder. Omit to use the root.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "mediaTypes", + "in": "query", + "description": "Optional. Filter by MediaType. Allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MediaType" + } + } + }, + { + "name": "enableUserData", + "in": "query", + "description": "Optional. Include user data.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional. The max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + }, + { + "name": "excludeItemTypes", + "in": "query", + "description": "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemKind" + } + } + }, + { + "name": "includeItemTypes", + "in": "query", + "description": "Optional. If specified, results will be filtered based on the item type. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemKind" + } + } + }, + { + "name": "enableTotalRecordCount", + "in": "query", + "description": "Optional. Enable the total record count.", + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional. Include image information in output.", + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "excludeActiveSessions", + "in": "query", + "description": "Optional. Whether to exclude the currently active sessions.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Items returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/{itemId}": { + "post": { + "tags": ["ItemUpdate"], + "summary": "Updates an item.", + "operationId": "UpdateItem", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "description": "The new item properties.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/BaseItemDto" + } + ], + "description": "This is strictly used as a data transfer object from the api layer.\r\nThis holds information about a BaseItem in a format that is convenient for the client." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/BaseItemDto" + } + ], + "description": "This is strictly used as a data transfer object from the api layer.\r\nThis holds information about a BaseItem in a format that is convenient for the client." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/BaseItemDto" + } + ], + "description": "This is strictly used as a data transfer object from the api layer.\r\nThis holds information about a BaseItem in a format that is convenient for the client." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Item updated." + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + }, + "delete": { + "tags": ["Library"], + "summary": "Deletes an item from the library and filesystem.", + "operationId": "DeleteItem", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "204": { + "description": "Item deleted." + }, + "401": { + "description": "Unauthorized access.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + }, + "get": { + "tags": ["UserLibrary"], + "summary": "Gets an item from a user's library.", + "operationId": "GetItem", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "User id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Item returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/{itemId}/ContentType": { + "post": { + "tags": ["ItemUpdate"], + "summary": "Updates an item's content type.", + "operationId": "UpdateItemContentType", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "contentType", + "in": "query", + "description": "The content type of the item.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Item content type updated." + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Items/{itemId}/MetadataEditor": { + "get": { + "tags": ["ItemUpdate"], + "summary": "Gets metadata editor info for an item.", + "operationId": "GetMetadataEditorInfo", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Item metadata editor returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetadataEditorInfo" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/MetadataEditorInfo" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/MetadataEditorInfo" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Albums/{itemId}/Similar": { + "get": { + "tags": ["Library"], + "summary": "Gets similar items.", + "operationId": "GetSimilarAlbums", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "excludeArtistIds", + "in": "query", + "description": "Exclude artist ids.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user id, and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + } + ], + "responses": { + "200": { + "description": "Similar items returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Artists/{itemId}/Similar": { + "get": { + "tags": ["Library"], + "summary": "Gets similar items.", + "operationId": "GetSimilarArtists", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "excludeArtistIds", + "in": "query", + "description": "Exclude artist ids.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user id, and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + } + ], + "responses": { + "200": { + "description": "Similar items returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/{itemId}/Ancestors": { + "get": { + "tags": ["Library"], + "summary": "Gets all parents of an item.", + "operationId": "GetAncestors", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user id, and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Item parents returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemDto" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemDto" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemDto" + } + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/{itemId}/CriticReviews": { + "get": { + "tags": ["Library"], + "summary": "Gets critic review for an item.", + "operationId": "GetCriticReviews", + "parameters": [ + { + "name": "itemId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Critic reviews returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "deprecated": true, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/{itemId}/Download": { + "get": { + "tags": ["Library"], + "summary": "Downloads item media.", + "operationId": "GetDownload", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Media downloaded.", + "content": { + "video/*": { + "schema": { + "type": "string", + "format": "binary" + } + }, + "audio/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["Download", "DefaultAuthorization"] + } + ] + } + }, + "/Items/{itemId}/File": { + "get": { + "tags": ["Library"], + "summary": "Get the original file of an item.", + "operationId": "GetFile", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "File stream returned.", + "content": { + "video/*": { + "schema": { + "type": "string", + "format": "binary" + } + }, + "audio/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/{itemId}/Similar": { + "get": { + "tags": ["Library"], + "summary": "Gets similar items.", + "operationId": "GetSimilarItems", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "excludeArtistIds", + "in": "query", + "description": "Exclude artist ids.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user id, and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + } + ], + "responses": { + "200": { + "description": "Similar items returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/{itemId}/ThemeMedia": { + "get": { + "tags": ["Library"], + "summary": "Get theme songs and videos for an item.", + "operationId": "GetThemeMedia", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user id, and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "inheritFromParent", + "in": "query", + "description": "Optional. Determines whether or not parent items should be searched for theme media.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Theme songs and videos returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AllThemeMediaResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/AllThemeMediaResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/AllThemeMediaResult" + } + } + } + }, + "404": { + "description": "Item not found." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/{itemId}/ThemeSongs": { + "get": { + "tags": ["Library"], + "summary": "Get theme songs for an item.", + "operationId": "GetThemeSongs", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user id, and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "inheritFromParent", + "in": "query", + "description": "Optional. Determines whether or not parent items should be searched for theme media.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Theme songs returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ThemeMediaResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ThemeMediaResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ThemeMediaResult" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/{itemId}/ThemeVideos": { + "get": { + "tags": ["Library"], + "summary": "Get theme videos for an item.", + "operationId": "GetThemeVideos", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user id, and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "inheritFromParent", + "in": "query", + "description": "Optional. Determines whether or not parent items should be searched for theme media.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Theme videos returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ThemeMediaResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ThemeMediaResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ThemeMediaResult" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/Counts": { + "get": { + "tags": ["Library"], + "summary": "Get item counts.", + "operationId": "GetItemCounts", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "Optional. Get counts from a specific user's library.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "isFavorite", + "in": "query", + "description": "Optional. Get counts of favorite items.", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Item counts returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ItemCounts" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ItemCounts" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ItemCounts" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Libraries/AvailableOptions": { + "get": { + "tags": ["Library"], + "summary": "Gets the library options info.", + "operationId": "GetLibraryOptionsInfo", + "parameters": [ + { + "name": "libraryContentType", + "in": "query", + "description": "Library content type.", + "schema": { + "enum": [ + "unknown", + "movies", + "tvshows", + "music", + "musicvideos", + "trailers", + "homevideos", + "boxsets", + "books", + "photos", + "livetv", + "playlists", + "folders" + ], + "allOf": [ + { + "$ref": "#/components/schemas/CollectionType" + } + ] + } + }, + { + "name": "isNewLibrary", + "in": "query", + "description": "Whether this is a new library.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Library options info returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LibraryOptionsResultDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/LibraryOptionsResultDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/LibraryOptionsResultDto" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "FirstTimeSetupOrDefault", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Library/Media/Updated": { + "post": { + "tags": ["Library"], + "summary": "Reports that new movies have been added by an external source.", + "operationId": "PostUpdatedMedia", + "requestBody": { + "description": "The update paths.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/MediaUpdateInfoDto" + } + ], + "description": "Media Update Info Dto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/MediaUpdateInfoDto" + } + ], + "description": "Media Update Info Dto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/MediaUpdateInfoDto" + } + ], + "description": "Media Update Info Dto." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Report success." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Library/MediaFolders": { + "get": { + "tags": ["Library"], + "summary": "Gets all user media folders.", + "operationId": "GetMediaFolders", + "parameters": [ + { + "name": "isHidden", + "in": "query", + "description": "Optional. Filter by folders that are marked hidden, or not.", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Media folders returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Library/Movies/Added": { + "post": { + "tags": ["Library"], + "summary": "Reports that new movies have been added by an external source.", + "operationId": "PostAddedMovies", + "parameters": [ + { + "name": "tmdbId", + "in": "query", + "description": "The tmdbId.", + "schema": { + "type": "string" + } + }, + { + "name": "imdbId", + "in": "query", + "description": "The imdbId.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Report success." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Library/Movies/Updated": { + "post": { + "tags": ["Library"], + "summary": "Reports that new movies have been added by an external source.", + "operationId": "PostUpdatedMovies", + "parameters": [ + { + "name": "tmdbId", + "in": "query", + "description": "The tmdbId.", + "schema": { + "type": "string" + } + }, + { + "name": "imdbId", + "in": "query", + "description": "The imdbId.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Report success." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Library/PhysicalPaths": { + "get": { + "tags": ["Library"], + "summary": "Gets a list of physical paths from virtual folders.", + "operationId": "GetPhysicalPaths", + "responses": { + "200": { + "description": "Physical paths returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Library/Refresh": { + "post": { + "tags": ["Library"], + "summary": "Starts a library scan.", + "operationId": "RefreshLibrary", + "responses": { + "204": { + "description": "Library scan started." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Library/Series/Added": { + "post": { + "tags": ["Library"], + "summary": "Reports that new episodes of a series have been added by an external source.", + "operationId": "PostAddedSeries", + "parameters": [ + { + "name": "tvdbId", + "in": "query", + "description": "The tvdbId.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Report success." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Library/Series/Updated": { + "post": { + "tags": ["Library"], + "summary": "Reports that new episodes of a series have been added by an external source.", + "operationId": "PostUpdatedSeries", + "parameters": [ + { + "name": "tvdbId", + "in": "query", + "description": "The tvdbId.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Report success." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Movies/{itemId}/Similar": { + "get": { + "tags": ["Library"], + "summary": "Gets similar items.", + "operationId": "GetSimilarMovies", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "excludeArtistIds", + "in": "query", + "description": "Exclude artist ids.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user id, and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + } + ], + "responses": { + "200": { + "description": "Similar items returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Shows/{itemId}/Similar": { + "get": { + "tags": ["Library"], + "summary": "Gets similar items.", + "operationId": "GetSimilarShows", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "excludeArtistIds", + "in": "query", + "description": "Exclude artist ids.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user id, and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + } + ], + "responses": { + "200": { + "description": "Similar items returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Trailers/{itemId}/Similar": { + "get": { + "tags": ["Library"], + "summary": "Gets similar items.", + "operationId": "GetSimilarTrailers", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "excludeArtistIds", + "in": "query", + "description": "Exclude artist ids.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user id, and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + } + ], + "responses": { + "200": { + "description": "Similar items returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Library/VirtualFolders": { + "get": { + "tags": ["LibraryStructure"], + "summary": "Gets all virtual folders.", + "operationId": "GetVirtualFolders", + "responses": { + "200": { + "description": "Virtual folders retrieved.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VirtualFolderInfo" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VirtualFolderInfo" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VirtualFolderInfo" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "FirstTimeSetupOrElevated", + "DefaultAuthorization" + ] + } + ] + }, + "post": { + "tags": ["LibraryStructure"], + "summary": "Adds a virtual folder.", + "operationId": "AddVirtualFolder", + "parameters": [ + { + "name": "name", + "in": "query", + "description": "The name of the virtual folder.", + "schema": { + "type": "string" + } + }, + { + "name": "collectionType", + "in": "query", + "description": "The type of the collection.", + "schema": { + "enum": [ + "movies", + "tvshows", + "music", + "musicvideos", + "homevideos", + "boxsets", + "books", + "mixed" + ], + "allOf": [ + { + "$ref": "#/components/schemas/CollectionTypeOptions" + } + ] + } + }, + { + "name": "paths", + "in": "query", + "description": "The paths of the virtual folder.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "refreshLibrary", + "in": "query", + "description": "Whether to refresh the library.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "description": "The library options.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/AddVirtualFolderDto" + } + ], + "description": "Add virtual folder dto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/AddVirtualFolderDto" + } + ], + "description": "Add virtual folder dto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/AddVirtualFolderDto" + } + ], + "description": "Add virtual folder dto." + } + } + } + }, + "responses": { + "204": { + "description": "Folder added." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "FirstTimeSetupOrElevated", + "DefaultAuthorization" + ] + } + ] + }, + "delete": { + "tags": ["LibraryStructure"], + "summary": "Removes a virtual folder.", + "operationId": "RemoveVirtualFolder", + "parameters": [ + { + "name": "name", + "in": "query", + "description": "The name of the folder.", + "schema": { + "type": "string" + } + }, + { + "name": "refreshLibrary", + "in": "query", + "description": "Whether to refresh the library.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "204": { + "description": "Folder removed." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "FirstTimeSetupOrElevated", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Library/VirtualFolders/LibraryOptions": { + "post": { + "tags": ["LibraryStructure"], + "summary": "Update library options.", + "operationId": "UpdateLibraryOptions", + "requestBody": { + "description": "The library name and options.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UpdateLibraryOptionsDto" + } + ], + "description": "Update library options dto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UpdateLibraryOptionsDto" + } + ], + "description": "Update library options dto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UpdateLibraryOptionsDto" + } + ], + "description": "Update library options dto." + } + } + } + }, + "responses": { + "204": { + "description": "Library updated." + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "FirstTimeSetupOrElevated", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Library/VirtualFolders/Name": { + "post": { + "tags": ["LibraryStructure"], + "summary": "Renames a virtual folder.", + "operationId": "RenameVirtualFolder", + "parameters": [ + { + "name": "name", + "in": "query", + "description": "The name of the virtual folder.", + "schema": { + "type": "string" + } + }, + { + "name": "newName", + "in": "query", + "description": "The new name.", + "schema": { + "type": "string" + } + }, + { + "name": "refreshLibrary", + "in": "query", + "description": "Whether to refresh the library.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "204": { + "description": "Folder renamed." + }, + "404": { + "description": "Library doesn't exist.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "409": { + "description": "Library already exists.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "FirstTimeSetupOrElevated", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Library/VirtualFolders/Paths": { + "post": { + "tags": ["LibraryStructure"], + "summary": "Add a media path to a library.", + "operationId": "AddMediaPath", + "parameters": [ + { + "name": "refreshLibrary", + "in": "query", + "description": "Whether to refresh the library.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "description": "The media path dto.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/MediaPathDto" + } + ], + "description": "Media Path dto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/MediaPathDto" + } + ], + "description": "Media Path dto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/MediaPathDto" + } + ], + "description": "Media Path dto." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Media path added." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "FirstTimeSetupOrElevated", + "DefaultAuthorization" + ] + } + ] + }, + "delete": { + "tags": ["LibraryStructure"], + "summary": "Remove a media path.", + "operationId": "RemoveMediaPath", + "parameters": [ + { + "name": "name", + "in": "query", + "description": "The name of the library.", + "schema": { + "type": "string" + } + }, + { + "name": "path", + "in": "query", + "description": "The path to remove.", + "schema": { + "type": "string" + } + }, + { + "name": "refreshLibrary", + "in": "query", + "description": "Whether to refresh the library.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "204": { + "description": "Media path removed." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "FirstTimeSetupOrElevated", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Library/VirtualFolders/Paths/Update": { + "post": { + "tags": ["LibraryStructure"], + "summary": "Updates a media path.", + "operationId": "UpdateMediaPath", + "requestBody": { + "description": "The name of the library and path infos.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UpdateMediaPathRequestDto" + } + ], + "description": "Update library options dto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UpdateMediaPathRequestDto" + } + ], + "description": "Update library options dto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UpdateMediaPathRequestDto" + } + ], + "description": "Update library options dto." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Media path updated." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "FirstTimeSetupOrElevated", + "DefaultAuthorization" + ] + } + ] + } + }, + "/LiveTv/ChannelMappingOptions": { + "get": { + "tags": ["LiveTv"], + "summary": "Get channel mapping options.", + "operationId": "GetChannelMappingOptions", + "parameters": [ + { + "name": "providerId", + "in": "query", + "description": "Provider id.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Channel mapping options returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChannelMappingOptionsDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ChannelMappingOptionsDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ChannelMappingOptionsDto" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvAccess", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/ChannelMappings": { + "post": { + "tags": ["LiveTv"], + "summary": "Set channel mappings.", + "operationId": "SetChannelMapping", + "requestBody": { + "description": "The set channel mapping dto.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SetChannelMappingDto" + } + ], + "description": "Set channel mapping dto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SetChannelMappingDto" + } + ], + "description": "Set channel mapping dto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SetChannelMappingDto" + } + ], + "description": "Set channel mapping dto." + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Created channel mapping returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TunerChannelMapping" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/TunerChannelMapping" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/TunerChannelMapping" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvManagement", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/Channels": { + "get": { + "tags": ["LiveTv"], + "summary": "Gets available live tv channels.", + "operationId": "GetLiveTvChannels", + "parameters": [ + { + "name": "type", + "in": "query", + "description": "Optional. Filter by channel type.", + "schema": { + "enum": ["TV", "Radio"], + "allOf": [ + { + "$ref": "#/components/schemas/ChannelType" + } + ] + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "startIndex", + "in": "query", + "description": "Optional. The record index to start at. All items with a lower index will be dropped from the results.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "isMovie", + "in": "query", + "description": "Optional. Filter for movies.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isSeries", + "in": "query", + "description": "Optional. Filter for series.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isNews", + "in": "query", + "description": "Optional. Filter for news.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isKids", + "in": "query", + "description": "Optional. Filter for kids.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isSports", + "in": "query", + "description": "Optional. Filter for sports.", + "schema": { + "type": "boolean" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "isFavorite", + "in": "query", + "description": "Optional. Filter by channels that are favorites, or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isLiked", + "in": "query", + "description": "Optional. Filter by channels that are liked, or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isDisliked", + "in": "query", + "description": "Optional. Filter by channels that are disliked, or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional. Include image information in output.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional. The max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "\"Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "enableUserData", + "in": "query", + "description": "Optional. Include user data.", + "schema": { + "type": "boolean" + } + }, + { + "name": "sortBy", + "in": "query", + "description": "Optional. Key to sort by.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemSortBy" + } + } + }, + { + "name": "sortOrder", + "in": "query", + "description": "Optional. Sort order.", + "schema": { + "enum": ["Ascending", "Descending"], + "allOf": [ + { + "$ref": "#/components/schemas/SortOrder" + } + ] + } + }, + { + "name": "enableFavoriteSorting", + "in": "query", + "description": "Optional. Incorporate favorite and like status into channel sorting.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "addCurrentProgram", + "in": "query", + "description": "Optional. Adds current program info to each channel.", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Available live tv channels returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvAccess", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/Channels/{channelId}": { + "get": { + "tags": ["LiveTv"], + "summary": "Gets a live tv channel.", + "operationId": "GetChannel", + "parameters": [ + { + "name": "channelId", + "in": "path", + "description": "Channel id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Live tv channel returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvAccess", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/GuideInfo": { + "get": { + "tags": ["LiveTv"], + "summary": "Get guid info.", + "operationId": "GetGuideInfo", + "responses": { + "200": { + "description": "Guid info returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuideInfo" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/GuideInfo" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/GuideInfo" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvAccess", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/Info": { + "get": { + "tags": ["LiveTv"], + "summary": "Gets available live tv services.", + "operationId": "GetLiveTvInfo", + "responses": { + "200": { + "description": "Available live tv services returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LiveTvInfo" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/LiveTvInfo" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/LiveTvInfo" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvAccess", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/ListingProviders": { + "post": { + "tags": ["LiveTv"], + "summary": "Adds a listings provider.", + "operationId": "AddListingProvider", + "parameters": [ + { + "name": "pw", + "in": "query", + "description": "Password.", + "schema": { + "type": "string" + } + }, + { + "name": "validateListings", + "in": "query", + "description": "Validate listings.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "validateLogin", + "in": "query", + "description": "Validate login.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "description": "New listings info.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ListingsProviderInfo" + } + ] + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ListingsProviderInfo" + } + ] + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ListingsProviderInfo" + } + ] + } + } + } + }, + "responses": { + "200": { + "description": "Created listings provider returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListingsProviderInfo" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ListingsProviderInfo" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ListingsProviderInfo" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvManagement", "DefaultAuthorization"] + } + ] + }, + "delete": { + "tags": ["LiveTv"], + "summary": "Delete listing provider.", + "operationId": "DeleteListingProvider", + "parameters": [ + { + "name": "id", + "in": "query", + "description": "Listing provider id.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Listing provider deleted." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvManagement", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/ListingProviders/Default": { + "get": { + "tags": ["LiveTv"], + "summary": "Gets default listings provider info.", + "operationId": "GetDefaultListingProvider", + "responses": { + "200": { + "description": "Default listings provider info returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListingsProviderInfo" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ListingsProviderInfo" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ListingsProviderInfo" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvAccess", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/ListingProviders/Lineups": { + "get": { + "tags": ["LiveTv"], + "summary": "Gets available lineups.", + "operationId": "GetLineups", + "parameters": [ + { + "name": "id", + "in": "query", + "description": "Provider id.", + "schema": { + "type": "string" + } + }, + { + "name": "type", + "in": "query", + "description": "Provider type.", + "schema": { + "type": "string" + } + }, + { + "name": "location", + "in": "query", + "description": "Location.", + "schema": { + "type": "string" + } + }, + { + "name": "country", + "in": "query", + "description": "Country.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Available lineups returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NameIdPair" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NameIdPair" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NameIdPair" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvAccess", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/ListingProviders/SchedulesDirect/Countries": { + "get": { + "tags": ["LiveTv"], + "summary": "Gets available countries.", + "operationId": "GetSchedulesDirectCountries", + "responses": { + "200": { + "description": "Available countries returned.", + "content": { + "application/json": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvAccess", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/LiveRecordings/{recordingId}/stream": { + "get": { + "tags": ["LiveTv"], + "summary": "Gets a live tv recording stream.", + "operationId": "GetLiveRecordingFile", + "parameters": [ + { + "name": "recordingId", + "in": "path", + "description": "Recording id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Recording stream returned.", + "content": { + "video/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Recording not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + } + }, + "/LiveTv/LiveStreamFiles/{streamId}/stream.{container}": { + "get": { + "tags": ["LiveTv"], + "summary": "Gets a live tv channel stream.", + "operationId": "GetLiveStreamFile", + "parameters": [ + { + "name": "streamId", + "in": "path", + "description": "Stream id.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "container", + "in": "path", + "description": "Container type.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Stream returned.", + "content": { + "video/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Stream not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + } + }, + "/LiveTv/Programs": { + "get": { + "tags": ["LiveTv"], + "summary": "Gets available live tv epgs.", + "operationId": "GetLiveTvPrograms", + "parameters": [ + { + "name": "channelIds", + "in": "query", + "description": "The channels to return guide information for.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "minStartDate", + "in": "query", + "description": "Optional. The minimum premiere start date.", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "hasAired", + "in": "query", + "description": "Optional. Filter by programs that have completed airing, or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isAiring", + "in": "query", + "description": "Optional. Filter by programs that are currently airing, or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "maxStartDate", + "in": "query", + "description": "Optional. The maximum premiere start date.", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "minEndDate", + "in": "query", + "description": "Optional. The minimum premiere end date.", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "maxEndDate", + "in": "query", + "description": "Optional. The maximum premiere end date.", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "isMovie", + "in": "query", + "description": "Optional. Filter for movies.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isSeries", + "in": "query", + "description": "Optional. Filter for series.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isNews", + "in": "query", + "description": "Optional. Filter for news.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isKids", + "in": "query", + "description": "Optional. Filter for kids.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isSports", + "in": "query", + "description": "Optional. Filter for sports.", + "schema": { + "type": "boolean" + } + }, + { + "name": "startIndex", + "in": "query", + "description": "Optional. The record index to start at. All items with a lower index will be dropped from the results.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "sortBy", + "in": "query", + "description": "Optional. Specify one or more sort orders, comma delimited. Options: Name, StartDate.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemSortBy" + } + } + }, + { + "name": "sortOrder", + "in": "query", + "description": "Sort Order - Ascending,Descending.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SortOrder" + } + } + }, + { + "name": "genres", + "in": "query", + "description": "The genres to return guide information for.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "genreIds", + "in": "query", + "description": "The genre ids to return guide information for.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional. Include image information in output.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional. The max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + }, + { + "name": "enableUserData", + "in": "query", + "description": "Optional. Include user data.", + "schema": { + "type": "boolean" + } + }, + { + "name": "seriesTimerId", + "in": "query", + "description": "Optional. Filter by series timer id.", + "schema": { + "type": "string" + } + }, + { + "name": "librarySeriesId", + "in": "query", + "description": "Optional. Filter by library series id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "enableTotalRecordCount", + "in": "query", + "description": "Retrieve total record count.", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Live tv epgs returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvAccess", "DefaultAuthorization"] + } + ] + }, + "post": { + "tags": ["LiveTv"], + "summary": "Gets available live tv epgs.", + "operationId": "GetPrograms", + "requestBody": { + "description": "Request body.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/GetProgramsDto" + } + ], + "description": "Get programs dto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/GetProgramsDto" + } + ], + "description": "Get programs dto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/GetProgramsDto" + } + ], + "description": "Get programs dto." + } + } + } + }, + "responses": { + "200": { + "description": "Live tv epgs returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvAccess", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/Programs/{programId}": { + "get": { + "tags": ["LiveTv"], + "summary": "Gets a live tv program.", + "operationId": "GetProgram", + "parameters": [ + { + "name": "programId", + "in": "path", + "description": "Program id.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Program returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvAccess", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/Programs/Recommended": { + "get": { + "tags": ["LiveTv"], + "summary": "Gets recommended live tv epgs.", + "operationId": "GetRecommendedPrograms", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "Optional. filter by user id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "isAiring", + "in": "query", + "description": "Optional. Filter by programs that are currently airing, or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "hasAired", + "in": "query", + "description": "Optional. Filter by programs that have completed airing, or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isSeries", + "in": "query", + "description": "Optional. Filter for series.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isMovie", + "in": "query", + "description": "Optional. Filter for movies.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isNews", + "in": "query", + "description": "Optional. Filter for news.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isKids", + "in": "query", + "description": "Optional. Filter for kids.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isSports", + "in": "query", + "description": "Optional. Filter for sports.", + "schema": { + "type": "boolean" + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional. Include image information in output.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional. The max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + }, + { + "name": "genreIds", + "in": "query", + "description": "The genres to return guide information for.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "enableUserData", + "in": "query", + "description": "Optional. include user data.", + "schema": { + "type": "boolean" + } + }, + { + "name": "enableTotalRecordCount", + "in": "query", + "description": "Retrieve total record count.", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Recommended epgs returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvAccess", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/Recordings": { + "get": { + "tags": ["LiveTv"], + "summary": "Gets live tv recordings.", + "operationId": "GetRecordings", + "parameters": [ + { + "name": "channelId", + "in": "query", + "description": "Optional. Filter by channel id.", + "schema": { + "type": "string" + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "startIndex", + "in": "query", + "description": "Optional. The record index to start at. All items with a lower index will be dropped from the results.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "status", + "in": "query", + "description": "Optional. Filter by recording status.", + "schema": { + "enum": [ + "New", + "InProgress", + "Completed", + "Cancelled", + "ConflictedOk", + "ConflictedNotOk", + "Error" + ], + "allOf": [ + { + "$ref": "#/components/schemas/RecordingStatus" + } + ] + } + }, + { + "name": "isInProgress", + "in": "query", + "description": "Optional. Filter by recordings that are in progress, or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "seriesTimerId", + "in": "query", + "description": "Optional. Filter by recordings belonging to a series timer.", + "schema": { + "type": "string" + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional. Include image information in output.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional. The max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "enableUserData", + "in": "query", + "description": "Optional. Include user data.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isMovie", + "in": "query", + "description": "Optional. Filter for movies.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isSeries", + "in": "query", + "description": "Optional. Filter for series.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isKids", + "in": "query", + "description": "Optional. Filter for kids.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isSports", + "in": "query", + "description": "Optional. Filter for sports.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isNews", + "in": "query", + "description": "Optional. Filter for news.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isLibraryItem", + "in": "query", + "description": "Optional. Filter for is library item.", + "schema": { + "type": "boolean" + } + }, + { + "name": "enableTotalRecordCount", + "in": "query", + "description": "Optional. Return total record count.", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Live tv recordings returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvAccess", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/Recordings/{recordingId}": { + "get": { + "tags": ["LiveTv"], + "summary": "Gets a live tv recording.", + "operationId": "GetRecording", + "parameters": [ + { + "name": "recordingId", + "in": "path", + "description": "Recording id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Recording returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvAccess", "DefaultAuthorization"] + } + ] + }, + "delete": { + "tags": ["LiveTv"], + "summary": "Deletes a live tv recording.", + "operationId": "DeleteRecording", + "parameters": [ + { + "name": "recordingId", + "in": "path", + "description": "Recording id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "204": { + "description": "Recording deleted." + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvManagement", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/Recordings/Folders": { + "get": { + "tags": ["LiveTv"], + "summary": "Gets recording folders.", + "operationId": "GetRecordingFolders", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Recording folders returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvAccess", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/Recordings/Groups": { + "get": { + "tags": ["LiveTv"], + "summary": "Gets live tv recording groups.", + "operationId": "GetRecordingGroups", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Recording groups returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "deprecated": true, + "security": [ + { + "CustomAuthentication": ["LiveTvAccess", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/Recordings/Groups/{groupId}": { + "get": { + "tags": ["LiveTv"], + "summary": "Get recording group.", + "operationId": "GetRecordingGroup", + "parameters": [ + { + "name": "groupId", + "in": "path", + "description": "Group id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "deprecated": true, + "security": [ + { + "CustomAuthentication": ["LiveTvAccess", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/Recordings/Series": { + "get": { + "tags": ["LiveTv"], + "summary": "Gets live tv recording series.", + "operationId": "GetRecordingsSeries", + "parameters": [ + { + "name": "channelId", + "in": "query", + "description": "Optional. Filter by channel id.", + "schema": { + "type": "string" + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "groupId", + "in": "query", + "description": "Optional. Filter by recording group.", + "schema": { + "type": "string" + } + }, + { + "name": "startIndex", + "in": "query", + "description": "Optional. The record index to start at. All items with a lower index will be dropped from the results.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "status", + "in": "query", + "description": "Optional. Filter by recording status.", + "schema": { + "enum": [ + "New", + "InProgress", + "Completed", + "Cancelled", + "ConflictedOk", + "ConflictedNotOk", + "Error" + ], + "allOf": [ + { + "$ref": "#/components/schemas/RecordingStatus" + } + ] + } + }, + { + "name": "isInProgress", + "in": "query", + "description": "Optional. Filter by recordings that are in progress, or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "seriesTimerId", + "in": "query", + "description": "Optional. Filter by recordings belonging to a series timer.", + "schema": { + "type": "string" + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional. Include image information in output.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional. The max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "enableUserData", + "in": "query", + "description": "Optional. Include user data.", + "schema": { + "type": "boolean" + } + }, + { + "name": "enableTotalRecordCount", + "in": "query", + "description": "Optional. Return total record count.", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Live tv recordings returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "deprecated": true, + "security": [ + { + "CustomAuthentication": ["LiveTvAccess", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/SeriesTimers": { + "get": { + "tags": ["LiveTv"], + "summary": "Gets live tv series timers.", + "operationId": "GetSeriesTimers", + "parameters": [ + { + "name": "sortBy", + "in": "query", + "description": "Optional. Sort by SortName or Priority.", + "schema": { + "type": "string" + } + }, + { + "name": "sortOrder", + "in": "query", + "description": "Optional. Sort in Ascending or Descending order.", + "schema": { + "enum": ["Ascending", "Descending"], + "allOf": [ + { + "$ref": "#/components/schemas/SortOrder" + } + ] + } + } + ], + "responses": { + "200": { + "description": "Timers returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SeriesTimerInfoDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/SeriesTimerInfoDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/SeriesTimerInfoDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvAccess", "DefaultAuthorization"] + } + ] + }, + "post": { + "tags": ["LiveTv"], + "summary": "Creates a live tv series timer.", + "operationId": "CreateSeriesTimer", + "requestBody": { + "description": "New series timer info.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SeriesTimerInfoDto" + } + ], + "description": "Class SeriesTimerInfoDto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SeriesTimerInfoDto" + } + ], + "description": "Class SeriesTimerInfoDto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SeriesTimerInfoDto" + } + ], + "description": "Class SeriesTimerInfoDto." + } + } + } + }, + "responses": { + "204": { + "description": "Series timer info created." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvManagement", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/SeriesTimers/{timerId}": { + "get": { + "tags": ["LiveTv"], + "summary": "Gets a live tv series timer.", + "operationId": "GetSeriesTimer", + "parameters": [ + { + "name": "timerId", + "in": "path", + "description": "Timer id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Series timer returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SeriesTimerInfoDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/SeriesTimerInfoDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/SeriesTimerInfoDto" + } + } + } + }, + "404": { + "description": "Series timer not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvAccess", "DefaultAuthorization"] + } + ] + }, + "delete": { + "tags": ["LiveTv"], + "summary": "Cancels a live tv series timer.", + "operationId": "CancelSeriesTimer", + "parameters": [ + { + "name": "timerId", + "in": "path", + "description": "Timer id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Timer cancelled." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvManagement", "DefaultAuthorization"] + } + ] + }, + "post": { + "tags": ["LiveTv"], + "summary": "Updates a live tv series timer.", + "operationId": "UpdateSeriesTimer", + "parameters": [ + { + "name": "timerId", + "in": "path", + "description": "Timer id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "New series timer info.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SeriesTimerInfoDto" + } + ], + "description": "Class SeriesTimerInfoDto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SeriesTimerInfoDto" + } + ], + "description": "Class SeriesTimerInfoDto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SeriesTimerInfoDto" + } + ], + "description": "Class SeriesTimerInfoDto." + } + } + } + }, + "responses": { + "204": { + "description": "Series timer updated." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvManagement", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/Timers": { + "get": { + "tags": ["LiveTv"], + "summary": "Gets the live tv timers.", + "operationId": "GetTimers", + "parameters": [ + { + "name": "channelId", + "in": "query", + "description": "Optional. Filter by channel id.", + "schema": { + "type": "string" + } + }, + { + "name": "seriesTimerId", + "in": "query", + "description": "Optional. Filter by timers belonging to a series timer.", + "schema": { + "type": "string" + } + }, + { + "name": "isActive", + "in": "query", + "description": "Optional. Filter by timers that are active.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isScheduled", + "in": "query", + "description": "Optional. Filter by timers that are scheduled.", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TimerInfoDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/TimerInfoDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/TimerInfoDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvAccess", "DefaultAuthorization"] + } + ] + }, + "post": { + "tags": ["LiveTv"], + "summary": "Creates a live tv timer.", + "operationId": "CreateTimer", + "requestBody": { + "description": "New timer info.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/TimerInfoDto" + } + ] + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/TimerInfoDto" + } + ] + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/TimerInfoDto" + } + ] + } + } + } + }, + "responses": { + "204": { + "description": "Timer created." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvManagement", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/Timers/{timerId}": { + "get": { + "tags": ["LiveTv"], + "summary": "Gets a timer.", + "operationId": "GetTimer", + "parameters": [ + { + "name": "timerId", + "in": "path", + "description": "Timer id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Timer returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TimerInfoDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/TimerInfoDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/TimerInfoDto" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvAccess", "DefaultAuthorization"] + } + ] + }, + "delete": { + "tags": ["LiveTv"], + "summary": "Cancels a live tv timer.", + "operationId": "CancelTimer", + "parameters": [ + { + "name": "timerId", + "in": "path", + "description": "Timer id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Timer deleted." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvManagement", "DefaultAuthorization"] + } + ] + }, + "post": { + "tags": ["LiveTv"], + "summary": "Updates a live tv timer.", + "operationId": "UpdateTimer", + "parameters": [ + { + "name": "timerId", + "in": "path", + "description": "Timer id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "New timer info.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/TimerInfoDto" + } + ] + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/TimerInfoDto" + } + ] + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/TimerInfoDto" + } + ] + } + } + } + }, + "responses": { + "204": { + "description": "Timer updated." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvManagement", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/Timers/Defaults": { + "get": { + "tags": ["LiveTv"], + "summary": "Gets the default values for a new timer.", + "operationId": "GetDefaultTimer", + "parameters": [ + { + "name": "programId", + "in": "query", + "description": "Optional. To attach default values based on a program.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Default values returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SeriesTimerInfoDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/SeriesTimerInfoDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/SeriesTimerInfoDto" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvAccess", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/TunerHosts": { + "post": { + "tags": ["LiveTv"], + "summary": "Adds a tuner host.", + "operationId": "AddTunerHost", + "requestBody": { + "description": "New tuner host.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/TunerHostInfo" + } + ] + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/TunerHostInfo" + } + ] + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/TunerHostInfo" + } + ] + } + } + } + }, + "responses": { + "200": { + "description": "Created tuner host returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TunerHostInfo" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/TunerHostInfo" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/TunerHostInfo" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvManagement", "DefaultAuthorization"] + } + ] + }, + "delete": { + "tags": ["LiveTv"], + "summary": "Deletes a tuner host.", + "operationId": "DeleteTunerHost", + "parameters": [ + { + "name": "id", + "in": "query", + "description": "Tuner host id.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Tuner host deleted." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvManagement", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/TunerHosts/Types": { + "get": { + "tags": ["LiveTv"], + "summary": "Get tuner host types.", + "operationId": "GetTunerHostTypes", + "responses": { + "200": { + "description": "Tuner host types returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NameIdPair" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NameIdPair" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NameIdPair" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvAccess", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/Tuners/{tunerId}/Reset": { + "post": { + "tags": ["LiveTv"], + "summary": "Resets a tv tuner.", + "operationId": "ResetTuner", + "parameters": [ + { + "name": "tunerId", + "in": "path", + "description": "Tuner id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Tuner reset." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvManagement", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/Tuners/Discover": { + "get": { + "tags": ["LiveTv"], + "summary": "Discover tuners.", + "operationId": "DiscoverTuners", + "parameters": [ + { + "name": "newDevicesOnly", + "in": "query", + "description": "Only discover new tuners.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Tuners returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TunerHostInfo" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TunerHostInfo" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TunerHostInfo" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvManagement", "DefaultAuthorization"] + } + ] + } + }, + "/LiveTv/Tuners/Discvover": { + "get": { + "tags": ["LiveTv"], + "summary": "Discover tuners.", + "operationId": "DiscvoverTuners", + "parameters": [ + { + "name": "newDevicesOnly", + "in": "query", + "description": "Only discover new tuners.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Tuners returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TunerHostInfo" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TunerHostInfo" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TunerHostInfo" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LiveTvManagement", "DefaultAuthorization"] + } + ] + } + }, + "/Localization/Countries": { + "get": { + "tags": ["Localization"], + "summary": "Gets known countries.", + "operationId": "GetCountries", + "responses": { + "200": { + "description": "Known countries returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CountryInfo" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CountryInfo" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CountryInfo" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "FirstTimeSetupOrDefault", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Localization/Cultures": { + "get": { + "tags": ["Localization"], + "summary": "Gets known cultures.", + "operationId": "GetCultures", + "responses": { + "200": { + "description": "Known cultures returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CultureDto" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CultureDto" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CultureDto" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "FirstTimeSetupOrDefault", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Localization/Options": { + "get": { + "tags": ["Localization"], + "summary": "Gets localization options.", + "operationId": "GetLocalizationOptions", + "responses": { + "200": { + "description": "Localization options returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LocalizationOption" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LocalizationOption" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LocalizationOption" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "FirstTimeSetupOrDefault", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Localization/ParentalRatings": { + "get": { + "tags": ["Localization"], + "summary": "Gets known parental ratings.", + "operationId": "GetParentalRatings", + "responses": { + "200": { + "description": "Known parental ratings returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ParentalRating" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ParentalRating" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ParentalRating" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "FirstTimeSetupOrDefault", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Audio/{itemId}/Lyrics": { + "get": { + "tags": ["Lyrics"], + "summary": "Gets an item's lyrics.", + "operationId": "GetLyrics", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Lyrics returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LyricDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/LyricDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/LyricDto" + } + } + } + }, + "404": { + "description": "Something went wrong. No Lyrics will be returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + }, + "post": { + "tags": ["Lyrics"], + "summary": "Upload an external lyric file.", + "operationId": "UploadLyrics", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item the lyric belongs to.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "fileName", + "in": "query", + "description": "Name of the file being uploaded.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "text/plain": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "responses": { + "200": { + "description": "Lyrics uploaded.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LyricDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/LyricDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/LyricDto" + } + } + } + }, + "400": { + "description": "Error processing upload.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LyricManagement", "DefaultAuthorization"] + } + ] + }, + "delete": { + "tags": ["Lyrics"], + "summary": "Deletes an external lyric file.", + "operationId": "DeleteLyrics", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "204": { + "description": "Lyric deleted." + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LyricManagement", "DefaultAuthorization"] + } + ] + } + }, + "/Audio/{itemId}/RemoteSearch/Lyrics": { + "get": { + "tags": ["Lyrics"], + "summary": "Search remote lyrics.", + "operationId": "SearchRemoteLyrics", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Lyrics retrieved.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteLyricInfoDto" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteLyricInfoDto" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteLyricInfoDto" + } + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LyricManagement", "DefaultAuthorization"] + } + ] + } + }, + "/Audio/{itemId}/RemoteSearch/Lyrics/{lyricId}": { + "post": { + "tags": ["Lyrics"], + "summary": "Downloads a remote lyric.", + "operationId": "DownloadRemoteLyrics", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "lyricId", + "in": "path", + "description": "The lyric id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Lyric downloaded.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LyricDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/LyricDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/LyricDto" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LyricManagement", "DefaultAuthorization"] + } + ] + } + }, + "/Providers/Lyrics/{lyricId}": { + "get": { + "tags": ["Lyrics"], + "summary": "Gets the remote lyrics.", + "operationId": "GetRemoteLyrics", + "parameters": [ + { + "name": "lyricId", + "in": "path", + "description": "The remote provider item id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "File returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LyricDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/LyricDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/LyricDto" + } + } + } + }, + "404": { + "description": "Lyric not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["LyricManagement", "DefaultAuthorization"] + } + ] + } + }, + "/Items/{itemId}/PlaybackInfo": { + "get": { + "tags": ["MediaInfo"], + "summary": "Gets live playback media info for an item.", + "operationId": "GetPlaybackInfo", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "userId", + "in": "query", + "description": "The user id.", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Playback info returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PlaybackInfoResponse" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/PlaybackInfoResponse" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/PlaybackInfoResponse" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + }, + "post": { + "tags": ["MediaInfo"], + "summary": "Gets live playback media info for an item.", + "description": "For backwards compatibility parameters can be sent via Query or Body, with Query having higher precedence.\r\nQuery parameters are obsolete.", + "operationId": "GetPostedPlaybackInfo", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "userId", + "in": "query", + "description": "The user id.", + "deprecated": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "maxStreamingBitrate", + "in": "query", + "description": "The maximum streaming bitrate.", + "deprecated": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "startTimeTicks", + "in": "query", + "description": "The start time in ticks.", + "deprecated": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "audioStreamIndex", + "in": "query", + "description": "The audio stream index.", + "deprecated": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleStreamIndex", + "in": "query", + "description": "The subtitle stream index.", + "deprecated": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioChannels", + "in": "query", + "description": "The maximum number of audio channels.", + "deprecated": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "The media source id.", + "deprecated": true, + "schema": { + "type": "string" + } + }, + { + "name": "liveStreamId", + "in": "query", + "description": "The livestream id.", + "deprecated": true, + "schema": { + "type": "string" + } + }, + { + "name": "autoOpenLiveStream", + "in": "query", + "description": "Whether to auto open the livestream.", + "deprecated": true, + "schema": { + "type": "boolean" + } + }, + { + "name": "enableDirectPlay", + "in": "query", + "description": "Whether to enable direct play. Default: true.", + "deprecated": true, + "schema": { + "type": "boolean" + } + }, + { + "name": "enableDirectStream", + "in": "query", + "description": "Whether to enable direct stream. Default: true.", + "deprecated": true, + "schema": { + "type": "boolean" + } + }, + { + "name": "enableTranscoding", + "in": "query", + "description": "Whether to enable transcoding. Default: true.", + "deprecated": true, + "schema": { + "type": "boolean" + } + }, + { + "name": "allowVideoStreamCopy", + "in": "query", + "description": "Whether to allow to copy the video stream. Default: true.", + "deprecated": true, + "schema": { + "type": "boolean" + } + }, + { + "name": "allowAudioStreamCopy", + "in": "query", + "description": "Whether to allow to copy the audio stream. Default: true.", + "deprecated": true, + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "description": "The playback info.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PlaybackInfoDto" + } + ], + "description": "Plabyback info dto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PlaybackInfoDto" + } + ], + "description": "Plabyback info dto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PlaybackInfoDto" + } + ], + "description": "Plabyback info dto." + } + } + } + }, + "responses": { + "200": { + "description": "Playback info returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PlaybackInfoResponse" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/PlaybackInfoResponse" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/PlaybackInfoResponse" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/LiveStreams/Close": { + "post": { + "tags": ["MediaInfo"], + "summary": "Closes a media source.", + "operationId": "CloseLiveStream", + "parameters": [ + { + "name": "liveStreamId", + "in": "query", + "description": "The livestream id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Livestream closed." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/LiveStreams/Open": { + "post": { + "tags": ["MediaInfo"], + "summary": "Opens a media source.", + "operationId": "OpenLiveStream", + "parameters": [ + { + "name": "openToken", + "in": "query", + "description": "The open token.", + "schema": { + "type": "string" + } + }, + { + "name": "userId", + "in": "query", + "description": "The user id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "playSessionId", + "in": "query", + "description": "The play session id.", + "schema": { + "type": "string" + } + }, + { + "name": "maxStreamingBitrate", + "in": "query", + "description": "The maximum streaming bitrate.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "startTimeTicks", + "in": "query", + "description": "The start time in ticks.", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "audioStreamIndex", + "in": "query", + "description": "The audio stream index.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleStreamIndex", + "in": "query", + "description": "The subtitle stream index.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioChannels", + "in": "query", + "description": "The maximum number of audio channels.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "itemId", + "in": "query", + "description": "The item id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "enableDirectPlay", + "in": "query", + "description": "Whether to enable direct play. Default: true.", + "schema": { + "type": "boolean" + } + }, + { + "name": "enableDirectStream", + "in": "query", + "description": "Whether to enable direct stream. Default: true.", + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "description": "The open live stream dto.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/OpenLiveStreamDto" + } + ], + "description": "Open live stream dto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/OpenLiveStreamDto" + } + ], + "description": "Open live stream dto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/OpenLiveStreamDto" + } + ], + "description": "Open live stream dto." + } + } + } + }, + "responses": { + "200": { + "description": "Media source opened.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LiveStreamResponse" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/LiveStreamResponse" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/LiveStreamResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Playback/BitrateTest": { + "get": { + "tags": ["MediaInfo"], + "summary": "Tests the network with a request with the size of the bitrate.", + "operationId": "GetBitrateTestBytes", + "parameters": [ + { + "name": "size", + "in": "query", + "description": "The bitrate. Defaults to 102400.", + "schema": { + "maximum": 100000000, + "minimum": 1, + "type": "integer", + "format": "int32", + "default": 102400 + } + } + ], + "responses": { + "200": { + "description": "Test buffer returned.", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Movies/Recommendations": { + "get": { + "tags": ["Movies"], + "summary": "Gets movie recommendations.", + "operationId": "GetMovieRecommendations", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user id, and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "parentId", + "in": "query", + "description": "Specify this to localize the search to a specific item or folder. Omit to use the root.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. The fields to return.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "categoryLimit", + "in": "query", + "description": "The max number of categories to return.", + "schema": { + "type": "integer", + "format": "int32", + "default": 5 + } + }, + { + "name": "itemLimit", + "in": "query", + "description": "The max number of items to return per category.", + "schema": { + "type": "integer", + "format": "int32", + "default": 8 + } + } + ], + "responses": { + "200": { + "description": "Movie recommendations returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RecommendationDto" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RecommendationDto" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RecommendationDto" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/MusicGenres": { + "get": { + "tags": ["MusicGenres"], + "summary": "Gets all music genres from a given item, folder, or the entire library.", + "operationId": "GetMusicGenres", + "parameters": [ + { + "name": "startIndex", + "in": "query", + "description": "Optional. The record index to start at. All items with a lower index will be dropped from the results.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "searchTerm", + "in": "query", + "description": "The search term.", + "schema": { + "type": "string" + } + }, + { + "name": "parentId", + "in": "query", + "description": "Specify this to localize the search to a specific item or folder. Omit to use the root.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "excludeItemTypes", + "in": "query", + "description": "Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemKind" + } + } + }, + { + "name": "includeItemTypes", + "in": "query", + "description": "Optional. If specified, results will be filtered in based on item type. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemKind" + } + } + }, + { + "name": "isFavorite", + "in": "query", + "description": "Optional filter by items that are marked as favorite, or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional, the max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + }, + { + "name": "userId", + "in": "query", + "description": "User id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "nameStartsWithOrGreater", + "in": "query", + "description": "Optional filter by items whose name is sorted equally or greater than a given input string.", + "schema": { + "type": "string" + } + }, + { + "name": "nameStartsWith", + "in": "query", + "description": "Optional filter by items whose name is sorted equally than a given input string.", + "schema": { + "type": "string" + } + }, + { + "name": "nameLessThan", + "in": "query", + "description": "Optional filter by items whose name is equally or lesser than a given input string.", + "schema": { + "type": "string" + } + }, + { + "name": "sortBy", + "in": "query", + "description": "Optional. Specify one or more sort orders, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemSortBy" + } + } + }, + { + "name": "sortOrder", + "in": "query", + "description": "Sort Order - Ascending,Descending.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SortOrder" + } + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional, include image information in output.", + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "enableTotalRecordCount", + "in": "query", + "description": "Optional. Include total record count.", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Music genres returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "deprecated": true, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/MusicGenres/{genreName}": { + "get": { + "tags": ["MusicGenres"], + "summary": "Gets a music genre, by name.", + "operationId": "GetMusicGenre", + "parameters": [ + { + "name": "genreName", + "in": "path", + "description": "The genre name.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user id, and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Packages": { + "get": { + "tags": ["Package"], + "summary": "Gets available packages.", + "operationId": "GetPackages", + "responses": { + "200": { + "description": "Available packages returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PackageInfo" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PackageInfo" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PackageInfo" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Packages/{name}": { + "get": { + "tags": ["Package"], + "summary": "Gets a package by name or assembly GUID.", + "operationId": "GetPackageInfo", + "parameters": [ + { + "name": "name", + "in": "path", + "description": "The name of the package.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "assemblyGuid", + "in": "query", + "description": "The GUID of the associated assembly.", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Package retrieved.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PackageInfo" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/PackageInfo" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/PackageInfo" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Packages/Installed/{name}": { + "post": { + "tags": ["Package"], + "summary": "Installs a package.", + "operationId": "InstallPackage", + "parameters": [ + { + "name": "name", + "in": "path", + "description": "Package name.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "assemblyGuid", + "in": "query", + "description": "GUID of the associated assembly.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "version", + "in": "query", + "description": "Optional version. Defaults to latest version.", + "schema": { + "type": "string" + } + }, + { + "name": "repositoryUrl", + "in": "query", + "description": "Optional. Specify the repository to install from.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Package found." + }, + "404": { + "description": "Package not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Packages/Installing/{packageId}": { + "delete": { + "tags": ["Package"], + "summary": "Cancels a package installation.", + "operationId": "CancelPackageInstallation", + "parameters": [ + { + "name": "packageId", + "in": "path", + "description": "Installation Id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "204": { + "description": "Installation cancelled." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Repositories": { + "get": { + "tags": ["Package"], + "summary": "Gets all package repositories.", + "operationId": "GetRepositories", + "responses": { + "200": { + "description": "Package repositories returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RepositoryInfo" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RepositoryInfo" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RepositoryInfo" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + }, + "post": { + "tags": ["Package"], + "summary": "Sets the enabled and existing package repositories.", + "operationId": "SetRepositories", + "requestBody": { + "description": "The list of package repositories.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RepositoryInfo" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RepositoryInfo" + } + } + }, + "application/*+json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RepositoryInfo" + } + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Package repositories saved." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Persons": { + "get": { + "tags": ["Persons"], + "summary": "Gets all persons.", + "operationId": "GetPersons", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "searchTerm", + "in": "query", + "description": "The search term.", + "schema": { + "type": "string" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "filters", + "in": "query", + "description": "Optional. Specify additional filters to apply.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFilter" + } + } + }, + { + "name": "isFavorite", + "in": "query", + "description": "Optional filter by items that are marked as favorite, or not. userId is required.", + "schema": { + "type": "boolean" + } + }, + { + "name": "enableUserData", + "in": "query", + "description": "Optional, include user data.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional, the max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + }, + { + "name": "excludePersonTypes", + "in": "query", + "description": "Optional. If specified results will be filtered to exclude those containing the specified PersonType. Allows multiple, comma-delimited.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "personTypes", + "in": "query", + "description": "Optional. If specified results will be filtered to include only those containing the specified PersonType. Allows multiple, comma-delimited.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "appearsInItemId", + "in": "query", + "description": "Optional. If specified, person results will be filtered on items related to said persons.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "userId", + "in": "query", + "description": "User id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional, include image information in output.", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Persons returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Persons/{name}": { + "get": { + "tags": ["Persons"], + "summary": "Get person by name.", + "operationId": "GetPerson", + "parameters": [ + { + "name": "name", + "in": "path", + "description": "Person name.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user id, and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Person returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + } + } + }, + "404": { + "description": "Person not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/user_usage_stats/{breakdownType}/BreakdownReport": { + "get": { + "tags": ["PlaybackReportingActivity"], + "operationId": "GetBreakdownReport", + "parameters": [ + { + "name": "breakdownType", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "days", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "endDate", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "timezoneOffset", + "in": "query", + "schema": { + "type": "number", + "format": "float" + } + } + ], + "responses": { + "200": { + "description": "Success" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/user_usage_stats/{userId}/{date}/GetItems": { + "get": { + "tags": ["PlaybackReportingActivity"], + "operationId": "GetUserReportData", + "parameters": [ + { + "name": "userId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "date", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "filter", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "timezoneOffset", + "in": "query", + "schema": { + "type": "number", + "format": "float" + } + } + ], + "responses": { + "200": { + "description": "Success" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/user_usage_stats/DurationHistogramReport": { + "get": { + "tags": ["PlaybackReportingActivity"], + "operationId": "GetDurationHistogramReport", + "parameters": [ + { + "name": "days", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "endDate", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "filter", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/user_usage_stats/GetTvShowsReport": { + "get": { + "tags": ["PlaybackReportingActivity"], + "operationId": "GetTvShowsReport", + "parameters": [ + { + "name": "days", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "endDate", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "timezoneOffset", + "in": "query", + "schema": { + "type": "number", + "format": "float" + } + } + ], + "responses": { + "200": { + "description": "Success" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/user_usage_stats/HourlyReport": { + "get": { + "tags": ["PlaybackReportingActivity"], + "operationId": "GetHourlyReport", + "parameters": [ + { + "name": "days", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "endDate", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "filter", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "timezoneOffset", + "in": "query", + "schema": { + "type": "number", + "format": "float" + } + } + ], + "responses": { + "200": { + "description": "Success" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/user_usage_stats/load_backup": { + "get": { + "tags": ["PlaybackReportingActivity"], + "operationId": "LoadBackup", + "parameters": [ + { + "name": "backupFilePath", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/user_usage_stats/MoviesReport": { + "get": { + "tags": ["PlaybackReportingActivity"], + "operationId": "GetMovieReport", + "parameters": [ + { + "name": "days", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "endDate", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "timezoneOffset", + "in": "query", + "schema": { + "type": "number", + "format": "float" + } + } + ], + "responses": { + "200": { + "description": "Success" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/user_usage_stats/PlayActivity": { + "get": { + "tags": ["PlaybackReportingActivity"], + "operationId": "GetUsageStats", + "parameters": [ + { + "name": "days", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "endDate", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "filter", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "dataType", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "timezoneOffset", + "in": "query", + "schema": { + "type": "number", + "format": "float" + } + } + ], + "responses": { + "200": { + "description": "Success" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/user_usage_stats/save_backup": { + "get": { + "tags": ["PlaybackReportingActivity"], + "operationId": "SaveBackup", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/user_usage_stats/submit_custom_query": { + "post": { + "tags": ["PlaybackReportingActivity"], + "operationId": "CustomQuery", + "requestBody": { + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/CustomQueryData" + } + ] + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/CustomQueryData" + } + ] + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/CustomQueryData" + } + ] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": {} + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/user_usage_stats/type_filter_list": { + "get": { + "tags": ["PlaybackReportingActivity"], + "operationId": "GetTypeFilterList", + "responses": { + "200": { + "description": "Success" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/user_usage_stats/user_activity": { + "get": { + "tags": ["PlaybackReportingActivity"], + "operationId": "GetUserReport", + "parameters": [ + { + "name": "days", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "endDate", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "timezoneOffset", + "in": "query", + "schema": { + "type": "number", + "format": "float" + } + } + ], + "responses": { + "200": { + "description": "Success" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/user_usage_stats/user_list": { + "get": { + "tags": ["PlaybackReportingActivity"], + "operationId": "GetJellyfinUsers", + "responses": { + "200": { + "description": "Success" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/user_usage_stats/user_manage/add": { + "get": { + "tags": ["PlaybackReportingActivity"], + "operationId": "IgnoreListAdd", + "parameters": [ + { + "name": "id", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/user_usage_stats/user_manage/prune": { + "get": { + "tags": ["PlaybackReportingActivity"], + "operationId": "PruneUnknownUsers", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/user_usage_stats/user_manage/remove": { + "get": { + "tags": ["PlaybackReportingActivity"], + "operationId": "IgnoreListRemove", + "parameters": [ + { + "name": "id", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Playlists": { + "post": { + "tags": ["Playlists"], + "summary": "Creates a new playlist.", + "description": "For backwards compatibility parameters can be sent via Query or Body, with Query having higher precedence.\r\nQuery parameters are obsolete.", + "operationId": "CreatePlaylist", + "parameters": [ + { + "name": "name", + "in": "query", + "description": "The playlist name.", + "deprecated": true, + "schema": { + "type": "string" + } + }, + { + "name": "ids", + "in": "query", + "description": "The item ids.", + "deprecated": true, + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "userId", + "in": "query", + "description": "The user id.", + "deprecated": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "mediaType", + "in": "query", + "description": "The media type.", + "deprecated": true, + "schema": { + "enum": ["Unknown", "Video", "Audio", "Photo", "Book"], + "allOf": [ + { + "$ref": "#/components/schemas/MediaType" + } + ] + } + } + ], + "requestBody": { + "description": "The create playlist payload.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/CreatePlaylistDto" + } + ], + "description": "Create new playlist dto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/CreatePlaylistDto" + } + ], + "description": "Create new playlist dto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/CreatePlaylistDto" + } + ], + "description": "Create new playlist dto." + } + } + } + }, + "responses": { + "200": { + "description": "Playlist created.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PlaylistCreationResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/PlaylistCreationResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/PlaylistCreationResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Playlists/{playlistId}": { + "post": { + "tags": ["Playlists"], + "summary": "Updates a playlist.", + "operationId": "UpdatePlaylist", + "parameters": [ + { + "name": "playlistId", + "in": "path", + "description": "The playlist id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "description": "The Jellyfin.Api.Models.PlaylistDtos.UpdatePlaylistDto id.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UpdatePlaylistDto" + } + ], + "description": "Update existing playlist dto. Fields set to `null` will not be updated and keep their current values." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UpdatePlaylistDto" + } + ], + "description": "Update existing playlist dto. Fields set to `null` will not be updated and keep their current values." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UpdatePlaylistDto" + } + ], + "description": "Update existing playlist dto. Fields set to `null` will not be updated and keep their current values." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Playlist updated." + }, + "403": { + "description": "Access forbidden.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Playlist not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Playlists/{playlistId}/Items": { + "post": { + "tags": ["Playlists"], + "summary": "Adds items to a playlist.", + "operationId": "AddItemToPlaylist", + "parameters": [ + { + "name": "playlistId", + "in": "path", + "description": "The playlist id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "ids", + "in": "query", + "description": "Item id, comma delimited.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "userId", + "in": "query", + "description": "The userId.", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "204": { + "description": "Items added to playlist." + }, + "403": { + "description": "Access forbidden.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Playlist not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + }, + "delete": { + "tags": ["Playlists"], + "summary": "Removes items from a playlist.", + "operationId": "RemoveItemFromPlaylist", + "parameters": [ + { + "name": "playlistId", + "in": "path", + "description": "The playlist id.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "entryIds", + "in": "query", + "description": "The item ids, comma delimited.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "204": { + "description": "Items removed." + }, + "403": { + "description": "Access forbidden.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Playlist not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + }, + "get": { + "tags": ["Playlists"], + "summary": "Gets the original items of a playlist.", + "operationId": "GetPlaylistItems", + "parameters": [ + { + "name": "playlistId", + "in": "path", + "description": "The playlist id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "userId", + "in": "query", + "description": "User id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "startIndex", + "in": "query", + "description": "Optional. The record index to start at. All items with a lower index will be dropped from the results.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional. Include image information in output.", + "schema": { + "type": "boolean" + } + }, + { + "name": "enableUserData", + "in": "query", + "description": "Optional. Include user data.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional. The max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + } + ], + "responses": { + "200": { + "description": "Original playlist returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Playlist not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Playlists/{playlistId}/Items/{itemId}/Move/{newIndex}": { + "post": { + "tags": ["Playlists"], + "summary": "Moves a playlist item.", + "operationId": "MoveItem", + "parameters": [ + { + "name": "playlistId", + "in": "path", + "description": "The playlist id.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "newIndex", + "in": "path", + "description": "The new index.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Item moved to new index." + }, + "403": { + "description": "Access forbidden.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Playlist not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Playlists/{playlistId}/Users": { + "get": { + "tags": ["Playlists"], + "summary": "Get a playlist's users.", + "operationId": "GetPlaylistUsers", + "parameters": [ + { + "name": "playlistId", + "in": "path", + "description": "The playlist id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Found shares.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PlaylistUserPermissions" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PlaylistUserPermissions" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PlaylistUserPermissions" + } + } + } + } + }, + "403": { + "description": "Access forbidden.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Playlist not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Playlists/{playlistId}/Users/{userId}": { + "get": { + "tags": ["Playlists"], + "summary": "Get a playlist user.", + "operationId": "GetPlaylistUser", + "parameters": [ + { + "name": "playlistId", + "in": "path", + "description": "The playlist id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "userId", + "in": "path", + "description": "The user id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "User permission found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PlaylistUserPermissions" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/PlaylistUserPermissions" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/PlaylistUserPermissions" + } + } + } + }, + "403": { + "description": "Access forbidden.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Playlist not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + }, + "post": { + "tags": ["Playlists"], + "summary": "Modify a user of a playlist's users.", + "operationId": "UpdatePlaylistUser", + "parameters": [ + { + "name": "playlistId", + "in": "path", + "description": "The playlist id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "userId", + "in": "path", + "description": "The user id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "description": "The Jellyfin.Api.Models.PlaylistDtos.UpdatePlaylistUserDto.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UpdatePlaylistUserDto" + } + ], + "description": "Update existing playlist user dto. Fields set to `null` will not be updated and keep their current values." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UpdatePlaylistUserDto" + } + ], + "description": "Update existing playlist user dto. Fields set to `null` will not be updated and keep their current values." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UpdatePlaylistUserDto" + } + ], + "description": "Update existing playlist user dto. Fields set to `null` will not be updated and keep their current values." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "User's permissions modified." + }, + "403": { + "description": "Access forbidden.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Playlist not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + }, + "delete": { + "tags": ["Playlists"], + "summary": "Remove a user from a playlist's users.", + "operationId": "RemoveUserFromPlaylist", + "parameters": [ + { + "name": "playlistId", + "in": "path", + "description": "The playlist id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "userId", + "in": "path", + "description": "The user id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "204": { + "description": "User permissions removed from playlist." + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "No playlist or user permissions found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized access." + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/PlayingItems/{itemId}": { + "post": { + "tags": ["Playstate"], + "summary": "Reports that a session has begun playing an item.", + "operationId": "OnPlaybackStart", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "The id of the MediaSource.", + "schema": { + "type": "string" + } + }, + { + "name": "audioStreamIndex", + "in": "query", + "description": "The audio stream index.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleStreamIndex", + "in": "query", + "description": "The subtitle stream index.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "playMethod", + "in": "query", + "description": "The play method.", + "schema": { + "enum": ["Transcode", "DirectStream", "DirectPlay"], + "allOf": [ + { + "$ref": "#/components/schemas/PlayMethod" + } + ] + } + }, + { + "name": "liveStreamId", + "in": "query", + "description": "The live stream id.", + "schema": { + "type": "string" + } + }, + { + "name": "playSessionId", + "in": "query", + "description": "The play session id.", + "schema": { + "type": "string" + } + }, + { + "name": "canSeek", + "in": "query", + "description": "Indicates if the client can seek.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "204": { + "description": "Play start recorded." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + }, + "delete": { + "tags": ["Playstate"], + "summary": "Reports that a session has stopped playing an item.", + "operationId": "OnPlaybackStopped", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "The id of the MediaSource.", + "schema": { + "type": "string" + } + }, + { + "name": "nextMediaType", + "in": "query", + "description": "The next media type that will play.", + "schema": { + "type": "string" + } + }, + { + "name": "positionTicks", + "in": "query", + "description": "Optional. The position, in ticks, where playback stopped. 1 tick = 10000 ms.", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "liveStreamId", + "in": "query", + "description": "The live stream id.", + "schema": { + "type": "string" + } + }, + { + "name": "playSessionId", + "in": "query", + "description": "The play session id.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Playback stop recorded." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/PlayingItems/{itemId}/Progress": { + "post": { + "tags": ["Playstate"], + "summary": "Reports a session's playback progress.", + "operationId": "OnPlaybackProgress", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "The id of the MediaSource.", + "schema": { + "type": "string" + } + }, + { + "name": "positionTicks", + "in": "query", + "description": "Optional. The current position, in ticks. 1 tick = 10000 ms.", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "audioStreamIndex", + "in": "query", + "description": "The audio stream index.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleStreamIndex", + "in": "query", + "description": "The subtitle stream index.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "volumeLevel", + "in": "query", + "description": "Scale of 0-100.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "playMethod", + "in": "query", + "description": "The play method.", + "schema": { + "enum": ["Transcode", "DirectStream", "DirectPlay"], + "allOf": [ + { + "$ref": "#/components/schemas/PlayMethod" + } + ] + } + }, + { + "name": "liveStreamId", + "in": "query", + "description": "The live stream id.", + "schema": { + "type": "string" + } + }, + { + "name": "playSessionId", + "in": "query", + "description": "The play session id.", + "schema": { + "type": "string" + } + }, + { + "name": "repeatMode", + "in": "query", + "description": "The repeat mode.", + "schema": { + "enum": ["RepeatNone", "RepeatAll", "RepeatOne"], + "allOf": [ + { + "$ref": "#/components/schemas/RepeatMode" + } + ] + } + }, + { + "name": "isPaused", + "in": "query", + "description": "Indicates if the player is paused.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "isMuted", + "in": "query", + "description": "Indicates if the player is muted.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "204": { + "description": "Play progress recorded." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Sessions/Playing": { + "post": { + "tags": ["Playstate"], + "summary": "Reports playback has started within a session.", + "operationId": "ReportPlaybackStart", + "requestBody": { + "description": "The playback start info.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PlaybackStartInfo" + } + ], + "description": "Class PlaybackStartInfo." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PlaybackStartInfo" + } + ], + "description": "Class PlaybackStartInfo." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PlaybackStartInfo" + } + ], + "description": "Class PlaybackStartInfo." + } + } + } + }, + "responses": { + "204": { + "description": "Playback start recorded." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Sessions/Playing/Ping": { + "post": { + "tags": ["Playstate"], + "summary": "Pings a playback session.", + "operationId": "PingPlaybackSession", + "parameters": [ + { + "name": "playSessionId", + "in": "query", + "description": "Playback session id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Playback session pinged." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Sessions/Playing/Progress": { + "post": { + "tags": ["Playstate"], + "summary": "Reports playback progress within a session.", + "operationId": "ReportPlaybackProgress", + "requestBody": { + "description": "The playback progress info.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PlaybackProgressInfo" + } + ], + "description": "Class PlaybackProgressInfo." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PlaybackProgressInfo" + } + ], + "description": "Class PlaybackProgressInfo." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PlaybackProgressInfo" + } + ], + "description": "Class PlaybackProgressInfo." + } + } + } + }, + "responses": { + "204": { + "description": "Playback progress recorded." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Sessions/Playing/Stopped": { + "post": { + "tags": ["Playstate"], + "summary": "Reports playback has stopped within a session.", + "operationId": "ReportPlaybackStopped", + "requestBody": { + "description": "The playback stop info.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PlaybackStopInfo" + } + ], + "description": "Class PlaybackStopInfo." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PlaybackStopInfo" + } + ], + "description": "Class PlaybackStopInfo." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PlaybackStopInfo" + } + ], + "description": "Class PlaybackStopInfo." + } + } + } + }, + "responses": { + "204": { + "description": "Playback stop recorded." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/UserPlayedItems/{itemId}": { + "post": { + "tags": ["Playstate"], + "summary": "Marks an item as played for user.", + "operationId": "MarkPlayedItem", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "User id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "datePlayed", + "in": "query", + "description": "Optional. The date the item was played.", + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "Item marked as played.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserItemDataDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/UserItemDataDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/UserItemDataDto" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + }, + "delete": { + "tags": ["Playstate"], + "summary": "Marks an item as unplayed for user.", + "operationId": "MarkUnplayedItem", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "User id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Item marked as unplayed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserItemDataDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/UserItemDataDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/UserItemDataDto" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Plugins": { + "get": { + "tags": ["Plugins"], + "summary": "Gets a list of currently installed plugins.", + "operationId": "GetPlugins", + "responses": { + "200": { + "description": "Installed plugins returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PluginInfo" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PluginInfo" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PluginInfo" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Plugins/{pluginId}": { + "delete": { + "tags": ["Plugins"], + "summary": "Uninstalls a plugin.", + "operationId": "UninstallPlugin", + "parameters": [ + { + "name": "pluginId", + "in": "path", + "description": "Plugin id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "204": { + "description": "Plugin uninstalled." + }, + "404": { + "description": "Plugin not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "deprecated": true, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Plugins/{pluginId}/{version}": { + "delete": { + "tags": ["Plugins"], + "summary": "Uninstalls a plugin by version.", + "operationId": "UninstallPluginByVersion", + "parameters": [ + { + "name": "pluginId", + "in": "path", + "description": "Plugin id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "version", + "in": "path", + "description": "Plugin version.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Plugin uninstalled." + }, + "404": { + "description": "Plugin not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Plugins/{pluginId}/{version}/Disable": { + "post": { + "tags": ["Plugins"], + "summary": "Disable a plugin.", + "operationId": "DisablePlugin", + "parameters": [ + { + "name": "pluginId", + "in": "path", + "description": "Plugin id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "version", + "in": "path", + "description": "Plugin version.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Plugin disabled." + }, + "404": { + "description": "Plugin not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Plugins/{pluginId}/{version}/Enable": { + "post": { + "tags": ["Plugins"], + "summary": "Enables a disabled plugin.", + "operationId": "EnablePlugin", + "parameters": [ + { + "name": "pluginId", + "in": "path", + "description": "Plugin id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "version", + "in": "path", + "description": "Plugin version.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Plugin enabled." + }, + "404": { + "description": "Plugin not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Plugins/{pluginId}/{version}/Image": { + "get": { + "tags": ["Plugins"], + "summary": "Gets a plugin's image.", + "operationId": "GetPluginImage", + "parameters": [ + { + "name": "pluginId", + "in": "path", + "description": "Plugin id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "version", + "in": "path", + "description": "Plugin version.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Plugin image returned.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Plugins/{pluginId}/Configuration": { + "get": { + "tags": ["Plugins"], + "summary": "Gets plugin configuration.", + "operationId": "GetPluginConfiguration", + "parameters": [ + { + "name": "pluginId", + "in": "path", + "description": "Plugin id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Plugin configuration returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BasePluginConfiguration" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BasePluginConfiguration" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BasePluginConfiguration" + } + } + } + }, + "404": { + "description": "Plugin not found or plugin configuration not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + }, + "post": { + "tags": ["Plugins"], + "summary": "Updates plugin configuration.", + "description": "Accepts plugin configuration as JSON body.", + "operationId": "UpdatePluginConfiguration", + "parameters": [ + { + "name": "pluginId", + "in": "path", + "description": "Plugin id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "204": { + "description": "Plugin configuration updated." + }, + "404": { + "description": "Plugin not found or plugin does not have configuration.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Plugins/{pluginId}/Manifest": { + "post": { + "tags": ["Plugins"], + "summary": "Gets a plugin's manifest.", + "operationId": "GetPluginManifest", + "parameters": [ + { + "name": "pluginId", + "in": "path", + "description": "Plugin id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "204": { + "description": "Plugin manifest returned." + }, + "404": { + "description": "Plugin not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/QuickConnect/Authorize": { + "post": { + "tags": ["QuickConnect"], + "summary": "Authorizes a pending quick connect request.", + "operationId": "AuthorizeQuickConnect", + "parameters": [ + { + "name": "code", + "in": "query", + "description": "Quick connect code to authorize.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "userId", + "in": "query", + "description": "The user the authorize. Access to the requested user is required.", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Quick connect result authorized successfully.", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "boolean" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "boolean" + } + } + } + }, + "403": { + "description": "Unknown user id.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/QuickConnect/Connect": { + "get": { + "tags": ["QuickConnect"], + "summary": "Attempts to retrieve authentication information.", + "operationId": "GetQuickConnectState", + "parameters": [ + { + "name": "secret", + "in": "query", + "description": "Secret previously returned from the Initiate endpoint.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Quick connect result returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QuickConnectResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/QuickConnectResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/QuickConnectResult" + } + } + } + }, + "404": { + "description": "Unknown quick connect secret.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + } + }, + "/QuickConnect/Enabled": { + "get": { + "tags": ["QuickConnect"], + "summary": "Gets the current quick connect state.", + "operationId": "GetQuickConnectEnabled", + "responses": { + "200": { + "description": "Quick connect state returned.", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "boolean" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "boolean" + } + } + } + } + } + } + }, + "/QuickConnect/Initiate": { + "post": { + "tags": ["QuickConnect"], + "summary": "Initiate a new quick connect request.", + "operationId": "InitiateQuickConnect", + "responses": { + "200": { + "description": "Quick connect request successfully created.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QuickConnectResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/QuickConnectResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/QuickConnectResult" + } + } + } + }, + "401": { + "description": "Quick connect is not active on this server." + } + } + } + }, + "/Items/{itemId}/RemoteImages": { + "get": { + "tags": ["RemoteImage"], + "summary": "Gets available remote images for an item.", + "operationId": "GetRemoteImages", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "Item Id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "type", + "in": "query", + "description": "The image type.", + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ] + } + }, + { + "name": "startIndex", + "in": "query", + "description": "Optional. The record index to start at. All items with a lower index will be dropped from the results.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "providerName", + "in": "query", + "description": "Optional. The image provider to use.", + "schema": { + "type": "string" + } + }, + { + "name": "includeAllLanguages", + "in": "query", + "description": "Optional. Include all languages.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Remote Images returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RemoteImageResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/RemoteImageResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/RemoteImageResult" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/{itemId}/RemoteImages/Download": { + "post": { + "tags": ["RemoteImage"], + "summary": "Downloads a remote image for an item.", + "operationId": "DownloadRemoteImage", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "Item Id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "type", + "in": "query", + "description": "The image type.", + "required": true, + "schema": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Enum ImageType." + } + }, + { + "name": "imageUrl", + "in": "query", + "description": "The image url.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Remote image downloaded." + }, + "404": { + "description": "Remote image not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Items/{itemId}/RemoteImages/Providers": { + "get": { + "tags": ["RemoteImage"], + "summary": "Gets available remote image providers for an item.", + "operationId": "GetRemoteImageProviders", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "Item Id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Returned remote image providers.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageProviderInfo" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageProviderInfo" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageProviderInfo" + } + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/ScheduledTasks": { + "get": { + "tags": ["ScheduledTasks"], + "summary": "Get tasks.", + "operationId": "GetTasks", + "parameters": [ + { + "name": "isHidden", + "in": "query", + "description": "Optional filter tasks that are hidden, or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isEnabled", + "in": "query", + "description": "Optional filter tasks that are enabled, or not.", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Scheduled tasks retrieved.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TaskInfo" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TaskInfo" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TaskInfo" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/ScheduledTasks/{taskId}": { + "get": { + "tags": ["ScheduledTasks"], + "summary": "Get task by id.", + "operationId": "GetTask", + "parameters": [ + { + "name": "taskId", + "in": "path", + "description": "Task Id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Task retrieved.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskInfo" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/TaskInfo" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/TaskInfo" + } + } + } + }, + "404": { + "description": "Task not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/ScheduledTasks/{taskId}/Triggers": { + "post": { + "tags": ["ScheduledTasks"], + "summary": "Update specified task triggers.", + "operationId": "UpdateTask", + "parameters": [ + { + "name": "taskId", + "in": "path", + "description": "Task Id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "Triggers.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TaskTriggerInfo" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TaskTriggerInfo" + } + } + }, + "application/*+json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TaskTriggerInfo" + } + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Task triggers updated." + }, + "404": { + "description": "Task not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/ScheduledTasks/Running/{taskId}": { + "post": { + "tags": ["ScheduledTasks"], + "summary": "Start specified task.", + "operationId": "StartTask", + "parameters": [ + { + "name": "taskId", + "in": "path", + "description": "Task Id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Task started." + }, + "404": { + "description": "Task not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + }, + "delete": { + "tags": ["ScheduledTasks"], + "summary": "Stop specified task.", + "operationId": "StopTask", + "parameters": [ + { + "name": "taskId", + "in": "path", + "description": "Task Id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Task stopped." + }, + "404": { + "description": "Task not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Search/Hints": { + "get": { + "tags": ["Search"], + "summary": "Gets the search hint result.", + "operationId": "GetSearchHints", + "parameters": [ + { + "name": "startIndex", + "in": "query", + "description": "Optional. The record index to start at. All items with a lower index will be dropped from the results.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Supply a user id to search within a user's library or omit to search all.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "searchTerm", + "in": "query", + "description": "The search term to filter on.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "includeItemTypes", + "in": "query", + "description": "If specified, only results with the specified item types are returned. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemKind" + } + } + }, + { + "name": "excludeItemTypes", + "in": "query", + "description": "If specified, results with these item types are filtered out. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemKind" + } + } + }, + { + "name": "mediaTypes", + "in": "query", + "description": "If specified, only results with the specified media types are returned. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MediaType" + } + } + }, + { + "name": "parentId", + "in": "query", + "description": "If specified, only children of the parent are returned.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "isMovie", + "in": "query", + "description": "Optional filter for movies.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isSeries", + "in": "query", + "description": "Optional filter for series.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isNews", + "in": "query", + "description": "Optional filter for news.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isKids", + "in": "query", + "description": "Optional filter for kids.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isSports", + "in": "query", + "description": "Optional filter for sports.", + "schema": { + "type": "boolean" + } + }, + { + "name": "includePeople", + "in": "query", + "description": "Optional filter whether to include people.", + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "includeMedia", + "in": "query", + "description": "Optional filter whether to include media.", + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "includeGenres", + "in": "query", + "description": "Optional filter whether to include genres.", + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "includeStudios", + "in": "query", + "description": "Optional filter whether to include studios.", + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "includeArtists", + "in": "query", + "description": "Optional filter whether to include artists.", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Search hint returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SearchHintResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/SearchHintResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/SearchHintResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Auth/PasswordResetProviders": { + "get": { + "tags": ["Session"], + "summary": "Get all password reset providers.", + "operationId": "GetPasswordResetProviders", + "responses": { + "200": { + "description": "Password reset providers retrieved.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NameIdPair" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NameIdPair" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NameIdPair" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Auth/Providers": { + "get": { + "tags": ["Session"], + "summary": "Get all auth providers.", + "operationId": "GetAuthProviders", + "responses": { + "200": { + "description": "Auth providers retrieved.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NameIdPair" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NameIdPair" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NameIdPair" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Sessions": { + "get": { + "tags": ["Session"], + "summary": "Gets a list of sessions.", + "operationId": "GetSessions", + "parameters": [ + { + "name": "controllableByUserId", + "in": "query", + "description": "Filter by sessions that a given user is allowed to remote control.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "Filter by device Id.", + "schema": { + "type": "string" + } + }, + { + "name": "activeWithinSeconds", + "in": "query", + "description": "Optional. Filter by sessions that were active in the last n seconds.", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "List of sessions returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SessionInfo" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SessionInfo" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SessionInfo" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Sessions/{sessionId}/Command": { + "post": { + "tags": ["Session"], + "summary": "Issues a full general command to a client.", + "operationId": "SendFullGeneralCommand", + "parameters": [ + { + "name": "sessionId", + "in": "path", + "description": "The session id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "The MediaBrowser.Model.Session.GeneralCommand.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/GeneralCommand" + } + ] + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/GeneralCommand" + } + ] + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/GeneralCommand" + } + ] + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Full general command sent to session." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Sessions/{sessionId}/Command/{command}": { + "post": { + "tags": ["Session"], + "summary": "Issues a general command to a client.", + "operationId": "SendGeneralCommand", + "parameters": [ + { + "name": "sessionId", + "in": "path", + "description": "The session id.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "command", + "in": "path", + "description": "The command to send.", + "required": true, + "schema": { + "enum": [ + "MoveUp", + "MoveDown", + "MoveLeft", + "MoveRight", + "PageUp", + "PageDown", + "PreviousLetter", + "NextLetter", + "ToggleOsd", + "ToggleContextMenu", + "Select", + "Back", + "TakeScreenshot", + "SendKey", + "SendString", + "GoHome", + "GoToSettings", + "VolumeUp", + "VolumeDown", + "Mute", + "Unmute", + "ToggleMute", + "SetVolume", + "SetAudioStreamIndex", + "SetSubtitleStreamIndex", + "ToggleFullscreen", + "DisplayContent", + "GoToSearch", + "DisplayMessage", + "SetRepeatMode", + "ChannelUp", + "ChannelDown", + "Guide", + "ToggleStats", + "PlayMediaSource", + "PlayTrailers", + "SetShuffleQueue", + "PlayState", + "PlayNext", + "ToggleOsdMenu", + "Play", + "SetMaxStreamingBitrate", + "SetPlaybackOrder" + ], + "allOf": [ + { + "$ref": "#/components/schemas/GeneralCommandType" + } + ], + "description": "This exists simply to identify a set of known commands." + } + } + ], + "responses": { + "204": { + "description": "General command sent to session." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Sessions/{sessionId}/Message": { + "post": { + "tags": ["Session"], + "summary": "Issues a command to a client to display a message to the user.", + "operationId": "SendMessageCommand", + "parameters": [ + { + "name": "sessionId", + "in": "path", + "description": "The session id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "The MediaBrowser.Model.Session.MessageCommand object containing Header, Message Text, and TimeoutMs.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/MessageCommand" + } + ] + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/MessageCommand" + } + ] + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/MessageCommand" + } + ] + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Message sent." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Sessions/{sessionId}/Playing": { + "post": { + "tags": ["Session"], + "summary": "Instructs a session to play an item.", + "operationId": "Play", + "parameters": [ + { + "name": "sessionId", + "in": "path", + "description": "The session id.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "playCommand", + "in": "query", + "description": "The type of play command to issue (PlayNow, PlayNext, PlayLast). Clients who have not yet implemented play next and play last may play now.", + "required": true, + "schema": { + "enum": [ + "PlayNow", + "PlayNext", + "PlayLast", + "PlayInstantMix", + "PlayShuffle" + ], + "allOf": [ + { + "$ref": "#/components/schemas/PlayCommand" + } + ], + "description": "Enum PlayCommand." + } + }, + { + "name": "itemIds", + "in": "query", + "description": "The ids of the items to play, comma delimited.", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "startPositionTicks", + "in": "query", + "description": "The starting position of the first item.", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "Optional. The media source id.", + "schema": { + "type": "string" + } + }, + { + "name": "audioStreamIndex", + "in": "query", + "description": "Optional. The index of the audio stream to play.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleStreamIndex", + "in": "query", + "description": "Optional. The index of the subtitle stream to play.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "startIndex", + "in": "query", + "description": "Optional. The start index.", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Instruction sent to session." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Sessions/{sessionId}/Playing/{command}": { + "post": { + "tags": ["Session"], + "summary": "Issues a playstate command to a client.", + "operationId": "SendPlaystateCommand", + "parameters": [ + { + "name": "sessionId", + "in": "path", + "description": "The session id.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "command", + "in": "path", + "description": "The MediaBrowser.Model.Session.PlaystateCommand.", + "required": true, + "schema": { + "enum": [ + "Stop", + "Pause", + "Unpause", + "NextTrack", + "PreviousTrack", + "Seek", + "Rewind", + "FastForward", + "PlayPause" + ], + "allOf": [ + { + "$ref": "#/components/schemas/PlaystateCommand" + } + ], + "description": "Enum PlaystateCommand." + } + }, + { + "name": "seekPositionTicks", + "in": "query", + "description": "The optional position ticks.", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "controllingUserId", + "in": "query", + "description": "The optional controlling user id.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Playstate command sent to session." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Sessions/{sessionId}/System/{command}": { + "post": { + "tags": ["Session"], + "summary": "Issues a system command to a client.", + "operationId": "SendSystemCommand", + "parameters": [ + { + "name": "sessionId", + "in": "path", + "description": "The session id.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "command", + "in": "path", + "description": "The command to send.", + "required": true, + "schema": { + "enum": [ + "MoveUp", + "MoveDown", + "MoveLeft", + "MoveRight", + "PageUp", + "PageDown", + "PreviousLetter", + "NextLetter", + "ToggleOsd", + "ToggleContextMenu", + "Select", + "Back", + "TakeScreenshot", + "SendKey", + "SendString", + "GoHome", + "GoToSettings", + "VolumeUp", + "VolumeDown", + "Mute", + "Unmute", + "ToggleMute", + "SetVolume", + "SetAudioStreamIndex", + "SetSubtitleStreamIndex", + "ToggleFullscreen", + "DisplayContent", + "GoToSearch", + "DisplayMessage", + "SetRepeatMode", + "ChannelUp", + "ChannelDown", + "Guide", + "ToggleStats", + "PlayMediaSource", + "PlayTrailers", + "SetShuffleQueue", + "PlayState", + "PlayNext", + "ToggleOsdMenu", + "Play", + "SetMaxStreamingBitrate", + "SetPlaybackOrder" + ], + "allOf": [ + { + "$ref": "#/components/schemas/GeneralCommandType" + } + ], + "description": "This exists simply to identify a set of known commands." + } + } + ], + "responses": { + "204": { + "description": "System command sent to session." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Sessions/{sessionId}/User/{userId}": { + "post": { + "tags": ["Session"], + "summary": "Adds an additional user to a session.", + "operationId": "AddUserToSession", + "parameters": [ + { + "name": "sessionId", + "in": "path", + "description": "The session id.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "userId", + "in": "path", + "description": "The user id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "204": { + "description": "User added to session." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + }, + "delete": { + "tags": ["Session"], + "summary": "Removes an additional user from a session.", + "operationId": "RemoveUserFromSession", + "parameters": [ + { + "name": "sessionId", + "in": "path", + "description": "The session id.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "userId", + "in": "path", + "description": "The user id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "204": { + "description": "User removed from session." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Sessions/{sessionId}/Viewing": { + "post": { + "tags": ["Session"], + "summary": "Instructs a session to browse to an item or view.", + "operationId": "DisplayContent", + "parameters": [ + { + "name": "sessionId", + "in": "path", + "description": "The session Id.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "itemType", + "in": "query", + "description": "The type of item to browse to.", + "required": true, + "schema": { + "enum": [ + "AggregateFolder", + "Audio", + "AudioBook", + "BasePluginFolder", + "Book", + "BoxSet", + "Channel", + "ChannelFolderItem", + "CollectionFolder", + "Episode", + "Folder", + "Genre", + "ManualPlaylistsFolder", + "Movie", + "LiveTvChannel", + "LiveTvProgram", + "MusicAlbum", + "MusicArtist", + "MusicGenre", + "MusicVideo", + "Person", + "Photo", + "PhotoAlbum", + "Playlist", + "PlaylistsFolder", + "Program", + "Recording", + "Season", + "Series", + "Studio", + "Trailer", + "TvChannel", + "TvProgram", + "UserRootFolder", + "UserView", + "Video", + "Year" + ], + "allOf": [ + { + "$ref": "#/components/schemas/BaseItemKind" + } + ], + "description": "The base item kind." + } + }, + { + "name": "itemId", + "in": "query", + "description": "The Id of the item.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "itemName", + "in": "query", + "description": "The name of the item.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Instruction sent to session." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Sessions/Capabilities": { + "post": { + "tags": ["Session"], + "summary": "Updates capabilities for a device.", + "operationId": "PostCapabilities", + "parameters": [ + { + "name": "id", + "in": "query", + "description": "The session id.", + "schema": { + "type": "string" + } + }, + { + "name": "playableMediaTypes", + "in": "query", + "description": "A list of playable media types, comma delimited. Audio, Video, Book, Photo.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MediaType" + } + } + }, + { + "name": "supportedCommands", + "in": "query", + "description": "A list of supported remote control commands, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GeneralCommandType" + } + } + }, + { + "name": "supportsMediaControl", + "in": "query", + "description": "Determines whether media can be played remotely..", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "supportsPersistentIdentifier", + "in": "query", + "description": "Determines whether the device supports a unique identifier.", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "204": { + "description": "Capabilities posted." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Sessions/Capabilities/Full": { + "post": { + "tags": ["Session"], + "summary": "Updates capabilities for a device.", + "operationId": "PostFullCapabilities", + "parameters": [ + { + "name": "id", + "in": "query", + "description": "The session id.", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "The MediaBrowser.Model.Session.ClientCapabilities.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ClientCapabilitiesDto" + } + ], + "description": "Client capabilities dto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ClientCapabilitiesDto" + } + ], + "description": "Client capabilities dto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ClientCapabilitiesDto" + } + ], + "description": "Client capabilities dto." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Capabilities updated." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Sessions/Logout": { + "post": { + "tags": ["Session"], + "summary": "Reports that a session has ended.", + "operationId": "ReportSessionEnded", + "responses": { + "204": { + "description": "Session end reported to server." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Sessions/Viewing": { + "post": { + "tags": ["Session"], + "summary": "Reports that a session is viewing an item.", + "operationId": "ReportViewing", + "parameters": [ + { + "name": "sessionId", + "in": "query", + "description": "The session id.", + "schema": { + "type": "string" + } + }, + { + "name": "itemId", + "in": "query", + "description": "The item id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Session reported to server." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Episode/{id}/IntroSkipperSegments": { + "get": { + "tags": ["SkipIntro"], + "operationId": "GetSkippableSegments", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/Intro" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Episode/{id}/IntroTimestamps": { + "get": { + "tags": ["SkipIntro"], + "operationId": "GetIntroTimestamps", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "mode", + "in": "query", + "schema": { + "enum": ["Introduction", "Credits"], + "allOf": [ + { + "$ref": "#/components/schemas/AnalysisMode" + } + ], + "default": "Introduction" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Intro" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Episode/{id}/IntroTimestamps/v1": { + "get": { + "tags": ["SkipIntro"], + "operationId": "GetIntroTimestamps", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "mode", + "in": "query", + "schema": { + "enum": ["Introduction", "Credits"], + "allOf": [ + { + "$ref": "#/components/schemas/AnalysisMode" + } + ], + "default": "Introduction" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Intro" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Intros/All": { + "get": { + "tags": ["SkipIntro"], + "operationId": "GetAllTimestamps", + "parameters": [ + { + "name": "mode", + "in": "query", + "schema": { + "enum": ["Introduction", "Credits"], + "allOf": [ + { + "$ref": "#/components/schemas/AnalysisMode" + } + ], + "default": "Introduction" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IntroWithMetadata" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "RequiresElevation", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Intros/EraseTimestamps": { + "post": { + "tags": ["SkipIntro"], + "operationId": "ResetIntroTimestamps", + "parameters": [ + { + "name": "mode", + "in": "query", + "schema": { + "enum": ["Introduction", "Credits"], + "allOf": [ + { + "$ref": "#/components/schemas/AnalysisMode" + } + ] + } + }, + { + "name": "eraseCache", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Success" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "RequiresElevation", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Intros/UserInterfaceConfiguration": { + "get": { + "tags": ["SkipIntro"], + "operationId": "GetUserInterfaceConfiguration", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserInterfaceConfiguration" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Startup/Complete": { + "post": { + "tags": ["Startup"], + "summary": "Completes the startup wizard.", + "operationId": "CompleteWizard", + "responses": { + "204": { + "description": "Startup wizard completed." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "FirstTimeSetupOrElevated", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Startup/Configuration": { + "get": { + "tags": ["Startup"], + "summary": "Gets the initial startup wizard configuration.", + "operationId": "GetStartupConfiguration", + "responses": { + "200": { + "description": "Initial startup wizard configuration retrieved.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StartupConfigurationDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/StartupConfigurationDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/StartupConfigurationDto" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "FirstTimeSetupOrElevated", + "DefaultAuthorization" + ] + } + ] + }, + "post": { + "tags": ["Startup"], + "summary": "Sets the initial startup wizard configuration.", + "operationId": "UpdateInitialConfiguration", + "requestBody": { + "description": "The updated startup configuration.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/StartupConfigurationDto" + } + ], + "description": "The startup configuration DTO." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/StartupConfigurationDto" + } + ], + "description": "The startup configuration DTO." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/StartupConfigurationDto" + } + ], + "description": "The startup configuration DTO." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Configuration saved." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "FirstTimeSetupOrElevated", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Startup/FirstUser": { + "get": { + "tags": ["Startup"], + "summary": "Gets the first user.", + "operationId": "GetFirstUser_2", + "responses": { + "200": { + "description": "Initial user retrieved.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StartupUserDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/StartupUserDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/StartupUserDto" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "FirstTimeSetupOrElevated", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Startup/RemoteAccess": { + "post": { + "tags": ["Startup"], + "summary": "Sets remote access and UPnP.", + "operationId": "SetRemoteAccess", + "requestBody": { + "description": "The startup remote access dto.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/StartupRemoteAccessDto" + } + ], + "description": "Startup remote access dto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/StartupRemoteAccessDto" + } + ], + "description": "Startup remote access dto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/StartupRemoteAccessDto" + } + ], + "description": "Startup remote access dto." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Configuration saved." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "FirstTimeSetupOrElevated", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Startup/User": { + "get": { + "tags": ["Startup"], + "summary": "Gets the first user.", + "operationId": "GetFirstUser", + "responses": { + "200": { + "description": "Initial user retrieved.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StartupUserDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/StartupUserDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/StartupUserDto" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "FirstTimeSetupOrElevated", + "DefaultAuthorization" + ] + } + ] + }, + "post": { + "tags": ["Startup"], + "summary": "Sets the user name and password.", + "operationId": "UpdateStartupUser", + "requestBody": { + "description": "The DTO containing username and password.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/StartupUserDto" + } + ], + "description": "The startup user DTO." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/StartupUserDto" + } + ], + "description": "The startup user DTO." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/StartupUserDto" + } + ], + "description": "The startup user DTO." + } + } + } + }, + "responses": { + "204": { + "description": "Updated user name and password." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "FirstTimeSetupOrElevated", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Studios": { + "get": { + "tags": ["Studios"], + "summary": "Gets all studios from a given item, folder, or the entire library.", + "operationId": "GetStudios", + "parameters": [ + { + "name": "startIndex", + "in": "query", + "description": "Optional. The record index to start at. All items with a lower index will be dropped from the results.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "searchTerm", + "in": "query", + "description": "Optional. Search term.", + "schema": { + "type": "string" + } + }, + { + "name": "parentId", + "in": "query", + "description": "Specify this to localize the search to a specific item or folder. Omit to use the root.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "excludeItemTypes", + "in": "query", + "description": "Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemKind" + } + } + }, + { + "name": "includeItemTypes", + "in": "query", + "description": "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemKind" + } + } + }, + { + "name": "isFavorite", + "in": "query", + "description": "Optional filter by items that are marked as favorite, or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "enableUserData", + "in": "query", + "description": "Optional, include user data.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional, the max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + }, + { + "name": "userId", + "in": "query", + "description": "User id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "nameStartsWithOrGreater", + "in": "query", + "description": "Optional filter by items whose name is sorted equally or greater than a given input string.", + "schema": { + "type": "string" + } + }, + { + "name": "nameStartsWith", + "in": "query", + "description": "Optional filter by items whose name is sorted equally than a given input string.", + "schema": { + "type": "string" + } + }, + { + "name": "nameLessThan", + "in": "query", + "description": "Optional filter by items whose name is equally or lesser than a given input string.", + "schema": { + "type": "string" + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional, include image information in output.", + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "enableTotalRecordCount", + "in": "query", + "description": "Total record count.", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Studios returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Studios/{name}": { + "get": { + "tags": ["Studios"], + "summary": "Gets a studio by name.", + "operationId": "GetStudio", + "parameters": [ + { + "name": "name", + "in": "path", + "description": "Studio name.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user id, and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Studio returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/FallbackFont/Fonts": { + "get": { + "tags": ["Subtitle"], + "summary": "Gets a list of available fallback font files.", + "operationId": "GetFallbackFontList", + "responses": { + "200": { + "description": "Information retrieved.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FontFile" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FontFile" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FontFile" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/FallbackFont/Fonts/{name}": { + "get": { + "tags": ["Subtitle"], + "summary": "Gets a fallback font file.", + "operationId": "GetFallbackFont", + "parameters": [ + { + "name": "name", + "in": "path", + "description": "The name of the fallback font file to get.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Fallback font file retrieved.", + "content": { + "font/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/{itemId}/RemoteSearch/Subtitles/{language}": { + "get": { + "tags": ["Subtitle"], + "summary": "Search remote subtitles.", + "operationId": "SearchRemoteSubtitles", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "language", + "in": "path", + "description": "The language of the subtitles.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "isPerfectMatch", + "in": "query", + "description": "Optional. Only show subtitles which are a perfect match.", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Subtitles retrieved.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSubtitleInfo" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSubtitleInfo" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSubtitleInfo" + } + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "SubtitleManagement", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Items/{itemId}/RemoteSearch/Subtitles/{subtitleId}": { + "post": { + "tags": ["Subtitle"], + "summary": "Downloads a remote subtitle.", + "operationId": "DownloadRemoteSubtitles", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "subtitleId", + "in": "path", + "description": "The subtitle id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Subtitle downloaded." + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "SubtitleManagement", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Providers/Subtitles/Subtitles/{subtitleId}": { + "get": { + "tags": ["Subtitle"], + "summary": "Gets the remote subtitles.", + "operationId": "GetRemoteSubtitles", + "parameters": [ + { + "name": "subtitleId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "File returned.", + "content": { + "text/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "SubtitleManagement", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Videos/{itemId}/{mediaSourceId}/Subtitles/{index}/subtitles.m3u8": { + "get": { + "tags": ["Subtitle"], + "summary": "Gets an HLS subtitle playlist.", + "operationId": "GetSubtitlePlaylist", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "index", + "in": "path", + "description": "The subtitle stream index.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "mediaSourceId", + "in": "path", + "description": "The media source id.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "segmentLength", + "in": "query", + "description": "The subtitle segment length.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Subtitle playlist retrieved.", + "content": { + "application/x-mpegURL": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Videos/{itemId}/Subtitles": { + "post": { + "tags": ["Subtitle"], + "summary": "Upload an external subtitle file.", + "operationId": "UploadSubtitle", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item the subtitle belongs to.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "description": "The request body.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UploadSubtitleDto" + } + ], + "description": "Upload subtitles dto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UploadSubtitleDto" + } + ], + "description": "Upload subtitles dto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UploadSubtitleDto" + } + ], + "description": "Upload subtitles dto." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Subtitle uploaded." + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "SubtitleManagement", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Videos/{itemId}/Subtitles/{index}": { + "delete": { + "tags": ["Subtitle"], + "summary": "Deletes an external subtitle file.", + "operationId": "DeleteSubtitle", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "index", + "in": "path", + "description": "The index of the subtitle file.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Subtitle deleted." + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Videos/{routeItemId}/{routeMediaSourceId}/Subtitles/{routeIndex}/{routeStartPositionTicks}/Stream.{routeFormat}": { + "get": { + "tags": ["Subtitle"], + "summary": "Gets subtitles in a specified format.", + "operationId": "GetSubtitleWithTicks", + "parameters": [ + { + "name": "routeItemId", + "in": "path", + "description": "The (route) item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "routeMediaSourceId", + "in": "path", + "description": "The (route) media source id.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "routeIndex", + "in": "path", + "description": "The (route) subtitle stream index.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "routeStartPositionTicks", + "in": "path", + "description": "The (route) start position of the subtitle in ticks.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "routeFormat", + "in": "path", + "description": "The (route) format of the returned subtitle.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "itemId", + "in": "query", + "description": "The item id.", + "deprecated": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "The media source id.", + "deprecated": true, + "schema": { + "type": "string" + } + }, + { + "name": "index", + "in": "query", + "description": "The subtitle stream index.", + "deprecated": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "startPositionTicks", + "in": "query", + "description": "The start position of the subtitle in ticks.", + "deprecated": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "format", + "in": "query", + "description": "The format of the returned subtitle.", + "deprecated": true, + "schema": { + "type": "string" + } + }, + { + "name": "endPositionTicks", + "in": "query", + "description": "Optional. The end position of the subtitle in ticks.", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "copyTimestamps", + "in": "query", + "description": "Optional. Whether to copy the timestamps.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "addVttTimeMap", + "in": "query", + "description": "Optional. Whether to add a VTT time map.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "File returned.", + "content": { + "text/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + } + } + } + }, + "/Videos/{routeItemId}/{routeMediaSourceId}/Subtitles/{routeIndex}/Stream.{routeFormat}": { + "get": { + "tags": ["Subtitle"], + "summary": "Gets subtitles in a specified format.", + "operationId": "GetSubtitle", + "parameters": [ + { + "name": "routeItemId", + "in": "path", + "description": "The (route) item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "routeMediaSourceId", + "in": "path", + "description": "The (route) media source id.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "routeIndex", + "in": "path", + "description": "The (route) subtitle stream index.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "routeFormat", + "in": "path", + "description": "The (route) format of the returned subtitle.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "itemId", + "in": "query", + "description": "The item id.", + "deprecated": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "The media source id.", + "deprecated": true, + "schema": { + "type": "string" + } + }, + { + "name": "index", + "in": "query", + "description": "The subtitle stream index.", + "deprecated": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "format", + "in": "query", + "description": "The format of the returned subtitle.", + "deprecated": true, + "schema": { + "type": "string" + } + }, + { + "name": "endPositionTicks", + "in": "query", + "description": "Optional. The end position of the subtitle in ticks.", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "copyTimestamps", + "in": "query", + "description": "Optional. Whether to copy the timestamps.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "addVttTimeMap", + "in": "query", + "description": "Optional. Whether to add a VTT time map.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "startPositionTicks", + "in": "query", + "description": "The start position of the subtitle in ticks.", + "schema": { + "type": "integer", + "format": "int64", + "default": 0 + } + } + ], + "responses": { + "200": { + "description": "File returned.", + "content": { + "text/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + } + } + } + }, + "/Items/Suggestions": { + "get": { + "tags": ["Suggestions"], + "summary": "Gets suggestions.", + "operationId": "GetSuggestions", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "The user id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "mediaType", + "in": "query", + "description": "The media types.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MediaType" + } + } + }, + { + "name": "type", + "in": "query", + "description": "The type.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemKind" + } + } + }, + { + "name": "startIndex", + "in": "query", + "description": "Optional. The start index.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The limit.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableTotalRecordCount", + "in": "query", + "description": "Whether to enable the total record count.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Suggestions returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/SyncPlay/Buffering": { + "post": { + "tags": ["SyncPlay"], + "summary": "Notify SyncPlay group that member is buffering.", + "operationId": "SyncPlayBuffering", + "requestBody": { + "description": "The player status.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/BufferRequestDto" + } + ], + "description": "Class BufferRequestDto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/BufferRequestDto" + } + ], + "description": "Class BufferRequestDto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/BufferRequestDto" + } + ], + "description": "Class BufferRequestDto." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Group state update sent to all group members." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "SyncPlayIsInGroup", + "SyncPlayHasAccess", + "DefaultAuthorization" + ] + } + ] + } + }, + "/SyncPlay/Join": { + "post": { + "tags": ["SyncPlay"], + "summary": "Join an existing SyncPlay group.", + "operationId": "SyncPlayJoinGroup", + "requestBody": { + "description": "The group to join.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/JoinGroupRequestDto" + } + ], + "description": "Class JoinGroupRequestDto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/JoinGroupRequestDto" + } + ], + "description": "Class JoinGroupRequestDto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/JoinGroupRequestDto" + } + ], + "description": "Class JoinGroupRequestDto." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Group join successful." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "SyncPlayJoinGroup", + "SyncPlayHasAccess", + "DefaultAuthorization" + ] + } + ] + } + }, + "/SyncPlay/Leave": { + "post": { + "tags": ["SyncPlay"], + "summary": "Leave the joined SyncPlay group.", + "operationId": "SyncPlayLeaveGroup", + "responses": { + "204": { + "description": "Group leave successful." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "SyncPlayIsInGroup", + "SyncPlayHasAccess", + "DefaultAuthorization" + ] + } + ] + } + }, + "/SyncPlay/List": { + "get": { + "tags": ["SyncPlay"], + "summary": "Gets all SyncPlay groups.", + "operationId": "SyncPlayGetGroups", + "responses": { + "200": { + "description": "Groups returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GroupInfoDto" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GroupInfoDto" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GroupInfoDto" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "SyncPlayJoinGroup", + "SyncPlayHasAccess", + "DefaultAuthorization" + ] + } + ] + } + }, + "/SyncPlay/MovePlaylistItem": { + "post": { + "tags": ["SyncPlay"], + "summary": "Request to move an item in the playlist in SyncPlay group.", + "operationId": "SyncPlayMovePlaylistItem", + "requestBody": { + "description": "The new position for the item.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/MovePlaylistItemRequestDto" + } + ], + "description": "Class MovePlaylistItemRequestDto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/MovePlaylistItemRequestDto" + } + ], + "description": "Class MovePlaylistItemRequestDto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/MovePlaylistItemRequestDto" + } + ], + "description": "Class MovePlaylistItemRequestDto." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Queue update sent to all group members." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "SyncPlayIsInGroup", + "SyncPlayHasAccess", + "DefaultAuthorization" + ] + } + ] + } + }, + "/SyncPlay/New": { + "post": { + "tags": ["SyncPlay"], + "summary": "Create a new SyncPlay group.", + "operationId": "SyncPlayCreateGroup", + "requestBody": { + "description": "The settings of the new group.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/NewGroupRequestDto" + } + ], + "description": "Class NewGroupRequestDto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/NewGroupRequestDto" + } + ], + "description": "Class NewGroupRequestDto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/NewGroupRequestDto" + } + ], + "description": "Class NewGroupRequestDto." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "New group created." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "SyncPlayCreateGroup", + "SyncPlayHasAccess", + "DefaultAuthorization" + ] + } + ] + } + }, + "/SyncPlay/NextItem": { + "post": { + "tags": ["SyncPlay"], + "summary": "Request next item in SyncPlay group.", + "operationId": "SyncPlayNextItem", + "requestBody": { + "description": "The current item information.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/NextItemRequestDto" + } + ], + "description": "Class NextItemRequestDto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/NextItemRequestDto" + } + ], + "description": "Class NextItemRequestDto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/NextItemRequestDto" + } + ], + "description": "Class NextItemRequestDto." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Next item update sent to all group members." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "SyncPlayIsInGroup", + "SyncPlayHasAccess", + "DefaultAuthorization" + ] + } + ] + } + }, + "/SyncPlay/Pause": { + "post": { + "tags": ["SyncPlay"], + "summary": "Request pause in SyncPlay group.", + "operationId": "SyncPlayPause", + "responses": { + "204": { + "description": "Pause update sent to all group members." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "SyncPlayIsInGroup", + "SyncPlayHasAccess", + "DefaultAuthorization" + ] + } + ] + } + }, + "/SyncPlay/Ping": { + "post": { + "tags": ["SyncPlay"], + "summary": "Update session ping.", + "operationId": "SyncPlayPing", + "requestBody": { + "description": "The new ping.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PingRequestDto" + } + ], + "description": "Class PingRequestDto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PingRequestDto" + } + ], + "description": "Class PingRequestDto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PingRequestDto" + } + ], + "description": "Class PingRequestDto." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Ping updated." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "SyncPlayHasAccess", + "DefaultAuthorization" + ] + } + ] + } + }, + "/SyncPlay/PreviousItem": { + "post": { + "tags": ["SyncPlay"], + "summary": "Request previous item in SyncPlay group.", + "operationId": "SyncPlayPreviousItem", + "requestBody": { + "description": "The current item information.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PreviousItemRequestDto" + } + ], + "description": "Class PreviousItemRequestDto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PreviousItemRequestDto" + } + ], + "description": "Class PreviousItemRequestDto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PreviousItemRequestDto" + } + ], + "description": "Class PreviousItemRequestDto." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Previous item update sent to all group members." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "SyncPlayIsInGroup", + "SyncPlayHasAccess", + "DefaultAuthorization" + ] + } + ] + } + }, + "/SyncPlay/Queue": { + "post": { + "tags": ["SyncPlay"], + "summary": "Request to queue items to the playlist of a SyncPlay group.", + "operationId": "SyncPlayQueue", + "requestBody": { + "description": "The items to add.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/QueueRequestDto" + } + ], + "description": "Class QueueRequestDto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/QueueRequestDto" + } + ], + "description": "Class QueueRequestDto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/QueueRequestDto" + } + ], + "description": "Class QueueRequestDto." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Queue update sent to all group members." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "SyncPlayIsInGroup", + "SyncPlayHasAccess", + "DefaultAuthorization" + ] + } + ] + } + }, + "/SyncPlay/Ready": { + "post": { + "tags": ["SyncPlay"], + "summary": "Notify SyncPlay group that member is ready for playback.", + "operationId": "SyncPlayReady", + "requestBody": { + "description": "The player status.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ReadyRequestDto" + } + ], + "description": "Class ReadyRequest." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ReadyRequestDto" + } + ], + "description": "Class ReadyRequest." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ReadyRequestDto" + } + ], + "description": "Class ReadyRequest." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Group state update sent to all group members." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "SyncPlayIsInGroup", + "SyncPlayHasAccess", + "DefaultAuthorization" + ] + } + ] + } + }, + "/SyncPlay/RemoveFromPlaylist": { + "post": { + "tags": ["SyncPlay"], + "summary": "Request to remove items from the playlist in SyncPlay group.", + "operationId": "SyncPlayRemoveFromPlaylist", + "requestBody": { + "description": "The items to remove.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/RemoveFromPlaylistRequestDto" + } + ], + "description": "Class RemoveFromPlaylistRequestDto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/RemoveFromPlaylistRequestDto" + } + ], + "description": "Class RemoveFromPlaylistRequestDto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/RemoveFromPlaylistRequestDto" + } + ], + "description": "Class RemoveFromPlaylistRequestDto." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Queue update sent to all group members." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "SyncPlayIsInGroup", + "SyncPlayHasAccess", + "DefaultAuthorization" + ] + } + ] + } + }, + "/SyncPlay/Seek": { + "post": { + "tags": ["SyncPlay"], + "summary": "Request seek in SyncPlay group.", + "operationId": "SyncPlaySeek", + "requestBody": { + "description": "The new playback position.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SeekRequestDto" + } + ], + "description": "Class SeekRequestDto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SeekRequestDto" + } + ], + "description": "Class SeekRequestDto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SeekRequestDto" + } + ], + "description": "Class SeekRequestDto." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Seek update sent to all group members." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "SyncPlayIsInGroup", + "SyncPlayHasAccess", + "DefaultAuthorization" + ] + } + ] + } + }, + "/SyncPlay/SetIgnoreWait": { + "post": { + "tags": ["SyncPlay"], + "summary": "Request SyncPlay group to ignore member during group-wait.", + "operationId": "SyncPlaySetIgnoreWait", + "requestBody": { + "description": "The settings to set.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/IgnoreWaitRequestDto" + } + ], + "description": "Class IgnoreWaitRequestDto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/IgnoreWaitRequestDto" + } + ], + "description": "Class IgnoreWaitRequestDto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/IgnoreWaitRequestDto" + } + ], + "description": "Class IgnoreWaitRequestDto." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Member state updated." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "SyncPlayIsInGroup", + "SyncPlayHasAccess", + "DefaultAuthorization" + ] + } + ] + } + }, + "/SyncPlay/SetNewQueue": { + "post": { + "tags": ["SyncPlay"], + "summary": "Request to set new playlist in SyncPlay group.", + "operationId": "SyncPlaySetNewQueue", + "requestBody": { + "description": "The new playlist to play in the group.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PlayRequestDto" + } + ], + "description": "Class PlayRequestDto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PlayRequestDto" + } + ], + "description": "Class PlayRequestDto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PlayRequestDto" + } + ], + "description": "Class PlayRequestDto." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Queue update sent to all group members." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "SyncPlayIsInGroup", + "SyncPlayHasAccess", + "DefaultAuthorization" + ] + } + ] + } + }, + "/SyncPlay/SetPlaylistItem": { + "post": { + "tags": ["SyncPlay"], + "summary": "Request to change playlist item in SyncPlay group.", + "operationId": "SyncPlaySetPlaylistItem", + "requestBody": { + "description": "The new item to play.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SetPlaylistItemRequestDto" + } + ], + "description": "Class SetPlaylistItemRequestDto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SetPlaylistItemRequestDto" + } + ], + "description": "Class SetPlaylistItemRequestDto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SetPlaylistItemRequestDto" + } + ], + "description": "Class SetPlaylistItemRequestDto." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Queue update sent to all group members." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "SyncPlayIsInGroup", + "SyncPlayHasAccess", + "DefaultAuthorization" + ] + } + ] + } + }, + "/SyncPlay/SetRepeatMode": { + "post": { + "tags": ["SyncPlay"], + "summary": "Request to set repeat mode in SyncPlay group.", + "operationId": "SyncPlaySetRepeatMode", + "requestBody": { + "description": "The new repeat mode.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SetRepeatModeRequestDto" + } + ], + "description": "Class SetRepeatModeRequestDto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SetRepeatModeRequestDto" + } + ], + "description": "Class SetRepeatModeRequestDto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SetRepeatModeRequestDto" + } + ], + "description": "Class SetRepeatModeRequestDto." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Play queue update sent to all group members." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "SyncPlayIsInGroup", + "SyncPlayHasAccess", + "DefaultAuthorization" + ] + } + ] + } + }, + "/SyncPlay/SetShuffleMode": { + "post": { + "tags": ["SyncPlay"], + "summary": "Request to set shuffle mode in SyncPlay group.", + "operationId": "SyncPlaySetShuffleMode", + "requestBody": { + "description": "The new shuffle mode.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SetShuffleModeRequestDto" + } + ], + "description": "Class SetShuffleModeRequestDto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SetShuffleModeRequestDto" + } + ], + "description": "Class SetShuffleModeRequestDto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SetShuffleModeRequestDto" + } + ], + "description": "Class SetShuffleModeRequestDto." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Play queue update sent to all group members." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "SyncPlayIsInGroup", + "SyncPlayHasAccess", + "DefaultAuthorization" + ] + } + ] + } + }, + "/SyncPlay/Stop": { + "post": { + "tags": ["SyncPlay"], + "summary": "Request stop in SyncPlay group.", + "operationId": "SyncPlayStop", + "responses": { + "204": { + "description": "Stop update sent to all group members." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "SyncPlayIsInGroup", + "SyncPlayHasAccess", + "DefaultAuthorization" + ] + } + ] + } + }, + "/SyncPlay/Unpause": { + "post": { + "tags": ["SyncPlay"], + "summary": "Request unpause in SyncPlay group.", + "operationId": "SyncPlayUnpause", + "responses": { + "204": { + "description": "Unpause update sent to all group members." + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "SyncPlayIsInGroup", + "SyncPlayHasAccess", + "DefaultAuthorization" + ] + } + ] + } + }, + "/System/Endpoint": { + "get": { + "tags": ["System"], + "summary": "Gets information about the request endpoint.", + "operationId": "GetEndpointInfo", + "responses": { + "200": { + "description": "Information retrieved.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EndPointInfo" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/EndPointInfo" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/EndPointInfo" + } + } + } + }, + "403": { + "description": "User does not have permission to get endpoint information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/System/Info": { + "get": { + "tags": ["System"], + "summary": "Gets information about the server.", + "operationId": "GetSystemInfo", + "responses": { + "200": { + "description": "Information retrieved.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SystemInfo" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/SystemInfo" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/SystemInfo" + } + } + } + }, + "403": { + "description": "User does not have permission to retrieve information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "CustomAuthentication": [ + "FirstTimeSetupOrIgnoreParentalControl", + "DefaultAuthorization" + ] + } + ] + } + }, + "/System/Info/Public": { + "get": { + "tags": ["System"], + "summary": "Gets public information about the server.", + "operationId": "GetPublicSystemInfo", + "responses": { + "200": { + "description": "Information retrieved.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicSystemInfo" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/PublicSystemInfo" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/PublicSystemInfo" + } + } + } + } + } + } + }, + "/System/Logs": { + "get": { + "tags": ["System"], + "summary": "Gets a list of available server log files.", + "operationId": "GetServerLogs", + "responses": { + "200": { + "description": "Information retrieved.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogFile" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogFile" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogFile" + } + } + } + } + }, + "403": { + "description": "User does not have permission to get server logs.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/System/Logs/Log": { + "get": { + "tags": ["System"], + "summary": "Gets a log file.", + "operationId": "GetLogFile", + "parameters": [ + { + "name": "name", + "in": "query", + "description": "The name of the log file to get.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Log file retrieved.", + "content": { + "text/plain": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "403": { + "description": "User does not have permission to get log files.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Could not find a log file with the name.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/System/Ping": { + "get": { + "tags": ["System"], + "summary": "Pings the system.", + "operationId": "GetPingSystem", + "responses": { + "200": { + "description": "Information retrieved.", + "content": { + "application/json": { + "schema": { + "type": "string" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "string" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "string" + } + } + } + } + } + }, + "post": { + "tags": ["System"], + "summary": "Pings the system.", + "operationId": "PostPingSystem", + "responses": { + "200": { + "description": "Information retrieved.", + "content": { + "application/json": { + "schema": { + "type": "string" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "string" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/System/Restart": { + "post": { + "tags": ["System"], + "summary": "Restarts the application.", + "operationId": "RestartApplication", + "responses": { + "204": { + "description": "Server restarted." + }, + "403": { + "description": "User does not have permission to restart server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "CustomAuthentication": ["LocalAccessOrRequiresElevation"] + } + ] + } + }, + "/System/Shutdown": { + "post": { + "tags": ["System"], + "summary": "Shuts down the application.", + "operationId": "ShutdownApplication", + "responses": { + "204": { + "description": "Server shut down." + }, + "403": { + "description": "User does not have permission to shutdown server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/System/WakeOnLanInfo": { + "get": { + "tags": ["System"], + "summary": "Gets wake on lan information.", + "operationId": "GetWakeOnLanInfo", + "responses": { + "200": { + "description": "Information retrieved.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WakeOnLanInfo" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WakeOnLanInfo" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WakeOnLanInfo" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "deprecated": true, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/GetUtcTime": { + "get": { + "tags": ["TimeSync"], + "summary": "Gets the current UTC time.", + "operationId": "GetUtcTime", + "responses": { + "200": { + "description": "Time returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UtcTimeResponse" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/UtcTimeResponse" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/UtcTimeResponse" + } + } + } + } + } + } + }, + "/Tmdb/ClientConfiguration": { + "get": { + "tags": ["Tmdb"], + "summary": "Gets the TMDb image configuration options.", + "operationId": "TmdbClientConfiguration", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConfigImageTypes" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/TMDbBoxSets/Refresh": { + "post": { + "tags": ["TMDbBoxSets"], + "operationId": "RefreshMetadataRequest", + "responses": { + "204": { + "description": "Success" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Trailers": { + "get": { + "tags": ["Trailers"], + "summary": "Finds movies and trailers similar to a given trailer.", + "operationId": "GetTrailers", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "The user id supplied as query parameter; this is required when not using an API key.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "maxOfficialRating", + "in": "query", + "description": "Optional filter by maximum official rating (PG, PG-13, TV-MA, etc).", + "schema": { + "type": "string" + } + }, + { + "name": "hasThemeSong", + "in": "query", + "description": "Optional filter by items with theme songs.", + "schema": { + "type": "boolean" + } + }, + { + "name": "hasThemeVideo", + "in": "query", + "description": "Optional filter by items with theme videos.", + "schema": { + "type": "boolean" + } + }, + { + "name": "hasSubtitles", + "in": "query", + "description": "Optional filter by items with subtitles.", + "schema": { + "type": "boolean" + } + }, + { + "name": "hasSpecialFeature", + "in": "query", + "description": "Optional filter by items with special features.", + "schema": { + "type": "boolean" + } + }, + { + "name": "hasTrailer", + "in": "query", + "description": "Optional filter by items with trailers.", + "schema": { + "type": "boolean" + } + }, + { + "name": "adjacentTo", + "in": "query", + "description": "Optional. Return items that are siblings of a supplied item.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "parentIndexNumber", + "in": "query", + "description": "Optional filter by parent index number.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "hasParentalRating", + "in": "query", + "description": "Optional filter by items that have or do not have a parental rating.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isHd", + "in": "query", + "description": "Optional filter by items that are HD or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "is4K", + "in": "query", + "description": "Optional filter by items that are 4K or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "locationTypes", + "in": "query", + "description": "Optional. If specified, results will be filtered based on LocationType. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LocationType" + } + } + }, + { + "name": "excludeLocationTypes", + "in": "query", + "description": "Optional. If specified, results will be filtered based on the LocationType. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LocationType" + } + } + }, + { + "name": "isMissing", + "in": "query", + "description": "Optional filter by items that are missing episodes or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isUnaired", + "in": "query", + "description": "Optional filter by items that are unaired episodes or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "minCommunityRating", + "in": "query", + "description": "Optional filter by minimum community rating.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "minCriticRating", + "in": "query", + "description": "Optional filter by minimum critic rating.", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "minPremiereDate", + "in": "query", + "description": "Optional. The minimum premiere date. Format = ISO.", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "minDateLastSaved", + "in": "query", + "description": "Optional. The minimum last saved date. Format = ISO.", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "minDateLastSavedForUser", + "in": "query", + "description": "Optional. The minimum last saved date for the current user. Format = ISO.", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "maxPremiereDate", + "in": "query", + "description": "Optional. The maximum premiere date. Format = ISO.", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "hasOverview", + "in": "query", + "description": "Optional filter by items that have an overview or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "hasImdbId", + "in": "query", + "description": "Optional filter by items that have an IMDb id or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "hasTmdbId", + "in": "query", + "description": "Optional filter by items that have a TMDb id or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "hasTvdbId", + "in": "query", + "description": "Optional filter by items that have a TVDb id or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isMovie", + "in": "query", + "description": "Optional filter for live tv movies.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isSeries", + "in": "query", + "description": "Optional filter for live tv series.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isNews", + "in": "query", + "description": "Optional filter for live tv news.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isKids", + "in": "query", + "description": "Optional filter for live tv kids.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isSports", + "in": "query", + "description": "Optional filter for live tv sports.", + "schema": { + "type": "boolean" + } + }, + { + "name": "excludeItemIds", + "in": "query", + "description": "Optional. If specified, results will be filtered by excluding item ids. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "startIndex", + "in": "query", + "description": "Optional. The record index to start at. All items with a lower index will be dropped from the results.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "recursive", + "in": "query", + "description": "When searching within folders, this determines whether or not the search will be recursive. true/false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "searchTerm", + "in": "query", + "description": "Optional. Filter based on a search term.", + "schema": { + "type": "string" + } + }, + { + "name": "sortOrder", + "in": "query", + "description": "Sort Order - Ascending, Descending.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SortOrder" + } + } + }, + { + "name": "parentId", + "in": "query", + "description": "Specify this to localize the search to a specific item or folder. Omit to use the root.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "excludeItemTypes", + "in": "query", + "description": "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemKind" + } + } + }, + { + "name": "filters", + "in": "query", + "description": "Optional. Specify additional filters to apply. This allows multiple, comma delimited. Options: IsFolder, IsNotFolder, IsUnplayed, IsPlayed, IsFavorite, IsResumable, Likes, Dislikes.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFilter" + } + } + }, + { + "name": "isFavorite", + "in": "query", + "description": "Optional filter by items that are marked as favorite, or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "mediaTypes", + "in": "query", + "description": "Optional filter by MediaType. Allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MediaType" + } + } + }, + { + "name": "imageTypes", + "in": "query", + "description": "Optional. If specified, results will be filtered based on those containing image types. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + }, + { + "name": "sortBy", + "in": "query", + "description": "Optional. Specify one or more sort orders, comma delimited. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemSortBy" + } + } + }, + { + "name": "isPlayed", + "in": "query", + "description": "Optional filter by items that are played, or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "genres", + "in": "query", + "description": "Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "officialRatings", + "in": "query", + "description": "Optional. If specified, results will be filtered based on OfficialRating. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "tags", + "in": "query", + "description": "Optional. If specified, results will be filtered based on tag. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "years", + "in": "query", + "description": "Optional. If specified, results will be filtered based on production year. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + }, + { + "name": "enableUserData", + "in": "query", + "description": "Optional, include user data.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional, the max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + }, + { + "name": "person", + "in": "query", + "description": "Optional. If specified, results will be filtered to include only those containing the specified person.", + "schema": { + "type": "string" + } + }, + { + "name": "personIds", + "in": "query", + "description": "Optional. If specified, results will be filtered to include only those containing the specified person id.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "personTypes", + "in": "query", + "description": "Optional. If specified, along with Person, results will be filtered to include only those containing the specified person and PersonType. Allows multiple, comma-delimited.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "studios", + "in": "query", + "description": "Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "artists", + "in": "query", + "description": "Optional. If specified, results will be filtered based on artists. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "excludeArtistIds", + "in": "query", + "description": "Optional. If specified, results will be filtered based on artist id. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "artistIds", + "in": "query", + "description": "Optional. If specified, results will be filtered to include only those containing the specified artist id.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "albumArtistIds", + "in": "query", + "description": "Optional. If specified, results will be filtered to include only those containing the specified album artist id.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "contributingArtistIds", + "in": "query", + "description": "Optional. If specified, results will be filtered to include only those containing the specified contributing artist id.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "albums", + "in": "query", + "description": "Optional. If specified, results will be filtered based on album. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "albumIds", + "in": "query", + "description": "Optional. If specified, results will be filtered based on album id. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "ids", + "in": "query", + "description": "Optional. If specific items are needed, specify a list of item id's to retrieve. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "videoTypes", + "in": "query", + "description": "Optional filter by VideoType (videofile, dvd, bluray, iso). Allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VideoType" + } + } + }, + { + "name": "minOfficialRating", + "in": "query", + "description": "Optional filter by minimum official rating (PG, PG-13, TV-MA, etc).", + "schema": { + "type": "string" + } + }, + { + "name": "isLocked", + "in": "query", + "description": "Optional filter by items that are locked.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isPlaceHolder", + "in": "query", + "description": "Optional filter by items that are placeholders.", + "schema": { + "type": "boolean" + } + }, + { + "name": "hasOfficialRating", + "in": "query", + "description": "Optional filter by items that have official ratings.", + "schema": { + "type": "boolean" + } + }, + { + "name": "collapseBoxSetItems", + "in": "query", + "description": "Whether or not to hide items behind their boxsets.", + "schema": { + "type": "boolean" + } + }, + { + "name": "minWidth", + "in": "query", + "description": "Optional. Filter by the minimum width of the item.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "minHeight", + "in": "query", + "description": "Optional. Filter by the minimum height of the item.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "Optional. Filter by the maximum width of the item.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "Optional. Filter by the maximum height of the item.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "is3D", + "in": "query", + "description": "Optional filter by items that are 3D, or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "seriesStatus", + "in": "query", + "description": "Optional filter by Series Status. Allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SeriesStatus" + } + } + }, + { + "name": "nameStartsWithOrGreater", + "in": "query", + "description": "Optional filter by items whose name is sorted equally or greater than a given input string.", + "schema": { + "type": "string" + } + }, + { + "name": "nameStartsWith", + "in": "query", + "description": "Optional filter by items whose name is sorted equally than a given input string.", + "schema": { + "type": "string" + } + }, + { + "name": "nameLessThan", + "in": "query", + "description": "Optional filter by items whose name is equally or lesser than a given input string.", + "schema": { + "type": "string" + } + }, + { + "name": "studioIds", + "in": "query", + "description": "Optional. If specified, results will be filtered based on studio id. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "genreIds", + "in": "query", + "description": "Optional. If specified, results will be filtered based on genre id. This allows multiple, pipe delimited.", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "enableTotalRecordCount", + "in": "query", + "description": "Optional. Enable the total record count.", + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional, include image information in output.", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Trakt/Users/{userGuid}/Authorize": { + "post": { + "tags": ["Trakt"], + "operationId": "TraktDeviceAuthorization", + "parameters": [ + { + "name": "userGuid", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "RequiresElevation", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Trakt/Users/{userGuid}/Deauthorize": { + "post": { + "tags": ["Trakt"], + "operationId": "TraktDeviceDeAuthorization", + "parameters": [ + { + "name": "userGuid", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "RequiresElevation", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Trakt/Users/{userGuid}/Items/{itemId}/Rate": { + "post": { + "tags": ["Trakt"], + "operationId": "TraktRateItem", + "parameters": [ + { + "name": "userGuid", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "itemId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "rating", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TraktSyncResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Trakt/Users/{userGuid}/PollAuthorizationStatus": { + "get": { + "tags": ["Trakt"], + "operationId": "TraktPollAuthorizationStatus", + "parameters": [ + { + "name": "userGuid", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "RequiresElevation", + "DefaultAuthorization" + ] + } + ] + } + }, + "/Trakt/Users/{userGuid}/RecommendedMovies": { + "post": { + "tags": ["Trakt"], + "operationId": "RecommendedTraktMovies", + "parameters": [ + { + "name": "userGuid", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TraktMovie" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Trakt/Users/{userGuid}/RecommendedShows": { + "post": { + "tags": ["Trakt"], + "operationId": "RecommendedTraktShows", + "parameters": [ + { + "name": "userGuid", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TraktShow" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Videos/{itemId}/Trickplay/{width}/{index}.jpg": { + "get": { + "tags": ["Trickplay"], + "summary": "Gets a trickplay tile image.", + "operationId": "GetTrickplayTileImage", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "width", + "in": "path", + "description": "The width of a single tile.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "index", + "in": "path", + "description": "The index of the desired tile.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "The media version id, if using an alternate version.", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Tile image not found at specified index.", + "content": { + "image/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Videos/{itemId}/Trickplay/{width}/tiles.m3u8": { + "get": { + "tags": ["Trickplay"], + "summary": "Gets an image tiles playlist for trickplay.", + "operationId": "GetTrickplayHlsPlaylist", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "width", + "in": "path", + "description": "The width of a single tile.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "The media version id, if using an alternate version.", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Tiles playlist returned.", + "content": { + "application/x-mpegURL": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/IntroSkipper/SupportBundle": { + "get": { + "tags": ["Troubleshooting"], + "operationId": "GetSupportBundle", + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + }, + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Shows/{seriesId}/Episodes": { + "get": { + "tags": ["TvShows"], + "summary": "Gets episodes for a tv season.", + "operationId": "GetEpisodes", + "parameters": [ + { + "name": "seriesId", + "in": "path", + "description": "The series id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "userId", + "in": "query", + "description": "The user id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "season", + "in": "query", + "description": "Optional filter by season number.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "seasonId", + "in": "query", + "description": "Optional. Filter by season id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "isMissing", + "in": "query", + "description": "Optional. Filter by items that are missing episodes or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "adjacentTo", + "in": "query", + "description": "Optional. Return items that are siblings of a supplied item.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "startItemId", + "in": "query", + "description": "Optional. Skip through the list until a given item is found.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "startIndex", + "in": "query", + "description": "Optional. The record index to start at. All items with a lower index will be dropped from the results.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional, include image information in output.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional, the max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + }, + { + "name": "enableUserData", + "in": "query", + "description": "Optional. Include user data.", + "schema": { + "type": "boolean" + } + }, + { + "name": "sortBy", + "in": "query", + "description": "Optional. Specify one or more sort orders, comma delimited. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime.", + "schema": { + "enum": [ + "Default", + "AiredEpisodeOrder", + "Album", + "AlbumArtist", + "Artist", + "DateCreated", + "OfficialRating", + "DatePlayed", + "PremiereDate", + "StartDate", + "SortName", + "Name", + "Random", + "Runtime", + "CommunityRating", + "ProductionYear", + "PlayCount", + "CriticRating", + "IsFolder", + "IsUnplayed", + "IsPlayed", + "SeriesSortName", + "VideoBitRate", + "AirTime", + "Studio", + "IsFavoriteOrLiked", + "DateLastContentAdded", + "SeriesDatePlayed", + "ParentIndexNumber", + "IndexNumber", + "SimilarityScore", + "SearchScore" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ItemSortBy" + } + ] + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Shows/{seriesId}/Seasons": { + "get": { + "tags": ["TvShows"], + "summary": "Gets seasons for a tv series.", + "operationId": "GetSeasons", + "parameters": [ + { + "name": "seriesId", + "in": "path", + "description": "The series id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "userId", + "in": "query", + "description": "The user id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "isSpecialSeason", + "in": "query", + "description": "Optional. Filter by special season.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isMissing", + "in": "query", + "description": "Optional. Filter by items that are missing episodes or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "adjacentTo", + "in": "query", + "description": "Optional. Return items that are siblings of a supplied item.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional. Include image information in output.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional. The max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + }, + { + "name": "enableUserData", + "in": "query", + "description": "Optional. Include user data.", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Shows/NextUp": { + "get": { + "tags": ["TvShows"], + "summary": "Gets a list of next up episodes.", + "operationId": "GetNextUp", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "The user id of the user to get the next up episodes for.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "startIndex", + "in": "query", + "description": "Optional. The record index to start at. All items with a lower index will be dropped from the results.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "seriesId", + "in": "query", + "description": "Optional. Filter by series id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "parentId", + "in": "query", + "description": "Optional. Specify this to localize the search to a specific item or folder. Omit to use the root.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional. Include image information in output.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional. The max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + }, + { + "name": "enableUserData", + "in": "query", + "description": "Optional. Include user data.", + "schema": { + "type": "boolean" + } + }, + { + "name": "nextUpDateCutoff", + "in": "query", + "description": "Optional. Starting date of shows to show in Next Up section.", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "enableTotalRecordCount", + "in": "query", + "description": "Whether to enable the total records count. Defaults to true.", + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "disableFirstEpisode", + "in": "query", + "description": "Whether to disable sending the first episode in a series as next up.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "enableResumable", + "in": "query", + "description": "Whether to include resumable episodes in next up results.", + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "enableRewatching", + "in": "query", + "description": "Whether to include watched episodes in next up results.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Shows/Upcoming": { + "get": { + "tags": ["TvShows"], + "summary": "Gets a list of upcoming episodes.", + "operationId": "GetUpcomingEpisodes", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "The user id of the user to get the upcoming episodes for.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "startIndex", + "in": "query", + "description": "Optional. The record index to start at. All items with a lower index will be dropped from the results.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "parentId", + "in": "query", + "description": "Optional. Specify this to localize the search to a specific item or folder. Omit to use the root.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional. Include image information in output.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional. The max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + }, + { + "name": "enableUserData", + "in": "query", + "description": "Optional. Include user data.", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Audio/{itemId}/universal": { + "get": { + "tags": ["UniversalAudio"], + "summary": "Gets an audio stream.", + "operationId": "GetUniversalAudioStream", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "container", + "in": "query", + "description": "Optional. The audio container.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "The media version id, if playing an alternate version.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "The device id of the client requesting. Used to stop encoding processes when needed.", + "schema": { + "type": "string" + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. The user id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "audioCodec", + "in": "query", + "description": "Optional. The audio codec to transcode to.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "maxAudioChannels", + "in": "query", + "description": "Optional. The maximum number of audio channels.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "transcodingAudioChannels", + "in": "query", + "description": "Optional. The number of how many audio channels to transcode to.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxStreamingBitrate", + "in": "query", + "description": "Optional. The maximum streaming bitrate.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioBitRate", + "in": "query", + "description": "Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "startTimeTicks", + "in": "query", + "description": "Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "transcodingContainer", + "in": "query", + "description": "Optional. The container to transcode to.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "transcodingProtocol", + "in": "query", + "description": "Optional. The transcoding protocol.", + "schema": { + "enum": ["http", "hls"], + "allOf": [ + { + "$ref": "#/components/schemas/MediaStreamProtocol" + } + ] + } + }, + { + "name": "maxAudioSampleRate", + "in": "query", + "description": "Optional. The maximum audio sample rate.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioBitDepth", + "in": "query", + "description": "Optional. The maximum audio bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableRemoteMedia", + "in": "query", + "description": "Optional. Whether to enable remote media.", + "schema": { + "type": "boolean" + } + }, + { + "name": "breakOnNonKeyFrames", + "in": "query", + "description": "Optional. Whether to break on non key frames.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "enableRedirection", + "in": "query", + "description": "Whether to enable redirection. Defaults to true.", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Audio stream returned.", + "content": { + "audio/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "302": { + "description": "Redirected to remote audio stream." + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + }, + "head": { + "tags": ["UniversalAudio"], + "summary": "Gets an audio stream.", + "operationId": "HeadUniversalAudioStream", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "container", + "in": "query", + "description": "Optional. The audio container.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "The media version id, if playing an alternate version.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "The device id of the client requesting. Used to stop encoding processes when needed.", + "schema": { + "type": "string" + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. The user id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "audioCodec", + "in": "query", + "description": "Optional. The audio codec to transcode to.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "maxAudioChannels", + "in": "query", + "description": "Optional. The maximum number of audio channels.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "transcodingAudioChannels", + "in": "query", + "description": "Optional. The number of how many audio channels to transcode to.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxStreamingBitrate", + "in": "query", + "description": "Optional. The maximum streaming bitrate.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioBitRate", + "in": "query", + "description": "Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "startTimeTicks", + "in": "query", + "description": "Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "transcodingContainer", + "in": "query", + "description": "Optional. The container to transcode to.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "transcodingProtocol", + "in": "query", + "description": "Optional. The transcoding protocol.", + "schema": { + "enum": ["http", "hls"], + "allOf": [ + { + "$ref": "#/components/schemas/MediaStreamProtocol" + } + ] + } + }, + { + "name": "maxAudioSampleRate", + "in": "query", + "description": "Optional. The maximum audio sample rate.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioBitDepth", + "in": "query", + "description": "Optional. The maximum audio bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableRemoteMedia", + "in": "query", + "description": "Optional. Whether to enable remote media.", + "schema": { + "type": "boolean" + } + }, + { + "name": "breakOnNonKeyFrames", + "in": "query", + "description": "Optional. Whether to break on non key frames.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "enableRedirection", + "in": "query", + "description": "Whether to enable redirection. Defaults to true.", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Audio stream returned.", + "content": { + "audio/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "302": { + "description": "Redirected to remote audio stream." + }, + "404": { + "description": "Item not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Users": { + "get": { + "tags": ["User"], + "summary": "Gets a list of users.", + "operationId": "GetUsers", + "parameters": [ + { + "name": "isHidden", + "in": "query", + "description": "Optional filter by IsHidden=true or false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "isDisabled", + "in": "query", + "description": "Optional filter by IsDisabled=true or false.", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Users returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserDto" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserDto" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserDto" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + }, + "post": { + "tags": ["User"], + "summary": "Updates a user.", + "operationId": "UpdateUser", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "The user id.", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "description": "The updated user model.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UserDto" + } + ], + "description": "Class UserDto." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UserDto" + } + ], + "description": "Class UserDto." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UserDto" + } + ], + "description": "Class UserDto." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "User updated." + }, + "400": { + "description": "User information was not supplied.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "User update forbidden.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Users/{userId}": { + "get": { + "tags": ["User"], + "summary": "Gets a user by Id.", + "operationId": "GetUserById", + "parameters": [ + { + "name": "userId", + "in": "path", + "description": "The user id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "User returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/UserDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/UserDto" + } + } + } + }, + "404": { + "description": "User not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": [ + "IgnoreParentalControl", + "DefaultAuthorization" + ] + } + ] + }, + "delete": { + "tags": ["User"], + "summary": "Deletes a user.", + "operationId": "DeleteUser", + "parameters": [ + { + "name": "userId", + "in": "path", + "description": "The user id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "204": { + "description": "User deleted." + }, + "404": { + "description": "User not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Users/{userId}/Policy": { + "post": { + "tags": ["User"], + "summary": "Updates a user policy.", + "operationId": "UpdateUserPolicy", + "parameters": [ + { + "name": "userId", + "in": "path", + "description": "The user id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "description": "The new user policy.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UserPolicy" + } + ] + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UserPolicy" + } + ] + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UserPolicy" + } + ] + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "User policy updated." + }, + "400": { + "description": "User policy was not supplied.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "403": { + "description": "User policy update forbidden.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Users/AuthenticateByName": { + "post": { + "tags": ["User"], + "summary": "Authenticates a user by name.", + "operationId": "AuthenticateUserByName", + "requestBody": { + "description": "The M:Jellyfin.Api.Controllers.UserController.AuthenticateUserByName(Jellyfin.Api.Models.UserDtos.AuthenticateUserByName) request.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/AuthenticateUserByName" + } + ], + "description": "The authenticate user by name request body." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/AuthenticateUserByName" + } + ], + "description": "The authenticate user by name request body." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/AuthenticateUserByName" + } + ], + "description": "The authenticate user by name request body." + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "User authenticated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthenticationResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/AuthenticationResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/AuthenticationResult" + } + } + } + } + } + } + }, + "/Users/AuthenticateWithQuickConnect": { + "post": { + "tags": ["User"], + "summary": "Authenticates a user with quick connect.", + "operationId": "AuthenticateWithQuickConnect", + "requestBody": { + "description": "The Jellyfin.Api.Models.UserDtos.QuickConnectDto request.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/QuickConnectDto" + } + ], + "description": "The quick connect request body." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/QuickConnectDto" + } + ], + "description": "The quick connect request body." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/QuickConnectDto" + } + ], + "description": "The quick connect request body." + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "User authenticated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthenticationResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/AuthenticationResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/AuthenticationResult" + } + } + } + }, + "400": { + "description": "Missing token." + } + } + } + }, + "/Users/Configuration": { + "post": { + "tags": ["User"], + "summary": "Updates a user configuration.", + "operationId": "UpdateUserConfiguration", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "The user id.", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "description": "The new user configuration.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UserConfiguration" + } + ], + "description": "Class UserConfiguration." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UserConfiguration" + } + ], + "description": "Class UserConfiguration." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UserConfiguration" + } + ], + "description": "Class UserConfiguration." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "User configuration updated." + }, + "403": { + "description": "User configuration update forbidden.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Users/ForgotPassword": { + "post": { + "tags": ["User"], + "summary": "Initiates the forgot password process for a local user.", + "operationId": "ForgotPassword", + "requestBody": { + "description": "The forgot password request containing the entered username.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ForgotPasswordDto" + } + ], + "description": "Forgot Password request body DTO." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ForgotPasswordDto" + } + ], + "description": "Forgot Password request body DTO." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ForgotPasswordDto" + } + ], + "description": "Forgot Password request body DTO." + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Password reset process started.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ForgotPasswordResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ForgotPasswordResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ForgotPasswordResult" + } + } + } + } + } + } + }, + "/Users/ForgotPassword/Pin": { + "post": { + "tags": ["User"], + "summary": "Redeems a forgot password pin.", + "operationId": "ForgotPasswordPin", + "requestBody": { + "description": "The forgot password pin request containing the entered pin.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ForgotPasswordPinDto" + } + ], + "description": "Forgot Password Pin enter request body DTO." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ForgotPasswordPinDto" + } + ], + "description": "Forgot Password Pin enter request body DTO." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ForgotPasswordPinDto" + } + ], + "description": "Forgot Password Pin enter request body DTO." + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Pin reset process started.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PinRedeemResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/PinRedeemResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/PinRedeemResult" + } + } + } + } + } + } + }, + "/Users/Me": { + "get": { + "tags": ["User"], + "summary": "Gets the user based on auth token.", + "operationId": "GetCurrentUser", + "responses": { + "200": { + "description": "User returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/UserDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/UserDto" + } + } + } + }, + "400": { + "description": "Token is not owned by a user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Users/New": { + "post": { + "tags": ["User"], + "summary": "Creates a user.", + "operationId": "CreateUserByName", + "requestBody": { + "description": "The create user by name request body.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/CreateUserByName" + } + ], + "description": "The create user by name request body." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/CreateUserByName" + } + ], + "description": "The create user by name request body." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/CreateUserByName" + } + ], + "description": "The create user by name request body." + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "User created.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/UserDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/UserDto" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Users/Password": { + "post": { + "tags": ["User"], + "summary": "Updates a user's password.", + "operationId": "UpdateUserPassword", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "The user id.", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "description": "The M:Jellyfin.Api.Controllers.UserController.UpdateUserPassword(System.Nullable{System.Guid},Jellyfin.Api.Models.UserDtos.UpdateUserPassword) request.", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UpdateUserPassword" + } + ], + "description": "The update user password request body." + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UpdateUserPassword" + } + ], + "description": "The update user password request body." + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/UpdateUserPassword" + } + ], + "description": "The update user password request body." + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Password successfully reset." + }, + "403": { + "description": "User is not allowed to update the password.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "User not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Users/Public": { + "get": { + "tags": ["User"], + "summary": "Gets a list of publicly visible users for display on a login screen.", + "operationId": "GetPublicUsers", + "responses": { + "200": { + "description": "Public users returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserDto" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserDto" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserDto" + } + } + } + } + } + } + } + }, + "/Items/{itemId}/Intros": { + "get": { + "tags": ["UserLibrary"], + "summary": "Gets intros to play before the main media item plays.", + "operationId": "GetIntros", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "User id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Intros returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/{itemId}/LocalTrailers": { + "get": { + "tags": ["UserLibrary"], + "summary": "Gets local trailers for an item.", + "operationId": "GetLocalTrailers", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "User id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "An Microsoft.AspNetCore.Mvc.OkResult containing the item's local trailers.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemDto" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemDto" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemDto" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/{itemId}/SpecialFeatures": { + "get": { + "tags": ["UserLibrary"], + "summary": "Gets special features for an item.", + "operationId": "GetSpecialFeatures", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "User id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Special features returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemDto" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemDto" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemDto" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/Latest": { + "get": { + "tags": ["UserLibrary"], + "summary": "Gets latest media.", + "operationId": "GetLatestMedia", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "User id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "parentId", + "in": "query", + "description": "Specify this to localize the search to a specific item or folder. Omit to use the root.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "includeItemTypes", + "in": "query", + "description": "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemKind" + } + } + }, + { + "name": "isPlayed", + "in": "query", + "description": "Filter by items that are played, or not.", + "schema": { + "type": "boolean" + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional. include image information in output.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional. the max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + }, + { + "name": "enableUserData", + "in": "query", + "description": "Optional. include user data.", + "schema": { + "type": "boolean" + } + }, + { + "name": "limit", + "in": "query", + "description": "Return item limit.", + "schema": { + "type": "integer", + "format": "int32", + "default": 20 + } + }, + { + "name": "groupItems", + "in": "query", + "description": "Whether or not to group items into a parent container.", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Latest media returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemDto" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemDto" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemDto" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Items/Root": { + "get": { + "tags": ["UserLibrary"], + "summary": "Gets the root folder from a user's library.", + "operationId": "GetRootFolder", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "User id.", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Root folder returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/UserFavoriteItems/{itemId}": { + "post": { + "tags": ["UserLibrary"], + "summary": "Marks an item as a favorite.", + "operationId": "MarkFavoriteItem", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "User id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Item marked as favorite.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserItemDataDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/UserItemDataDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/UserItemDataDto" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + }, + "delete": { + "tags": ["UserLibrary"], + "summary": "Unmarks item as a favorite.", + "operationId": "UnmarkFavoriteItem", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "User id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Item unmarked as favorite.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserItemDataDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/UserItemDataDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/UserItemDataDto" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/UserItems/{itemId}/Rating": { + "delete": { + "tags": ["UserLibrary"], + "summary": "Deletes a user's saved personal rating for an item.", + "operationId": "DeleteUserItemRating", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "User id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Personal rating removed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserItemDataDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/UserItemDataDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/UserItemDataDto" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + }, + "post": { + "tags": ["UserLibrary"], + "summary": "Updates a user's rating for an item.", + "operationId": "UpdateUserItemRating", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "User id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "itemId", + "in": "path", + "description": "Item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "likes", + "in": "query", + "description": "Whether this M:Jellyfin.Api.Controllers.UserLibraryController.UpdateUserItemRating(System.Nullable{System.Guid},System.Guid,System.Nullable{System.Boolean}) is likes.", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Item rating updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserItemDataDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/UserItemDataDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/UserItemDataDto" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/UserViews": { + "get": { + "tags": ["UserViews"], + "summary": "Get user views.", + "operationId": "GetUserViews", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "User id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "includeExternalContent", + "in": "query", + "description": "Whether or not to include external views such as channels or live tv.", + "schema": { + "type": "boolean" + } + }, + { + "name": "presetViews", + "in": "query", + "description": "Preset views.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CollectionType" + } + } + }, + { + "name": "includeHidden", + "in": "query", + "description": "Whether or not to include hidden content.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "User views returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/UserViews/GroupingOptions": { + "get": { + "tags": ["UserViews"], + "summary": "Get user view grouping options.", + "operationId": "GetGroupingOptions", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "User id.", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "User view grouping options returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SpecialViewOptionDto" + } + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SpecialViewOptionDto" + } + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SpecialViewOptionDto" + } + } + } + } + }, + "404": { + "description": "User not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Videos/{videoId}/{mediaSourceId}/Attachments/{index}": { + "get": { + "tags": ["VideoAttachments"], + "summary": "Get video attachment.", + "operationId": "GetAttachment", + "parameters": [ + { + "name": "videoId", + "in": "path", + "description": "Video ID.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "mediaSourceId", + "in": "path", + "description": "Media Source ID.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "index", + "in": "path", + "description": "Attachment Index.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Attachment retrieved.", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Video or attachment not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + } + }, + "/Videos/{itemId}/AdditionalParts": { + "get": { + "tags": ["Videos"], + "summary": "Gets additional parts for a video.", + "operationId": "GetAdditionalPart", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user id, and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Additional parts returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Videos/{itemId}/AlternateSources": { + "delete": { + "tags": ["Videos"], + "summary": "Removes alternate video sources.", + "operationId": "DeleteAlternateSources", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "204": { + "description": "Alternate sources deleted." + }, + "404": { + "description": "Video not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Videos/{itemId}/stream": { + "get": { + "tags": ["Videos"], + "summary": "Gets a video stream.", + "operationId": "GetVideoStream", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "container", + "in": "query", + "description": "The video container. Possible values are: ts, webm, asf, wmv, ogv, mp4, m4v, mkv, mpeg, mpg, avi, 3gp, wmv, wtv, m2ts, mov, iso, flv.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "static", + "in": "query", + "description": "Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "params", + "in": "query", + "description": "The streaming parameters.", + "schema": { + "type": "string" + } + }, + { + "name": "tag", + "in": "query", + "description": "The tag.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceProfileId", + "in": "query", + "description": "Optional. The dlna device profile id to utilize.", + "deprecated": true, + "schema": { + "type": "string" + } + }, + { + "name": "playSessionId", + "in": "query", + "description": "The play session id.", + "schema": { + "type": "string" + } + }, + { + "name": "segmentContainer", + "in": "query", + "description": "The segment container.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "segmentLength", + "in": "query", + "description": "The segment length.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "minSegments", + "in": "query", + "description": "The minimum number of segments.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "The media version id, if playing an alternate version.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "The device id of the client requesting. Used to stop encoding processes when needed.", + "schema": { + "type": "string" + } + }, + { + "name": "audioCodec", + "in": "query", + "description": "Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "enableAutoStreamCopy", + "in": "query", + "description": "Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowVideoStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the video stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowAudioStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the audio stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "breakOnNonKeyFrames", + "in": "query", + "description": "Optional. Whether to break on non key frames.", + "schema": { + "type": "boolean" + } + }, + { + "name": "audioSampleRate", + "in": "query", + "description": "Optional. Specify a specific audio sample rate, e.g. 44100.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioBitDepth", + "in": "query", + "description": "Optional. The maximum audio bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioBitRate", + "in": "query", + "description": "Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioChannels", + "in": "query", + "description": "Optional. Specify a specific number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioChannels", + "in": "query", + "description": "Optional. Specify a maximum number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "profile", + "in": "query", + "description": "Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high.", + "schema": { + "type": "string" + } + }, + { + "name": "level", + "in": "query", + "description": "Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1.", + "schema": { + "type": "string" + } + }, + { + "name": "framerate", + "in": "query", + "description": "Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "maxFramerate", + "in": "query", + "description": "Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "copyTimestamps", + "in": "query", + "description": "Whether or not to copy timestamps when transcoding with an offset. Defaults to false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "startTimeTicks", + "in": "query", + "description": "Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "width", + "in": "query", + "description": "Optional. The fixed horizontal resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "Optional. The fixed vertical resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "Optional. The maximum horizontal resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "Optional. The maximum vertical resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoBitRate", + "in": "query", + "description": "Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleStreamIndex", + "in": "query", + "description": "Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleMethod", + "in": "query", + "description": "Optional. Specify the subtitle delivery method.", + "schema": { + "enum": ["Encode", "Embed", "External", "Hls", "Drop"], + "allOf": [ + { + "$ref": "#/components/schemas/SubtitleDeliveryMethod" + } + ] + } + }, + { + "name": "maxRefFrames", + "in": "query", + "description": "Optional.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxVideoBitDepth", + "in": "query", + "description": "Optional. The maximum video bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "requireAvc", + "in": "query", + "description": "Optional. Whether to require avc.", + "schema": { + "type": "boolean" + } + }, + { + "name": "deInterlace", + "in": "query", + "description": "Optional. Whether to deinterlace the video.", + "schema": { + "type": "boolean" + } + }, + { + "name": "requireNonAnamorphic", + "in": "query", + "description": "Optional. Whether to require a non anamorphic stream.", + "schema": { + "type": "boolean" + } + }, + { + "name": "transcodingMaxAudioChannels", + "in": "query", + "description": "Optional. The maximum number of audio channels to transcode.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "cpuCoreLimit", + "in": "query", + "description": "Optional. The limit of how many cpu cores to use.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "liveStreamId", + "in": "query", + "description": "The live stream id.", + "schema": { + "type": "string" + } + }, + { + "name": "enableMpegtsM2TsMode", + "in": "query", + "description": "Optional. Whether to enable the MpegtsM2Ts mode.", + "schema": { + "type": "boolean" + } + }, + { + "name": "videoCodec", + "in": "query", + "description": "Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "subtitleCodec", + "in": "query", + "description": "Optional. Specify a subtitle codec to encode to.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "transcodeReasons", + "in": "query", + "description": "Optional. The transcoding reason.", + "schema": { + "type": "string" + } + }, + { + "name": "audioStreamIndex", + "in": "query", + "description": "Optional. The index of the audio stream to use. If omitted the first audio stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoStreamIndex", + "in": "query", + "description": "Optional. The index of the video stream to use. If omitted the first video stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "context", + "in": "query", + "description": "Optional. The MediaBrowser.Model.Dlna.EncodingContext.", + "schema": { + "enum": ["Streaming", "Static"], + "allOf": [ + { + "$ref": "#/components/schemas/EncodingContext" + } + ] + } + }, + { + "name": "streamOptions", + "in": "query", + "description": "Optional. The streaming options.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + } + } + } + ], + "responses": { + "200": { + "description": "Video stream returned.", + "content": { + "video/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + } + } + }, + "head": { + "tags": ["Videos"], + "summary": "Gets a video stream.", + "operationId": "HeadVideoStream", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "container", + "in": "query", + "description": "The video container. Possible values are: ts, webm, asf, wmv, ogv, mp4, m4v, mkv, mpeg, mpg, avi, 3gp, wmv, wtv, m2ts, mov, iso, flv.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "static", + "in": "query", + "description": "Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "params", + "in": "query", + "description": "The streaming parameters.", + "schema": { + "type": "string" + } + }, + { + "name": "tag", + "in": "query", + "description": "The tag.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceProfileId", + "in": "query", + "description": "Optional. The dlna device profile id to utilize.", + "deprecated": true, + "schema": { + "type": "string" + } + }, + { + "name": "playSessionId", + "in": "query", + "description": "The play session id.", + "schema": { + "type": "string" + } + }, + { + "name": "segmentContainer", + "in": "query", + "description": "The segment container.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "segmentLength", + "in": "query", + "description": "The segment length.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "minSegments", + "in": "query", + "description": "The minimum number of segments.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "The media version id, if playing an alternate version.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "The device id of the client requesting. Used to stop encoding processes when needed.", + "schema": { + "type": "string" + } + }, + { + "name": "audioCodec", + "in": "query", + "description": "Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "enableAutoStreamCopy", + "in": "query", + "description": "Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowVideoStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the video stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowAudioStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the audio stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "breakOnNonKeyFrames", + "in": "query", + "description": "Optional. Whether to break on non key frames.", + "schema": { + "type": "boolean" + } + }, + { + "name": "audioSampleRate", + "in": "query", + "description": "Optional. Specify a specific audio sample rate, e.g. 44100.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioBitDepth", + "in": "query", + "description": "Optional. The maximum audio bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioBitRate", + "in": "query", + "description": "Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioChannels", + "in": "query", + "description": "Optional. Specify a specific number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioChannels", + "in": "query", + "description": "Optional. Specify a maximum number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "profile", + "in": "query", + "description": "Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high.", + "schema": { + "type": "string" + } + }, + { + "name": "level", + "in": "query", + "description": "Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1.", + "schema": { + "type": "string" + } + }, + { + "name": "framerate", + "in": "query", + "description": "Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "maxFramerate", + "in": "query", + "description": "Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "copyTimestamps", + "in": "query", + "description": "Whether or not to copy timestamps when transcoding with an offset. Defaults to false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "startTimeTicks", + "in": "query", + "description": "Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "width", + "in": "query", + "description": "Optional. The fixed horizontal resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "Optional. The fixed vertical resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "Optional. The maximum horizontal resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "Optional. The maximum vertical resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoBitRate", + "in": "query", + "description": "Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleStreamIndex", + "in": "query", + "description": "Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleMethod", + "in": "query", + "description": "Optional. Specify the subtitle delivery method.", + "schema": { + "enum": ["Encode", "Embed", "External", "Hls", "Drop"], + "allOf": [ + { + "$ref": "#/components/schemas/SubtitleDeliveryMethod" + } + ] + } + }, + { + "name": "maxRefFrames", + "in": "query", + "description": "Optional.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxVideoBitDepth", + "in": "query", + "description": "Optional. The maximum video bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "requireAvc", + "in": "query", + "description": "Optional. Whether to require avc.", + "schema": { + "type": "boolean" + } + }, + { + "name": "deInterlace", + "in": "query", + "description": "Optional. Whether to deinterlace the video.", + "schema": { + "type": "boolean" + } + }, + { + "name": "requireNonAnamorphic", + "in": "query", + "description": "Optional. Whether to require a non anamorphic stream.", + "schema": { + "type": "boolean" + } + }, + { + "name": "transcodingMaxAudioChannels", + "in": "query", + "description": "Optional. The maximum number of audio channels to transcode.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "cpuCoreLimit", + "in": "query", + "description": "Optional. The limit of how many cpu cores to use.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "liveStreamId", + "in": "query", + "description": "The live stream id.", + "schema": { + "type": "string" + } + }, + { + "name": "enableMpegtsM2TsMode", + "in": "query", + "description": "Optional. Whether to enable the MpegtsM2Ts mode.", + "schema": { + "type": "boolean" + } + }, + { + "name": "videoCodec", + "in": "query", + "description": "Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "subtitleCodec", + "in": "query", + "description": "Optional. Specify a subtitle codec to encode to.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "transcodeReasons", + "in": "query", + "description": "Optional. The transcoding reason.", + "schema": { + "type": "string" + } + }, + { + "name": "audioStreamIndex", + "in": "query", + "description": "Optional. The index of the audio stream to use. If omitted the first audio stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoStreamIndex", + "in": "query", + "description": "Optional. The index of the video stream to use. If omitted the first video stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "context", + "in": "query", + "description": "Optional. The MediaBrowser.Model.Dlna.EncodingContext.", + "schema": { + "enum": ["Streaming", "Static"], + "allOf": [ + { + "$ref": "#/components/schemas/EncodingContext" + } + ] + } + }, + { + "name": "streamOptions", + "in": "query", + "description": "Optional. The streaming options.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + } + } + } + ], + "responses": { + "200": { + "description": "Video stream returned.", + "content": { + "video/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + } + } + } + }, + "/Videos/{itemId}/stream.{container}": { + "get": { + "tags": ["Videos"], + "summary": "Gets a video stream.", + "operationId": "GetVideoStreamByContainer", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "container", + "in": "path", + "description": "The video container. Possible values are: ts, webm, asf, wmv, ogv, mp4, m4v, mkv, mpeg, mpg, avi, 3gp, wmv, wtv, m2ts, mov, iso, flv.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "static", + "in": "query", + "description": "Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "params", + "in": "query", + "description": "The streaming parameters.", + "schema": { + "type": "string" + } + }, + { + "name": "tag", + "in": "query", + "description": "The tag.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceProfileId", + "in": "query", + "description": "Optional. The dlna device profile id to utilize.", + "schema": { + "type": "string" + } + }, + { + "name": "playSessionId", + "in": "query", + "description": "The play session id.", + "schema": { + "type": "string" + } + }, + { + "name": "segmentContainer", + "in": "query", + "description": "The segment container.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "segmentLength", + "in": "query", + "description": "The segment length.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "minSegments", + "in": "query", + "description": "The minimum number of segments.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "The media version id, if playing an alternate version.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "The device id of the client requesting. Used to stop encoding processes when needed.", + "schema": { + "type": "string" + } + }, + { + "name": "audioCodec", + "in": "query", + "description": "Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "enableAutoStreamCopy", + "in": "query", + "description": "Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowVideoStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the video stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowAudioStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the audio stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "breakOnNonKeyFrames", + "in": "query", + "description": "Optional. Whether to break on non key frames.", + "schema": { + "type": "boolean" + } + }, + { + "name": "audioSampleRate", + "in": "query", + "description": "Optional. Specify a specific audio sample rate, e.g. 44100.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioBitDepth", + "in": "query", + "description": "Optional. The maximum audio bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioBitRate", + "in": "query", + "description": "Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioChannels", + "in": "query", + "description": "Optional. Specify a specific number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioChannels", + "in": "query", + "description": "Optional. Specify a maximum number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "profile", + "in": "query", + "description": "Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high.", + "schema": { + "type": "string" + } + }, + { + "name": "level", + "in": "query", + "description": "Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1.", + "schema": { + "type": "string" + } + }, + { + "name": "framerate", + "in": "query", + "description": "Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "maxFramerate", + "in": "query", + "description": "Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "copyTimestamps", + "in": "query", + "description": "Whether or not to copy timestamps when transcoding with an offset. Defaults to false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "startTimeTicks", + "in": "query", + "description": "Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "width", + "in": "query", + "description": "Optional. The fixed horizontal resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "Optional. The fixed vertical resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "Optional. The maximum horizontal resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "Optional. The maximum vertical resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoBitRate", + "in": "query", + "description": "Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleStreamIndex", + "in": "query", + "description": "Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleMethod", + "in": "query", + "description": "Optional. Specify the subtitle delivery method.", + "schema": { + "enum": ["Encode", "Embed", "External", "Hls", "Drop"], + "allOf": [ + { + "$ref": "#/components/schemas/SubtitleDeliveryMethod" + } + ] + } + }, + { + "name": "maxRefFrames", + "in": "query", + "description": "Optional.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxVideoBitDepth", + "in": "query", + "description": "Optional. The maximum video bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "requireAvc", + "in": "query", + "description": "Optional. Whether to require avc.", + "schema": { + "type": "boolean" + } + }, + { + "name": "deInterlace", + "in": "query", + "description": "Optional. Whether to deinterlace the video.", + "schema": { + "type": "boolean" + } + }, + { + "name": "requireNonAnamorphic", + "in": "query", + "description": "Optional. Whether to require a non anamorphic stream.", + "schema": { + "type": "boolean" + } + }, + { + "name": "transcodingMaxAudioChannels", + "in": "query", + "description": "Optional. The maximum number of audio channels to transcode.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "cpuCoreLimit", + "in": "query", + "description": "Optional. The limit of how many cpu cores to use.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "liveStreamId", + "in": "query", + "description": "The live stream id.", + "schema": { + "type": "string" + } + }, + { + "name": "enableMpegtsM2TsMode", + "in": "query", + "description": "Optional. Whether to enable the MpegtsM2Ts mode.", + "schema": { + "type": "boolean" + } + }, + { + "name": "videoCodec", + "in": "query", + "description": "Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "subtitleCodec", + "in": "query", + "description": "Optional. Specify a subtitle codec to encode to.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "transcodeReasons", + "in": "query", + "description": "Optional. The transcoding reason.", + "schema": { + "type": "string" + } + }, + { + "name": "audioStreamIndex", + "in": "query", + "description": "Optional. The index of the audio stream to use. If omitted the first audio stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoStreamIndex", + "in": "query", + "description": "Optional. The index of the video stream to use. If omitted the first video stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "context", + "in": "query", + "description": "Optional. The MediaBrowser.Model.Dlna.EncodingContext.", + "schema": { + "enum": ["Streaming", "Static"], + "allOf": [ + { + "$ref": "#/components/schemas/EncodingContext" + } + ] + } + }, + { + "name": "streamOptions", + "in": "query", + "description": "Optional. The streaming options.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + } + } + } + ], + "responses": { + "200": { + "description": "Video stream returned.", + "content": { + "video/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + } + } + }, + "head": { + "tags": ["Videos"], + "summary": "Gets a video stream.", + "operationId": "HeadVideoStreamByContainer", + "parameters": [ + { + "name": "itemId", + "in": "path", + "description": "The item id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "container", + "in": "path", + "description": "The video container. Possible values are: ts, webm, asf, wmv, ogv, mp4, m4v, mkv, mpeg, mpg, avi, 3gp, wmv, wtv, m2ts, mov, iso, flv.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "static", + "in": "query", + "description": "Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "params", + "in": "query", + "description": "The streaming parameters.", + "schema": { + "type": "string" + } + }, + { + "name": "tag", + "in": "query", + "description": "The tag.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceProfileId", + "in": "query", + "description": "Optional. The dlna device profile id to utilize.", + "schema": { + "type": "string" + } + }, + { + "name": "playSessionId", + "in": "query", + "description": "The play session id.", + "schema": { + "type": "string" + } + }, + { + "name": "segmentContainer", + "in": "query", + "description": "The segment container.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "segmentLength", + "in": "query", + "description": "The segment length.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "minSegments", + "in": "query", + "description": "The minimum number of segments.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "mediaSourceId", + "in": "query", + "description": "The media version id, if playing an alternate version.", + "schema": { + "type": "string" + } + }, + { + "name": "deviceId", + "in": "query", + "description": "The device id of the client requesting. Used to stop encoding processes when needed.", + "schema": { + "type": "string" + } + }, + { + "name": "audioCodec", + "in": "query", + "description": "Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "enableAutoStreamCopy", + "in": "query", + "description": "Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowVideoStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the video stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "allowAudioStreamCopy", + "in": "query", + "description": "Whether or not to allow copying of the audio stream url.", + "schema": { + "type": "boolean" + } + }, + { + "name": "breakOnNonKeyFrames", + "in": "query", + "description": "Optional. Whether to break on non key frames.", + "schema": { + "type": "boolean" + } + }, + { + "name": "audioSampleRate", + "in": "query", + "description": "Optional. Specify a specific audio sample rate, e.g. 44100.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioBitDepth", + "in": "query", + "description": "Optional. The maximum audio bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioBitRate", + "in": "query", + "description": "Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "audioChannels", + "in": "query", + "description": "Optional. Specify a specific number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxAudioChannels", + "in": "query", + "description": "Optional. Specify a maximum number of audio channels to encode to, e.g. 2.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "profile", + "in": "query", + "description": "Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high.", + "schema": { + "type": "string" + } + }, + { + "name": "level", + "in": "query", + "description": "Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1.", + "schema": { + "type": "string" + } + }, + { + "name": "framerate", + "in": "query", + "description": "Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "maxFramerate", + "in": "query", + "description": "Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", + "schema": { + "type": "number", + "format": "float" + } + }, + { + "name": "copyTimestamps", + "in": "query", + "description": "Whether or not to copy timestamps when transcoding with an offset. Defaults to false.", + "schema": { + "type": "boolean" + } + }, + { + "name": "startTimeTicks", + "in": "query", + "description": "Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "width", + "in": "query", + "description": "Optional. The fixed horizontal resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "height", + "in": "query", + "description": "Optional. The fixed vertical resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxWidth", + "in": "query", + "description": "Optional. The maximum horizontal resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxHeight", + "in": "query", + "description": "Optional. The maximum vertical resolution of the encoded video.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoBitRate", + "in": "query", + "description": "Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleStreamIndex", + "in": "query", + "description": "Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "subtitleMethod", + "in": "query", + "description": "Optional. Specify the subtitle delivery method.", + "schema": { + "enum": ["Encode", "Embed", "External", "Hls", "Drop"], + "allOf": [ + { + "$ref": "#/components/schemas/SubtitleDeliveryMethod" + } + ] + } + }, + { + "name": "maxRefFrames", + "in": "query", + "description": "Optional.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "maxVideoBitDepth", + "in": "query", + "description": "Optional. The maximum video bit depth.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "requireAvc", + "in": "query", + "description": "Optional. Whether to require avc.", + "schema": { + "type": "boolean" + } + }, + { + "name": "deInterlace", + "in": "query", + "description": "Optional. Whether to deinterlace the video.", + "schema": { + "type": "boolean" + } + }, + { + "name": "requireNonAnamorphic", + "in": "query", + "description": "Optional. Whether to require a non anamorphic stream.", + "schema": { + "type": "boolean" + } + }, + { + "name": "transcodingMaxAudioChannels", + "in": "query", + "description": "Optional. The maximum number of audio channels to transcode.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "cpuCoreLimit", + "in": "query", + "description": "Optional. The limit of how many cpu cores to use.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "liveStreamId", + "in": "query", + "description": "The live stream id.", + "schema": { + "type": "string" + } + }, + { + "name": "enableMpegtsM2TsMode", + "in": "query", + "description": "Optional. Whether to enable the MpegtsM2Ts mode.", + "schema": { + "type": "boolean" + } + }, + { + "name": "videoCodec", + "in": "query", + "description": "Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "subtitleCodec", + "in": "query", + "description": "Optional. Specify a subtitle codec to encode to.", + "schema": { + "pattern": "^[a-zA-Z0-9\\-\\._,|]{0,40}$", + "type": "string" + } + }, + { + "name": "transcodeReasons", + "in": "query", + "description": "Optional. The transcoding reason.", + "schema": { + "type": "string" + } + }, + { + "name": "audioStreamIndex", + "in": "query", + "description": "Optional. The index of the audio stream to use. If omitted the first audio stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "videoStreamIndex", + "in": "query", + "description": "Optional. The index of the video stream to use. If omitted the first video stream will be used.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "context", + "in": "query", + "description": "Optional. The MediaBrowser.Model.Dlna.EncodingContext.", + "schema": { + "enum": ["Streaming", "Static"], + "allOf": [ + { + "$ref": "#/components/schemas/EncodingContext" + } + ] + } + }, + { + "name": "streamOptions", + "in": "query", + "description": "Optional. The streaming options.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + } + } + } + ], + "responses": { + "200": { + "description": "Video stream returned.", + "content": { + "video/*": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + } + } + } + }, + "/Videos/MergeVersions": { + "post": { + "tags": ["Videos"], + "summary": "Merges videos into a single record.", + "operationId": "MergeVersions", + "parameters": [ + { + "name": "ids", + "in": "query", + "description": "Item id list. This allows multiple, comma delimited.", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + } + ], + "responses": { + "204": { + "description": "Videos merged." + }, + "400": { + "description": "Supply at least 2 video ids.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Intros/Episode/{Id}/Chromaprint": { + "get": { + "tags": ["Visualization"], + "operationId": "GetEpisodeFingerprint", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Intros/Episode/{Id}/UpdateIntroTimestamps": { + "post": { + "tags": ["Visualization"], + "operationId": "UpdateTimestamps", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/Intro" + } + ] + } + }, + "text/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/Intro" + } + ] + } + }, + "application/*+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/Intro" + } + ] + } + } + } + }, + "responses": { + "200": { + "description": "Success" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Intros/Show/{Series}/{Season}": { + "get": { + "tags": ["Visualization"], + "operationId": "GetSeasonEpisodes", + "parameters": [ + { + "name": "series", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "season", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EpisodeVisualization" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + }, + "delete": { + "tags": ["Visualization"], + "operationId": "EraseSeason", + "parameters": [ + { + "name": "series", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "season", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "eraseCache", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Success" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Intros/Shows": { + "get": { + "tags": ["Visualization"], + "operationId": "GetShowSeasons", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["RequiresElevation"] + } + ] + } + }, + "/Years": { + "get": { + "tags": ["Years"], + "summary": "Get years.", + "operationId": "GetYears", + "parameters": [ + { + "name": "startIndex", + "in": "query", + "description": "Skips over a given number of items within the results. Use for paging.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "limit", + "in": "query", + "description": "Optional. The maximum number of records to return.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "sortOrder", + "in": "query", + "description": "Sort Order - Ascending,Descending.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SortOrder" + } + } + }, + { + "name": "parentId", + "in": "query", + "description": "Specify this to localize the search to a specific item or folder. Omit to use the root.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "fields", + "in": "query", + "description": "Optional. Specify additional fields of information to return in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + } + } + }, + { + "name": "excludeItemTypes", + "in": "query", + "description": "Optional. If specified, results will be excluded based on item type. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemKind" + } + } + }, + { + "name": "includeItemTypes", + "in": "query", + "description": "Optional. If specified, results will be included based on item type. This allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemKind" + } + } + }, + { + "name": "mediaTypes", + "in": "query", + "description": "Optional. Filter by MediaType. Allows multiple, comma delimited.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MediaType" + } + } + }, + { + "name": "sortBy", + "in": "query", + "description": "Optional. Specify one or more sort orders, comma delimited. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemSortBy" + } + } + }, + { + "name": "enableUserData", + "in": "query", + "description": "Optional. Include user data.", + "schema": { + "type": "boolean" + } + }, + { + "name": "imageTypeLimit", + "in": "query", + "description": "Optional. The max number of images to return, per image type.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "enableImageTypes", + "in": "query", + "description": "Optional. The image types to include in the output.", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + } + } + }, + { + "name": "userId", + "in": "query", + "description": "User Id.", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "recursive", + "in": "query", + "description": "Search recursively.", + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "enableImages", + "in": "query", + "description": "Optional. Include image information in output.", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Year query returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDtoQueryResult" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + }, + "/Years/{year}": { + "get": { + "tags": ["Years"], + "summary": "Gets a year.", + "operationId": "GetYear", + "parameters": [ + { + "name": "year", + "in": "path", + "description": "The year.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "userId", + "in": "query", + "description": "Optional. Filter by user id, and attach user data.", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Year returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/BaseItemDto" + } + } + } + }, + "404": { + "description": "Year not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"CamelCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json; profile=\"PascalCase\"": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "CustomAuthentication": ["DefaultAuthorization"] + } + ] + } + } + }, + "components": { + "schemas": { + "AccessSchedule": { + "type": "object", + "properties": { + "Id": { + "type": "integer", + "description": "Gets the id of this instance.", + "format": "int32", + "readOnly": true + }, + "UserId": { + "type": "string", + "description": "Gets the id of the associated user.", + "format": "uuid" + }, + "DayOfWeek": { + "enum": [ + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", + "Everyday", + "Weekday", + "Weekend" + ], + "allOf": [ + { + "$ref": "#/components/schemas/DynamicDayOfWeek" + } + ], + "description": "Gets or sets the day of week." + }, + "StartHour": { + "type": "number", + "description": "Gets or sets the start hour.", + "format": "double" + }, + "EndHour": { + "type": "number", + "description": "Gets or sets the end hour.", + "format": "double" + } + }, + "additionalProperties": false, + "description": "An entity representing a user's access schedule." + }, + "ActivityLogEntry": { + "type": "object", + "properties": { + "Id": { + "type": "integer", + "description": "Gets or sets the identifier.", + "format": "int64" + }, + "Name": { + "type": "string", + "description": "Gets or sets the name." + }, + "Overview": { + "type": "string", + "description": "Gets or sets the overview.", + "nullable": true + }, + "ShortOverview": { + "type": "string", + "description": "Gets or sets the short overview.", + "nullable": true + }, + "Type": { + "type": "string", + "description": "Gets or sets the type." + }, + "ItemId": { + "type": "string", + "description": "Gets or sets the item identifier.", + "nullable": true + }, + "Date": { + "type": "string", + "description": "Gets or sets the date.", + "format": "date-time" + }, + "UserId": { + "type": "string", + "description": "Gets or sets the user identifier.", + "format": "uuid" + }, + "UserPrimaryImageTag": { + "type": "string", + "description": "Gets or sets the user primary image tag.", + "nullable": true, + "deprecated": true + }, + "Severity": { + "enum": [ + "Trace", + "Debug", + "Information", + "Warning", + "Error", + "Critical", + "None" + ], + "allOf": [ + { + "$ref": "#/components/schemas/LogLevel" + } + ], + "description": "Gets or sets the log severity." + } + }, + "additionalProperties": false, + "description": "An activity log entry." + }, + "ActivityLogEntryMessage": { + "type": "object", + "properties": { + "Data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ActivityLogEntry" + }, + "description": "Gets or sets the data.", + "nullable": true + }, + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "ActivityLogEntry", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Activity log created message." + }, + "ActivityLogEntryQueryResult": { + "type": "object", + "properties": { + "Items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ActivityLogEntry" + }, + "description": "Gets or sets the items.", + "nullable": true + }, + "TotalRecordCount": { + "type": "integer", + "description": "Gets or sets the total number of records available.", + "format": "int32" + }, + "StartIndex": { + "type": "integer", + "description": "Gets or sets the index of the first record in Items.", + "format": "int32" + } + }, + "additionalProperties": false + }, + "ActivityLogEntryStartMessage": { + "type": "object", + "properties": { + "Data": { + "type": "string", + "description": "Gets or sets the data.", + "nullable": true + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "ActivityLogEntryStart", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Activity log entry start message.\r\nData is the timing data encoded as \"$initialDelay,$interval\" in ms." + }, + "ActivityLogEntryStopMessage": { + "type": "object", + "properties": { + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "ActivityLogEntryStop", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Activity log entry stop message." + }, + "AddVirtualFolderDto": { + "type": "object", + "properties": { + "LibraryOptions": { + "allOf": [ + { + "$ref": "#/components/schemas/LibraryOptions" + } + ], + "description": "Gets or sets library options.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Add virtual folder dto." + }, + "AlbumInfo": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + }, + "OriginalTitle": { + "type": "string", + "description": "Gets or sets the original title.", + "nullable": true + }, + "Path": { + "type": "string", + "description": "Gets or sets the path.", + "nullable": true + }, + "MetadataLanguage": { + "type": "string", + "description": "Gets or sets the metadata language.", + "nullable": true + }, + "MetadataCountryCode": { + "type": "string", + "description": "Gets or sets the metadata country code.", + "nullable": true + }, + "ProviderIds": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "description": "Gets or sets the provider ids.", + "nullable": true + }, + "Year": { + "type": "integer", + "description": "Gets or sets the year.", + "format": "int32", + "nullable": true + }, + "IndexNumber": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "ParentIndexNumber": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "PremiereDate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "IsAutomated": { + "type": "boolean" + }, + "AlbumArtists": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the album artist." + }, + "ArtistProviderIds": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "description": "Gets or sets the artist provider ids." + }, + "SongInfos": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SongInfo" + } + } + }, + "additionalProperties": false + }, + "AlbumInfoRemoteSearchQuery": { + "type": "object", + "properties": { + "SearchInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/AlbumInfo" + } + ], + "nullable": true + }, + "ItemId": { + "type": "string", + "format": "uuid" + }, + "SearchProviderName": { + "type": "string", + "description": "Gets or sets the provider name to search within if set.", + "nullable": true + }, + "IncludeDisabledProviders": { + "type": "boolean", + "description": "Gets or sets a value indicating whether disabled providers should be included." + } + }, + "additionalProperties": false + }, + "AllThemeMediaResult": { + "type": "object", + "properties": { + "ThemeVideosResult": { + "allOf": [ + { + "$ref": "#/components/schemas/ThemeMediaResult" + } + ], + "description": "Class ThemeMediaResult.", + "nullable": true + }, + "ThemeSongsResult": { + "allOf": [ + { + "$ref": "#/components/schemas/ThemeMediaResult" + } + ], + "description": "Class ThemeMediaResult.", + "nullable": true + }, + "SoundtrackSongsResult": { + "allOf": [ + { + "$ref": "#/components/schemas/ThemeMediaResult" + } + ], + "description": "Class ThemeMediaResult.", + "nullable": true + } + }, + "additionalProperties": false + }, + "AnalysisMode": { + "enum": ["Introduction", "Credits"], + "type": "string" + }, + "ArtistInfo": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + }, + "OriginalTitle": { + "type": "string", + "description": "Gets or sets the original title.", + "nullable": true + }, + "Path": { + "type": "string", + "description": "Gets or sets the path.", + "nullable": true + }, + "MetadataLanguage": { + "type": "string", + "description": "Gets or sets the metadata language.", + "nullable": true + }, + "MetadataCountryCode": { + "type": "string", + "description": "Gets or sets the metadata country code.", + "nullable": true + }, + "ProviderIds": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "description": "Gets or sets the provider ids.", + "nullable": true + }, + "Year": { + "type": "integer", + "description": "Gets or sets the year.", + "format": "int32", + "nullable": true + }, + "IndexNumber": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "ParentIndexNumber": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "PremiereDate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "IsAutomated": { + "type": "boolean" + }, + "SongInfos": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SongInfo" + } + } + }, + "additionalProperties": false + }, + "ArtistInfoRemoteSearchQuery": { + "type": "object", + "properties": { + "SearchInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/ArtistInfo" + } + ], + "nullable": true + }, + "ItemId": { + "type": "string", + "format": "uuid" + }, + "SearchProviderName": { + "type": "string", + "description": "Gets or sets the provider name to search within if set.", + "nullable": true + }, + "IncludeDisabledProviders": { + "type": "boolean", + "description": "Gets or sets a value indicating whether disabled providers should be included." + } + }, + "additionalProperties": false + }, + "AudioSpatialFormat": { + "enum": ["None", "DolbyAtmos", "DTSX"], + "type": "string", + "description": "An enum representing formats of spatial audio." + }, + "AuthenticateUserByName": { + "type": "object", + "properties": { + "Username": { + "type": "string", + "description": "Gets or sets the username.", + "nullable": true + }, + "Pw": { + "type": "string", + "description": "Gets or sets the plain text password.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "The authenticate user by name request body." + }, + "AuthenticationInfo": { + "type": "object", + "properties": { + "Id": { + "type": "integer", + "description": "Gets or sets the identifier.", + "format": "int64" + }, + "AccessToken": { + "type": "string", + "description": "Gets or sets the access token.", + "nullable": true + }, + "DeviceId": { + "type": "string", + "description": "Gets or sets the device identifier.", + "nullable": true + }, + "AppName": { + "type": "string", + "description": "Gets or sets the name of the application.", + "nullable": true + }, + "AppVersion": { + "type": "string", + "description": "Gets or sets the application version.", + "nullable": true + }, + "DeviceName": { + "type": "string", + "description": "Gets or sets the name of the device.", + "nullable": true + }, + "UserId": { + "type": "string", + "description": "Gets or sets the user identifier.", + "format": "uuid" + }, + "IsActive": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is active." + }, + "DateCreated": { + "type": "string", + "description": "Gets or sets the date created.", + "format": "date-time" + }, + "DateRevoked": { + "type": "string", + "description": "Gets or sets the date revoked.", + "format": "date-time", + "nullable": true + }, + "DateLastActivity": { + "type": "string", + "format": "date-time" + }, + "UserName": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "AuthenticationInfoQueryResult": { + "type": "object", + "properties": { + "Items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AuthenticationInfo" + }, + "description": "Gets or sets the items.", + "nullable": true + }, + "TotalRecordCount": { + "type": "integer", + "description": "Gets or sets the total number of records available.", + "format": "int32" + }, + "StartIndex": { + "type": "integer", + "description": "Gets or sets the index of the first record in Items.", + "format": "int32" + } + }, + "additionalProperties": false + }, + "AuthenticationResult": { + "type": "object", + "properties": { + "User": { + "allOf": [ + { + "$ref": "#/components/schemas/UserDto" + } + ], + "description": "Class UserDto.", + "nullable": true + }, + "SessionInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/SessionInfo" + } + ], + "description": "Class SessionInfo.", + "nullable": true + }, + "AccessToken": { + "type": "string", + "nullable": true + }, + "ServerId": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "BaseItemDto": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + }, + "OriginalTitle": { + "type": "string", + "nullable": true + }, + "ServerId": { + "type": "string", + "description": "Gets or sets the server identifier.", + "nullable": true + }, + "Id": { + "type": "string", + "description": "Gets or sets the id.", + "format": "uuid" + }, + "Etag": { + "type": "string", + "description": "Gets or sets the etag.", + "nullable": true + }, + "SourceType": { + "type": "string", + "description": "Gets or sets the type of the source.", + "nullable": true + }, + "PlaylistItemId": { + "type": "string", + "description": "Gets or sets the playlist item identifier.", + "nullable": true + }, + "DateCreated": { + "type": "string", + "description": "Gets or sets the date created.", + "format": "date-time", + "nullable": true + }, + "DateLastMediaAdded": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "ExtraType": { + "enum": [ + "Unknown", + "Clip", + "Trailer", + "BehindTheScenes", + "DeletedScene", + "Interview", + "Scene", + "Sample", + "ThemeSong", + "ThemeVideo", + "Featurette", + "Short" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ExtraType" + } + ], + "nullable": true + }, + "AirsBeforeSeasonNumber": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "AirsAfterSeasonNumber": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "AirsBeforeEpisodeNumber": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "CanDelete": { + "type": "boolean", + "nullable": true + }, + "CanDownload": { + "type": "boolean", + "nullable": true + }, + "HasLyrics": { + "type": "boolean", + "nullable": true + }, + "HasSubtitles": { + "type": "boolean", + "nullable": true + }, + "PreferredMetadataLanguage": { + "type": "string", + "nullable": true + }, + "PreferredMetadataCountryCode": { + "type": "string", + "nullable": true + }, + "Container": { + "type": "string", + "nullable": true + }, + "SortName": { + "type": "string", + "description": "Gets or sets the name of the sort.", + "nullable": true + }, + "ForcedSortName": { + "type": "string", + "nullable": true + }, + "Video3DFormat": { + "enum": [ + "HalfSideBySide", + "FullSideBySide", + "FullTopAndBottom", + "HalfTopAndBottom", + "MVC" + ], + "allOf": [ + { + "$ref": "#/components/schemas/Video3DFormat" + } + ], + "description": "Gets or sets the video3 D format.", + "nullable": true + }, + "PremiereDate": { + "type": "string", + "description": "Gets or sets the premiere date.", + "format": "date-time", + "nullable": true + }, + "ExternalUrls": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ExternalUrl" + }, + "description": "Gets or sets the external urls.", + "nullable": true + }, + "MediaSources": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MediaSourceInfo" + }, + "description": "Gets or sets the media versions.", + "nullable": true + }, + "CriticRating": { + "type": "number", + "description": "Gets or sets the critic rating.", + "format": "float", + "nullable": true + }, + "ProductionLocations": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "Path": { + "type": "string", + "description": "Gets or sets the path.", + "nullable": true + }, + "EnableMediaSourceDisplay": { + "type": "boolean", + "nullable": true + }, + "OfficialRating": { + "type": "string", + "description": "Gets or sets the official rating.", + "nullable": true + }, + "CustomRating": { + "type": "string", + "description": "Gets or sets the custom rating.", + "nullable": true + }, + "ChannelId": { + "type": "string", + "description": "Gets or sets the channel identifier.", + "format": "uuid", + "nullable": true + }, + "ChannelName": { + "type": "string", + "nullable": true + }, + "Overview": { + "type": "string", + "description": "Gets or sets the overview.", + "nullable": true + }, + "Taglines": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the taglines.", + "nullable": true + }, + "Genres": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the genres.", + "nullable": true + }, + "CommunityRating": { + "type": "number", + "description": "Gets or sets the community rating.", + "format": "float", + "nullable": true + }, + "CumulativeRunTimeTicks": { + "type": "integer", + "description": "Gets or sets the cumulative run time ticks.", + "format": "int64", + "nullable": true + }, + "RunTimeTicks": { + "type": "integer", + "description": "Gets or sets the run time ticks.", + "format": "int64", + "nullable": true + }, + "PlayAccess": { + "enum": ["Full", "None"], + "allOf": [ + { + "$ref": "#/components/schemas/PlayAccess" + } + ], + "description": "Gets or sets the play access.", + "nullable": true + }, + "AspectRatio": { + "type": "string", + "description": "Gets or sets the aspect ratio.", + "nullable": true + }, + "ProductionYear": { + "type": "integer", + "description": "Gets or sets the production year.", + "format": "int32", + "nullable": true + }, + "IsPlaceHolder": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is place holder.", + "nullable": true + }, + "Number": { + "type": "string", + "description": "Gets or sets the number.", + "nullable": true + }, + "ChannelNumber": { + "type": "string", + "nullable": true + }, + "IndexNumber": { + "type": "integer", + "description": "Gets or sets the index number.", + "format": "int32", + "nullable": true + }, + "IndexNumberEnd": { + "type": "integer", + "description": "Gets or sets the index number end.", + "format": "int32", + "nullable": true + }, + "ParentIndexNumber": { + "type": "integer", + "description": "Gets or sets the parent index number.", + "format": "int32", + "nullable": true + }, + "RemoteTrailers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MediaUrl" + }, + "description": "Gets or sets the trailer urls.", + "nullable": true + }, + "ProviderIds": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "description": "Gets or sets the provider ids.", + "nullable": true + }, + "IsHD": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is HD.", + "nullable": true + }, + "IsFolder": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is folder.", + "nullable": true + }, + "ParentId": { + "type": "string", + "description": "Gets or sets the parent id.", + "format": "uuid", + "nullable": true + }, + "Type": { + "enum": [ + "AggregateFolder", + "Audio", + "AudioBook", + "BasePluginFolder", + "Book", + "BoxSet", + "Channel", + "ChannelFolderItem", + "CollectionFolder", + "Episode", + "Folder", + "Genre", + "ManualPlaylistsFolder", + "Movie", + "LiveTvChannel", + "LiveTvProgram", + "MusicAlbum", + "MusicArtist", + "MusicGenre", + "MusicVideo", + "Person", + "Photo", + "PhotoAlbum", + "Playlist", + "PlaylistsFolder", + "Program", + "Recording", + "Season", + "Series", + "Studio", + "Trailer", + "TvChannel", + "TvProgram", + "UserRootFolder", + "UserView", + "Video", + "Year" + ], + "allOf": [ + { + "$ref": "#/components/schemas/BaseItemKind" + } + ], + "description": "The base item kind." + }, + "People": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemPerson" + }, + "description": "Gets or sets the people.", + "nullable": true + }, + "Studios": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NameGuidPair" + }, + "description": "Gets or sets the studios.", + "nullable": true + }, + "GenreItems": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NameGuidPair" + }, + "nullable": true + }, + "ParentLogoItemId": { + "type": "string", + "description": "Gets or sets whether the item has a logo, this will hold the Id of the Parent that has one.", + "format": "uuid", + "nullable": true + }, + "ParentBackdropItemId": { + "type": "string", + "description": "Gets or sets whether the item has any backdrops, this will hold the Id of the Parent that has one.", + "format": "uuid", + "nullable": true + }, + "ParentBackdropImageTags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the parent backdrop image tags.", + "nullable": true + }, + "LocalTrailerCount": { + "type": "integer", + "description": "Gets or sets the local trailer count.", + "format": "int32", + "nullable": true + }, + "UserData": { + "allOf": [ + { + "$ref": "#/components/schemas/UserItemDataDto" + } + ], + "description": "Gets or sets the user data for this item based on the user it's being requested for.", + "nullable": true + }, + "RecursiveItemCount": { + "type": "integer", + "description": "Gets or sets the recursive item count.", + "format": "int32", + "nullable": true + }, + "ChildCount": { + "type": "integer", + "description": "Gets or sets the child count.", + "format": "int32", + "nullable": true + }, + "SeriesName": { + "type": "string", + "description": "Gets or sets the name of the series.", + "nullable": true + }, + "SeriesId": { + "type": "string", + "description": "Gets or sets the series id.", + "format": "uuid", + "nullable": true + }, + "SeasonId": { + "type": "string", + "description": "Gets or sets the season identifier.", + "format": "uuid", + "nullable": true + }, + "SpecialFeatureCount": { + "type": "integer", + "description": "Gets or sets the special feature count.", + "format": "int32", + "nullable": true + }, + "DisplayPreferencesId": { + "type": "string", + "description": "Gets or sets the display preferences id.", + "nullable": true + }, + "Status": { + "type": "string", + "description": "Gets or sets the status.", + "nullable": true + }, + "AirTime": { + "type": "string", + "description": "Gets or sets the air time.", + "nullable": true + }, + "AirDays": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DayOfWeek" + }, + "description": "Gets or sets the air days.", + "nullable": true + }, + "Tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the tags.", + "nullable": true + }, + "PrimaryImageAspectRatio": { + "type": "number", + "description": "Gets or sets the primary image aspect ratio, after image enhancements.", + "format": "double", + "nullable": true + }, + "Artists": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the artists.", + "nullable": true + }, + "ArtistItems": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NameGuidPair" + }, + "description": "Gets or sets the artist items.", + "nullable": true + }, + "Album": { + "type": "string", + "description": "Gets or sets the album.", + "nullable": true + }, + "CollectionType": { + "enum": [ + "unknown", + "movies", + "tvshows", + "music", + "musicvideos", + "trailers", + "homevideos", + "boxsets", + "books", + "photos", + "livetv", + "playlists", + "folders" + ], + "allOf": [ + { + "$ref": "#/components/schemas/CollectionType" + } + ], + "description": "Gets or sets the type of the collection.", + "nullable": true + }, + "DisplayOrder": { + "type": "string", + "description": "Gets or sets the display order.", + "nullable": true + }, + "AlbumId": { + "type": "string", + "description": "Gets or sets the album id.", + "format": "uuid", + "nullable": true + }, + "AlbumPrimaryImageTag": { + "type": "string", + "description": "Gets or sets the album image tag.", + "nullable": true + }, + "SeriesPrimaryImageTag": { + "type": "string", + "description": "Gets or sets the series primary image tag.", + "nullable": true + }, + "AlbumArtist": { + "type": "string", + "description": "Gets or sets the album artist.", + "nullable": true + }, + "AlbumArtists": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NameGuidPair" + }, + "description": "Gets or sets the album artists.", + "nullable": true + }, + "SeasonName": { + "type": "string", + "description": "Gets or sets the name of the season.", + "nullable": true + }, + "MediaStreams": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MediaStream" + }, + "description": "Gets or sets the media streams.", + "nullable": true + }, + "VideoType": { + "enum": ["VideoFile", "Iso", "Dvd", "BluRay"], + "allOf": [ + { + "$ref": "#/components/schemas/VideoType" + } + ], + "description": "Gets or sets the type of the video.", + "nullable": true + }, + "PartCount": { + "type": "integer", + "description": "Gets or sets the part count.", + "format": "int32", + "nullable": true + }, + "MediaSourceCount": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "ImageTags": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Gets or sets the image tags.", + "nullable": true + }, + "BackdropImageTags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the backdrop image tags.", + "nullable": true + }, + "ScreenshotImageTags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the screenshot image tags.", + "nullable": true + }, + "ParentLogoImageTag": { + "type": "string", + "description": "Gets or sets the parent logo image tag.", + "nullable": true + }, + "ParentArtItemId": { + "type": "string", + "description": "Gets or sets whether the item has fan art, this will hold the Id of the Parent that has one.", + "format": "uuid", + "nullable": true + }, + "ParentArtImageTag": { + "type": "string", + "description": "Gets or sets the parent art image tag.", + "nullable": true + }, + "SeriesThumbImageTag": { + "type": "string", + "description": "Gets or sets the series thumb image tag.", + "nullable": true + }, + "ImageBlurHashes": { + "type": "object", + "properties": { + "Primary": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Art": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Backdrop": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Banner": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Logo": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Thumb": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Disc": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Box": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Screenshot": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Menu": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Chapter": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "BoxRear": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Profile": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "description": "Gets or sets the blurhashes for the image tags.\r\nMaps image type to dictionary mapping image tag to blurhash value.", + "nullable": true + }, + "SeriesStudio": { + "type": "string", + "description": "Gets or sets the series studio.", + "nullable": true + }, + "ParentThumbItemId": { + "type": "string", + "description": "Gets or sets the parent thumb item id.", + "format": "uuid", + "nullable": true + }, + "ParentThumbImageTag": { + "type": "string", + "description": "Gets or sets the parent thumb image tag.", + "nullable": true + }, + "ParentPrimaryImageItemId": { + "type": "string", + "description": "Gets or sets the parent primary image item identifier.", + "nullable": true + }, + "ParentPrimaryImageTag": { + "type": "string", + "description": "Gets or sets the parent primary image tag.", + "nullable": true + }, + "Chapters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ChapterInfo" + }, + "description": "Gets or sets the chapters.", + "nullable": true + }, + "Trickplay": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/TrickplayInfo" + } + }, + "description": "Gets or sets the trickplay manifest.", + "nullable": true + }, + "LocationType": { + "enum": ["FileSystem", "Remote", "Virtual", "Offline"], + "allOf": [ + { + "$ref": "#/components/schemas/LocationType" + } + ], + "description": "Gets or sets the type of the location.", + "nullable": true + }, + "IsoType": { + "enum": ["Dvd", "BluRay"], + "allOf": [ + { + "$ref": "#/components/schemas/IsoType" + } + ], + "description": "Gets or sets the type of the iso.", + "nullable": true + }, + "MediaType": { + "enum": ["Unknown", "Video", "Audio", "Photo", "Book"], + "allOf": [ + { + "$ref": "#/components/schemas/MediaType" + } + ], + "description": "Media types." + }, + "EndDate": { + "type": "string", + "description": "Gets or sets the end date.", + "format": "date-time", + "nullable": true + }, + "LockedFields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MetadataField" + }, + "description": "Gets or sets the locked fields.", + "nullable": true + }, + "TrailerCount": { + "type": "integer", + "description": "Gets or sets the trailer count.", + "format": "int32", + "nullable": true + }, + "MovieCount": { + "type": "integer", + "description": "Gets or sets the movie count.", + "format": "int32", + "nullable": true + }, + "SeriesCount": { + "type": "integer", + "description": "Gets or sets the series count.", + "format": "int32", + "nullable": true + }, + "ProgramCount": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "EpisodeCount": { + "type": "integer", + "description": "Gets or sets the episode count.", + "format": "int32", + "nullable": true + }, + "SongCount": { + "type": "integer", + "description": "Gets or sets the song count.", + "format": "int32", + "nullable": true + }, + "AlbumCount": { + "type": "integer", + "description": "Gets or sets the album count.", + "format": "int32", + "nullable": true + }, + "ArtistCount": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "MusicVideoCount": { + "type": "integer", + "description": "Gets or sets the music video count.", + "format": "int32", + "nullable": true + }, + "LockData": { + "type": "boolean", + "description": "Gets or sets a value indicating whether [enable internet providers].", + "nullable": true + }, + "Width": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "Height": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "CameraMake": { + "type": "string", + "nullable": true + }, + "CameraModel": { + "type": "string", + "nullable": true + }, + "Software": { + "type": "string", + "nullable": true + }, + "ExposureTime": { + "type": "number", + "format": "double", + "nullable": true + }, + "FocalLength": { + "type": "number", + "format": "double", + "nullable": true + }, + "ImageOrientation": { + "enum": [ + "TopLeft", + "TopRight", + "BottomRight", + "BottomLeft", + "LeftTop", + "RightTop", + "RightBottom", + "LeftBottom" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageOrientation" + } + ], + "nullable": true + }, + "Aperture": { + "type": "number", + "format": "double", + "nullable": true + }, + "ShutterSpeed": { + "type": "number", + "format": "double", + "nullable": true + }, + "Latitude": { + "type": "number", + "format": "double", + "nullable": true + }, + "Longitude": { + "type": "number", + "format": "double", + "nullable": true + }, + "Altitude": { + "type": "number", + "format": "double", + "nullable": true + }, + "IsoSpeedRating": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "SeriesTimerId": { + "type": "string", + "description": "Gets or sets the series timer identifier.", + "nullable": true + }, + "ProgramId": { + "type": "string", + "description": "Gets or sets the program identifier.", + "nullable": true + }, + "ChannelPrimaryImageTag": { + "type": "string", + "description": "Gets or sets the channel primary image tag.", + "nullable": true + }, + "StartDate": { + "type": "string", + "description": "Gets or sets the start date of the recording, in UTC.", + "format": "date-time", + "nullable": true + }, + "CompletionPercentage": { + "type": "number", + "description": "Gets or sets the completion percentage.", + "format": "double", + "nullable": true + }, + "IsRepeat": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is repeat.", + "nullable": true + }, + "EpisodeTitle": { + "type": "string", + "description": "Gets or sets the episode title.", + "nullable": true + }, + "ChannelType": { + "enum": ["TV", "Radio"], + "allOf": [ + { + "$ref": "#/components/schemas/ChannelType" + } + ], + "description": "Gets or sets the type of the channel.", + "nullable": true + }, + "Audio": { + "enum": ["Mono", "Stereo", "Dolby", "DolbyDigital", "Thx", "Atmos"], + "allOf": [ + { + "$ref": "#/components/schemas/ProgramAudio" + } + ], + "description": "Gets or sets the audio.", + "nullable": true + }, + "IsMovie": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is movie.", + "nullable": true + }, + "IsSports": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is sports.", + "nullable": true + }, + "IsSeries": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is series.", + "nullable": true + }, + "IsLive": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is live.", + "nullable": true + }, + "IsNews": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is news.", + "nullable": true + }, + "IsKids": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is kids.", + "nullable": true + }, + "IsPremiere": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is premiere.", + "nullable": true + }, + "TimerId": { + "type": "string", + "description": "Gets or sets the timer identifier.", + "nullable": true + }, + "NormalizationGain": { + "type": "number", + "description": "Gets or sets the gain required for audio normalization.", + "format": "float", + "nullable": true + }, + "CurrentProgram": { + "allOf": [ + { + "$ref": "#/components/schemas/BaseItemDto" + } + ], + "description": "Gets or sets the current program.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "This is strictly used as a data transfer object from the api layer.\r\nThis holds information about a BaseItem in a format that is convenient for the client." + }, + "BaseItemDtoQueryResult": { + "type": "object", + "properties": { + "Items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemDto" + }, + "description": "Gets or sets the items.", + "nullable": true + }, + "TotalRecordCount": { + "type": "integer", + "description": "Gets or sets the total number of records available.", + "format": "int32" + }, + "StartIndex": { + "type": "integer", + "description": "Gets or sets the index of the first record in Items.", + "format": "int32" + } + }, + "additionalProperties": false + }, + "BaseItemKind": { + "enum": [ + "AggregateFolder", + "Audio", + "AudioBook", + "BasePluginFolder", + "Book", + "BoxSet", + "Channel", + "ChannelFolderItem", + "CollectionFolder", + "Episode", + "Folder", + "Genre", + "ManualPlaylistsFolder", + "Movie", + "LiveTvChannel", + "LiveTvProgram", + "MusicAlbum", + "MusicArtist", + "MusicGenre", + "MusicVideo", + "Person", + "Photo", + "PhotoAlbum", + "Playlist", + "PlaylistsFolder", + "Program", + "Recording", + "Season", + "Series", + "Studio", + "Trailer", + "TvChannel", + "TvProgram", + "UserRootFolder", + "UserView", + "Video", + "Year" + ], + "type": "string", + "description": "The base item kind." + }, + "BaseItemPerson": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + }, + "Id": { + "type": "string", + "description": "Gets or sets the identifier.", + "format": "uuid" + }, + "Role": { + "type": "string", + "description": "Gets or sets the role.", + "nullable": true + }, + "Type": { + "enum": [ + "Unknown", + "Actor", + "Director", + "Composer", + "Writer", + "GuestStar", + "Producer", + "Conductor", + "Lyricist", + "Arranger", + "Engineer", + "Mixer", + "Remixer", + "Creator", + "Artist", + "AlbumArtist", + "Author", + "Illustrator", + "Penciller", + "Inker", + "Colorist", + "Letterer", + "CoverArtist", + "Editor", + "Translator" + ], + "allOf": [ + { + "$ref": "#/components/schemas/PersonKind" + } + ], + "description": "The person kind." + }, + "PrimaryImageTag": { + "type": "string", + "description": "Gets or sets the primary image tag.", + "nullable": true + }, + "ImageBlurHashes": { + "type": "object", + "properties": { + "Primary": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Art": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Backdrop": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Banner": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Logo": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Thumb": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Disc": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Box": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Screenshot": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Menu": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Chapter": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "BoxRear": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Profile": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "description": "Gets or sets the primary image blurhash.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "This is used by the api to get information about a Person within a BaseItem." + }, + "BasePluginConfiguration": { + "type": "object", + "additionalProperties": false, + "description": "Class BasePluginConfiguration." + }, + "BookInfo": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + }, + "OriginalTitle": { + "type": "string", + "description": "Gets or sets the original title.", + "nullable": true + }, + "Path": { + "type": "string", + "description": "Gets or sets the path.", + "nullable": true + }, + "MetadataLanguage": { + "type": "string", + "description": "Gets or sets the metadata language.", + "nullable": true + }, + "MetadataCountryCode": { + "type": "string", + "description": "Gets or sets the metadata country code.", + "nullable": true + }, + "ProviderIds": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "description": "Gets or sets the provider ids.", + "nullable": true + }, + "Year": { + "type": "integer", + "description": "Gets or sets the year.", + "format": "int32", + "nullable": true + }, + "IndexNumber": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "ParentIndexNumber": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "PremiereDate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "IsAutomated": { + "type": "boolean" + }, + "SeriesName": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "BookInfoRemoteSearchQuery": { + "type": "object", + "properties": { + "SearchInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/BookInfo" + } + ], + "nullable": true + }, + "ItemId": { + "type": "string", + "format": "uuid" + }, + "SearchProviderName": { + "type": "string", + "description": "Gets or sets the provider name to search within if set.", + "nullable": true + }, + "IncludeDisabledProviders": { + "type": "boolean", + "description": "Gets or sets a value indicating whether disabled providers should be included." + } + }, + "additionalProperties": false + }, + "BoxSetInfo": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + }, + "OriginalTitle": { + "type": "string", + "description": "Gets or sets the original title.", + "nullable": true + }, + "Path": { + "type": "string", + "description": "Gets or sets the path.", + "nullable": true + }, + "MetadataLanguage": { + "type": "string", + "description": "Gets or sets the metadata language.", + "nullable": true + }, + "MetadataCountryCode": { + "type": "string", + "description": "Gets or sets the metadata country code.", + "nullable": true + }, + "ProviderIds": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "description": "Gets or sets the provider ids.", + "nullable": true + }, + "Year": { + "type": "integer", + "description": "Gets or sets the year.", + "format": "int32", + "nullable": true + }, + "IndexNumber": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "ParentIndexNumber": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "PremiereDate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "IsAutomated": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "BoxSetInfoRemoteSearchQuery": { + "type": "object", + "properties": { + "SearchInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/BoxSetInfo" + } + ], + "nullable": true + }, + "ItemId": { + "type": "string", + "format": "uuid" + }, + "SearchProviderName": { + "type": "string", + "description": "Gets or sets the provider name to search within if set.", + "nullable": true + }, + "IncludeDisabledProviders": { + "type": "boolean", + "description": "Gets or sets a value indicating whether disabled providers should be included." + } + }, + "additionalProperties": false + }, + "BrandingOptions": { + "type": "object", + "properties": { + "LoginDisclaimer": { + "type": "string", + "description": "Gets or sets the login disclaimer.", + "nullable": true + }, + "CustomCss": { + "type": "string", + "description": "Gets or sets the custom CSS.", + "nullable": true + }, + "SplashscreenEnabled": { + "type": "boolean", + "description": "Gets or sets a value indicating whether to enable the splashscreen." + } + }, + "additionalProperties": false, + "description": "The branding options." + }, + "BufferRequestDto": { + "type": "object", + "properties": { + "When": { + "type": "string", + "description": "Gets or sets when the request has been made by the client.", + "format": "date-time" + }, + "PositionTicks": { + "type": "integer", + "description": "Gets or sets the position ticks.", + "format": "int64" + }, + "IsPlaying": { + "type": "boolean", + "description": "Gets or sets a value indicating whether the client playback is unpaused." + }, + "PlaylistItemId": { + "type": "string", + "description": "Gets or sets the playlist item identifier of the playing item.", + "format": "uuid" + } + }, + "additionalProperties": false, + "description": "Class BufferRequestDto." + }, + "CastReceiverApplication": { + "type": "object", + "properties": { + "Id": { + "type": "string", + "description": "Gets or sets the cast receiver application id." + }, + "Name": { + "type": "string", + "description": "Gets or sets the cast receiver application name." + } + }, + "additionalProperties": false, + "description": "The cast receiver application model." + }, + "ChannelFeatures": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name." + }, + "Id": { + "type": "string", + "description": "Gets or sets the identifier.", + "format": "uuid" + }, + "CanSearch": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance can search." + }, + "MediaTypes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ChannelMediaType" + }, + "description": "Gets or sets the media types." + }, + "ContentTypes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ChannelMediaContentType" + }, + "description": "Gets or sets the content types." + }, + "MaxPageSize": { + "type": "integer", + "description": "Gets or sets the maximum number of records the channel allows retrieving at a time.", + "format": "int32", + "nullable": true + }, + "AutoRefreshLevels": { + "type": "integer", + "description": "Gets or sets the automatic refresh levels.", + "format": "int32", + "nullable": true + }, + "DefaultSortFields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ChannelItemSortField" + }, + "description": "Gets or sets the default sort orders." + }, + "SupportsSortOrderToggle": { + "type": "boolean", + "description": "Gets or sets a value indicating whether a sort ascending/descending toggle is supported." + }, + "SupportsLatestMedia": { + "type": "boolean", + "description": "Gets or sets a value indicating whether [supports latest media]." + }, + "CanFilter": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance can filter." + }, + "SupportsContentDownloading": { + "type": "boolean", + "description": "Gets or sets a value indicating whether [supports content downloading]." + } + }, + "additionalProperties": false + }, + "ChannelItemSortField": { + "enum": [ + "Name", + "CommunityRating", + "PremiereDate", + "DateCreated", + "Runtime", + "PlayCount", + "CommunityPlayCount" + ], + "type": "string" + }, + "ChannelMappingOptionsDto": { + "type": "object", + "properties": { + "TunerChannels": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TunerChannelMapping" + }, + "description": "Gets or sets list of tuner channels." + }, + "ProviderChannels": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NameIdPair" + }, + "description": "Gets or sets list of provider channels." + }, + "Mappings": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NameValuePair" + }, + "description": "Gets or sets list of mappings." + }, + "ProviderName": { + "type": "string", + "description": "Gets or sets provider name.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Channel mapping options dto." + }, + "ChannelMediaContentType": { + "enum": [ + "Clip", + "Podcast", + "Trailer", + "Movie", + "Episode", + "Song", + "MovieExtra", + "TvExtra" + ], + "type": "string" + }, + "ChannelMediaType": { + "enum": ["Audio", "Video", "Photo"], + "type": "string" + }, + "ChannelType": { + "enum": ["TV", "Radio"], + "type": "string", + "description": "Enum ChannelType." + }, + "ChapterInfo": { + "type": "object", + "properties": { + "StartPositionTicks": { + "type": "integer", + "description": "Gets or sets the start position ticks.", + "format": "int64" + }, + "Name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + }, + "ImagePath": { + "type": "string", + "description": "Gets or sets the image path.", + "nullable": true + }, + "ImageDateModified": { + "type": "string", + "format": "date-time" + }, + "ImageTag": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class ChapterInfo." + }, + "ClientCapabilities": { + "type": "object", + "properties": { + "PlayableMediaTypes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MediaType" + }, + "nullable": true + }, + "SupportedCommands": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GeneralCommandType" + }, + "nullable": true + }, + "SupportsMediaControl": { + "type": "boolean" + }, + "SupportsPersistentIdentifier": { + "type": "boolean" + }, + "DeviceProfile": { + "allOf": [ + { + "$ref": "#/components/schemas/DeviceProfile" + } + ], + "description": "A MediaBrowser.Model.Dlna.DeviceProfile represents a set of metadata which determines which content a certain device is able to play.\r\n
\r\nSpecifically, it defines the supported containers and\r\ncodecs (video and/or audio, including codec profiles and levels)\r\nthe device is able to direct play (without transcoding or remuxing),\r\nas well as which containers/codecs to transcode to in case it isn't.", + "nullable": true + }, + "AppStoreUrl": { + "type": "string", + "nullable": true + }, + "IconUrl": { + "type": "string", + "nullable": true + }, + "SupportsContentUploading": { + "type": "boolean", + "default": false, + "nullable": true, + "deprecated": true + }, + "SupportsSync": { + "type": "boolean", + "default": false, + "nullable": true, + "deprecated": true + } + }, + "additionalProperties": false + }, + "ClientCapabilitiesDto": { + "type": "object", + "properties": { + "PlayableMediaTypes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MediaType" + }, + "description": "Gets or sets the list of playable media types." + }, + "SupportedCommands": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GeneralCommandType" + }, + "description": "Gets or sets the list of supported commands." + }, + "SupportsMediaControl": { + "type": "boolean", + "description": "Gets or sets a value indicating whether session supports media control." + }, + "SupportsPersistentIdentifier": { + "type": "boolean", + "description": "Gets or sets a value indicating whether session supports a persistent identifier." + }, + "DeviceProfile": { + "allOf": [ + { + "$ref": "#/components/schemas/DeviceProfile" + } + ], + "description": "Gets or sets the device profile.", + "nullable": true + }, + "AppStoreUrl": { + "type": "string", + "description": "Gets or sets the app store url.", + "nullable": true + }, + "IconUrl": { + "type": "string", + "description": "Gets or sets the icon url.", + "nullable": true + }, + "SupportsContentUploading": { + "type": "boolean", + "default": false, + "nullable": true, + "deprecated": true + }, + "SupportsSync": { + "type": "boolean", + "default": false, + "nullable": true, + "deprecated": true + } + }, + "additionalProperties": false, + "description": "Client capabilities dto." + }, + "ClientLogDocumentResponseDto": { + "type": "object", + "properties": { + "FileName": { + "type": "string", + "description": "Gets the resulting filename." + } + }, + "additionalProperties": false, + "description": "Client log document response dto." + }, + "CodecProfile": { + "type": "object", + "properties": { + "Type": { + "enum": ["Video", "VideoAudio", "Audio"], + "allOf": [ + { + "$ref": "#/components/schemas/CodecType" + } + ] + }, + "Conditions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProfileCondition" + }, + "nullable": true + }, + "ApplyConditions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProfileCondition" + }, + "nullable": true + }, + "Codec": { + "type": "string", + "nullable": true + }, + "Container": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "CodecType": { + "enum": ["Video", "VideoAudio", "Audio"], + "type": "string" + }, + "CollectionCreationResult": { + "type": "object", + "properties": { + "Id": { + "type": "string", + "format": "uuid" + } + }, + "additionalProperties": false + }, + "CollectionType": { + "enum": [ + "unknown", + "movies", + "tvshows", + "music", + "musicvideos", + "trailers", + "homevideos", + "boxsets", + "books", + "photos", + "livetv", + "playlists", + "folders" + ], + "type": "string", + "description": "Collection type." + }, + "CollectionTypeOptions": { + "enum": [ + "movies", + "tvshows", + "music", + "musicvideos", + "homevideos", + "boxsets", + "books", + "mixed" + ], + "type": "string", + "description": "The collection type options." + }, + "ConfigImageTypes": { + "type": "object", + "properties": { + "BackdropSizes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "BaseUrl": { + "type": "string", + "nullable": true + }, + "LogoSizes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "PosterSizes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "ProfileSizes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "SecureBaseUrl": { + "type": "string", + "nullable": true + }, + "StillSizes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "ConfigurationPageInfo": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name." + }, + "EnableInMainMenu": { + "type": "boolean", + "description": "Gets or sets a value indicating whether the configurations page is enabled in the main menu." + }, + "MenuSection": { + "type": "string", + "description": "Gets or sets the menu section.", + "nullable": true + }, + "MenuIcon": { + "type": "string", + "description": "Gets or sets the menu icon.", + "nullable": true + }, + "DisplayName": { + "type": "string", + "description": "Gets or sets the display name.", + "nullable": true + }, + "PluginId": { + "type": "string", + "description": "Gets or sets the plugin id.", + "format": "uuid", + "nullable": true + } + }, + "additionalProperties": false, + "description": "The configuration page info." + }, + "ContainerProfile": { + "type": "object", + "properties": { + "Type": { + "enum": ["Audio", "Video", "Photo", "Subtitle", "Lyric"], + "allOf": [ + { + "$ref": "#/components/schemas/DlnaProfileType" + } + ] + }, + "Conditions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProfileCondition" + } + }, + "Container": { + "type": "string" + } + }, + "additionalProperties": false + }, + "CountryInfo": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + }, + "DisplayName": { + "type": "string", + "description": "Gets or sets the display name.", + "nullable": true + }, + "TwoLetterISORegionName": { + "type": "string", + "description": "Gets or sets the name of the two letter ISO region.", + "nullable": true + }, + "ThreeLetterISORegionName": { + "type": "string", + "description": "Gets or sets the name of the three letter ISO region.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class CountryInfo." + }, + "CreatePlaylistDto": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name of the new playlist." + }, + "Ids": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "description": "Gets or sets item ids to add to the playlist." + }, + "UserId": { + "type": "string", + "description": "Gets or sets the user id.", + "format": "uuid", + "nullable": true + }, + "MediaType": { + "enum": ["Unknown", "Video", "Audio", "Photo", "Book"], + "allOf": [ + { + "$ref": "#/components/schemas/MediaType" + } + ], + "description": "Gets or sets the media type.", + "nullable": true + }, + "Users": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PlaylistUserPermissions" + }, + "description": "Gets or sets the playlist users." + }, + "IsPublic": { + "type": "boolean", + "description": "Gets or sets a value indicating whether the playlist is public." + } + }, + "additionalProperties": false, + "description": "Create new playlist dto." + }, + "CreateUserByName": { + "required": ["Name"], + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the username." + }, + "Password": { + "type": "string", + "description": "Gets or sets the password.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "The create user by name request body." + }, + "CultureDto": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets the name." + }, + "DisplayName": { + "type": "string", + "description": "Gets the display name." + }, + "TwoLetterISOLanguageName": { + "type": "string", + "description": "Gets the name of the two letter ISO language." + }, + "ThreeLetterISOLanguageName": { + "type": "string", + "description": "Gets the name of the three letter ISO language.", + "nullable": true, + "readOnly": true + }, + "ThreeLetterISOLanguageNames": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false, + "description": "Class CultureDto." + }, + "CustomQueryData": { + "type": "object", + "properties": { + "CustomQueryString": { + "type": "string" + }, + "ReplaceUserId": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "DayOfWeek": { + "enum": [ + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday" + ], + "type": "string" + }, + "DayPattern": { + "enum": ["Daily", "Weekdays", "Weekends"], + "type": "string" + }, + "DefaultDirectoryBrowserInfoDto": { + "type": "object", + "properties": { + "Path": { + "type": "string", + "description": "Gets or sets the path.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Default directory browser info." + }, + "DeviceInfo": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "nullable": true + }, + "CustomName": { + "type": "string", + "nullable": true + }, + "AccessToken": { + "type": "string", + "description": "Gets or sets the access token.", + "nullable": true + }, + "Id": { + "type": "string", + "description": "Gets or sets the identifier.", + "nullable": true + }, + "LastUserName": { + "type": "string", + "description": "Gets or sets the last name of the user.", + "nullable": true + }, + "AppName": { + "type": "string", + "description": "Gets or sets the name of the application.", + "nullable": true + }, + "AppVersion": { + "type": "string", + "description": "Gets or sets the application version.", + "nullable": true + }, + "LastUserId": { + "type": "string", + "description": "Gets or sets the last user identifier.", + "format": "uuid" + }, + "DateLastActivity": { + "type": "string", + "description": "Gets or sets the date last modified.", + "format": "date-time" + }, + "Capabilities": { + "allOf": [ + { + "$ref": "#/components/schemas/ClientCapabilities" + } + ], + "description": "Gets or sets the capabilities.", + "nullable": true + }, + "IconUrl": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "DeviceInfoQueryResult": { + "type": "object", + "properties": { + "Items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DeviceInfo" + }, + "description": "Gets or sets the items.", + "nullable": true + }, + "TotalRecordCount": { + "type": "integer", + "description": "Gets or sets the total number of records available.", + "format": "int32" + }, + "StartIndex": { + "type": "integer", + "description": "Gets or sets the index of the first record in Items.", + "format": "int32" + } + }, + "additionalProperties": false + }, + "DeviceOptions": { + "type": "object", + "properties": { + "Id": { + "type": "integer", + "description": "Gets the id.", + "format": "int32", + "readOnly": true + }, + "DeviceId": { + "type": "string", + "description": "Gets the device id." + }, + "CustomName": { + "type": "string", + "description": "Gets or sets the custom name.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "An entity representing custom options for a device." + }, + "DeviceOptionsDto": { + "type": "object", + "properties": { + "Id": { + "type": "integer", + "description": "Gets or sets the id.", + "format": "int32" + }, + "DeviceId": { + "type": "string", + "description": "Gets or sets the device id.", + "nullable": true + }, + "CustomName": { + "type": "string", + "description": "Gets or sets the custom name.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "A dto representing custom options for a device." + }, + "DeviceProfile": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name of this device profile.", + "nullable": true + }, + "Id": { + "type": "string", + "description": "Gets or sets the Id.", + "nullable": true + }, + "MaxStreamingBitrate": { + "type": "integer", + "description": "Gets or sets the maximum allowed bitrate for all streamed content.", + "format": "int32", + "nullable": true + }, + "MaxStaticBitrate": { + "type": "integer", + "description": "Gets or sets the maximum allowed bitrate for statically streamed content (= direct played files).", + "format": "int32", + "nullable": true + }, + "MusicStreamingTranscodingBitrate": { + "type": "integer", + "description": "Gets or sets the maximum allowed bitrate for transcoded music streams.", + "format": "int32", + "nullable": true + }, + "MaxStaticMusicBitrate": { + "type": "integer", + "description": "Gets or sets the maximum allowed bitrate for statically streamed (= direct played) music files.", + "format": "int32", + "nullable": true + }, + "DirectPlayProfiles": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DirectPlayProfile" + }, + "description": "Gets or sets the direct play profiles." + }, + "TranscodingProfiles": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TranscodingProfile" + }, + "description": "Gets or sets the transcoding profiles." + }, + "ContainerProfiles": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ContainerProfile" + }, + "description": "Gets or sets the container profiles." + }, + "CodecProfiles": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CodecProfile" + }, + "description": "Gets or sets the codec profiles." + }, + "SubtitleProfiles": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SubtitleProfile" + }, + "description": "Gets or sets the subtitle profiles." + } + }, + "additionalProperties": false, + "description": "A MediaBrowser.Model.Dlna.DeviceProfile represents a set of metadata which determines which content a certain device is able to play.\r\n
\r\nSpecifically, it defines the supported containers and\r\ncodecs (video and/or audio, including codec profiles and levels)\r\nthe device is able to direct play (without transcoding or remuxing),\r\nas well as which containers/codecs to transcode to in case it isn't." + }, + "DirectPlayProfile": { + "type": "object", + "properties": { + "Container": { + "type": "string", + "nullable": true + }, + "AudioCodec": { + "type": "string", + "nullable": true + }, + "VideoCodec": { + "type": "string", + "nullable": true + }, + "Type": { + "enum": ["Audio", "Video", "Photo", "Subtitle", "Lyric"], + "allOf": [ + { + "$ref": "#/components/schemas/DlnaProfileType" + } + ] + } + }, + "additionalProperties": false + }, + "DisplayPreferencesDto": { + "type": "object", + "properties": { + "Id": { + "type": "string", + "description": "Gets or sets the user id.", + "nullable": true + }, + "ViewType": { + "type": "string", + "description": "Gets or sets the type of the view.", + "nullable": true + }, + "SortBy": { + "type": "string", + "description": "Gets or sets the sort by.", + "nullable": true + }, + "IndexBy": { + "type": "string", + "description": "Gets or sets the index by.", + "nullable": true + }, + "RememberIndexing": { + "type": "boolean", + "description": "Gets or sets a value indicating whether [remember indexing]." + }, + "PrimaryImageHeight": { + "type": "integer", + "description": "Gets or sets the height of the primary image.", + "format": "int32" + }, + "PrimaryImageWidth": { + "type": "integer", + "description": "Gets or sets the width of the primary image.", + "format": "int32" + }, + "CustomPrefs": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "description": "Gets or sets the custom prefs." + }, + "ScrollDirection": { + "enum": ["Horizontal", "Vertical"], + "allOf": [ + { + "$ref": "#/components/schemas/ScrollDirection" + } + ], + "description": "An enum representing the axis that should be scrolled." + }, + "ShowBackdrop": { + "type": "boolean", + "description": "Gets or sets a value indicating whether to show backdrops on this item." + }, + "RememberSorting": { + "type": "boolean", + "description": "Gets or sets a value indicating whether [remember sorting]." + }, + "SortOrder": { + "enum": ["Ascending", "Descending"], + "allOf": [ + { + "$ref": "#/components/schemas/SortOrder" + } + ], + "description": "An enum representing the sorting order." + }, + "ShowSidebar": { + "type": "boolean", + "description": "Gets or sets a value indicating whether [show sidebar]." + }, + "Client": { + "type": "string", + "description": "Gets or sets the client.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Defines the display preferences for any item that supports them (usually Folders)." + }, + "DlnaProfileType": { + "enum": ["Audio", "Video", "Photo", "Subtitle", "Lyric"], + "type": "string" + }, + "DownMixStereoAlgorithms": { + "enum": ["None", "Dave750", "NightmodeDialogue"], + "type": "string", + "description": "An enum representing an algorithm to downmix 6ch+ to stereo.\r\nAlgorithms sourced from https://superuser.com/questions/852400/properly-downmix-5-1-to-stereo-using-ffmpeg/1410620#1410620." + }, + "DynamicDayOfWeek": { + "enum": [ + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", + "Everyday", + "Weekday", + "Weekend" + ], + "type": "string", + "description": "An enum that represents a day of the week, weekdays, weekends, or all days." + }, + "EmbeddedSubtitleOptions": { + "enum": ["AllowAll", "AllowText", "AllowImage", "AllowNone"], + "type": "string", + "description": "An enum representing the options to disable embedded subs." + }, + "EncodingContext": { + "enum": ["Streaming", "Static"], + "type": "string" + }, + "EncodingOptions": { + "type": "object", + "properties": { + "EncodingThreadCount": { + "type": "integer", + "description": "Gets or sets the thread count used for encoding.", + "format": "int32" + }, + "TranscodingTempPath": { + "type": "string", + "description": "Gets or sets the temporary transcoding path.", + "nullable": true + }, + "FallbackFontPath": { + "type": "string", + "description": "Gets or sets the path to the fallback font.", + "nullable": true + }, + "EnableFallbackFont": { + "type": "boolean", + "description": "Gets or sets a value indicating whether to use the fallback font." + }, + "EnableAudioVbr": { + "type": "boolean", + "description": "Gets or sets a value indicating whether audio VBR is enabled." + }, + "DownMixAudioBoost": { + "type": "number", + "description": "Gets or sets the audio boost applied when downmixing audio.", + "format": "double" + }, + "DownMixStereoAlgorithm": { + "enum": ["None", "Dave750", "NightmodeDialogue"], + "allOf": [ + { + "$ref": "#/components/schemas/DownMixStereoAlgorithms" + } + ], + "description": "Gets or sets the algorithm used for downmixing audio to stereo." + }, + "MaxMuxingQueueSize": { + "type": "integer", + "description": "Gets or sets the maximum size of the muxing queue.", + "format": "int32" + }, + "EnableThrottling": { + "type": "boolean", + "description": "Gets or sets a value indicating whether throttling is enabled." + }, + "ThrottleDelaySeconds": { + "type": "integer", + "description": "Gets or sets the delay after which throttling happens.", + "format": "int32" + }, + "EnableSegmentDeletion": { + "type": "boolean", + "description": "Gets or sets a value indicating whether segment deletion is enabled." + }, + "SegmentKeepSeconds": { + "type": "integer", + "description": "Gets or sets seconds for which segments should be kept before being deleted.", + "format": "int32" + }, + "HardwareAccelerationType": { + "type": "string", + "description": "Gets or sets the hardware acceleration type.", + "nullable": true + }, + "EncoderAppPath": { + "type": "string", + "description": "Gets or sets the FFmpeg path as set by the user via the UI.", + "nullable": true + }, + "EncoderAppPathDisplay": { + "type": "string", + "description": "Gets or sets the current FFmpeg path being used by the system and displayed on the transcode page.", + "nullable": true + }, + "VaapiDevice": { + "type": "string", + "description": "Gets or sets the VA-API device.", + "nullable": true + }, + "EnableTonemapping": { + "type": "boolean", + "description": "Gets or sets a value indicating whether tonemapping is enabled." + }, + "EnableVppTonemapping": { + "type": "boolean", + "description": "Gets or sets a value indicating whether VPP tonemapping is enabled." + }, + "EnableVideoToolboxTonemapping": { + "type": "boolean", + "description": "Gets or sets a value indicating whether videotoolbox tonemapping is enabled." + }, + "TonemappingAlgorithm": { + "type": "string", + "description": "Gets or sets the tone-mapping algorithm.", + "nullable": true + }, + "TonemappingMode": { + "type": "string", + "description": "Gets or sets the tone-mapping mode.", + "nullable": true + }, + "TonemappingRange": { + "type": "string", + "description": "Gets or sets the tone-mapping range.", + "nullable": true + }, + "TonemappingDesat": { + "type": "number", + "description": "Gets or sets the tone-mapping desaturation.", + "format": "double" + }, + "TonemappingPeak": { + "type": "number", + "description": "Gets or sets the tone-mapping peak.", + "format": "double" + }, + "TonemappingParam": { + "type": "number", + "description": "Gets or sets the tone-mapping parameters.", + "format": "double" + }, + "VppTonemappingBrightness": { + "type": "number", + "description": "Gets or sets the VPP tone-mapping brightness.", + "format": "double" + }, + "VppTonemappingContrast": { + "type": "number", + "description": "Gets or sets the VPP tone-mapping contrast.", + "format": "double" + }, + "H264Crf": { + "type": "integer", + "description": "Gets or sets the H264 CRF.", + "format": "int32" + }, + "H265Crf": { + "type": "integer", + "description": "Gets or sets the H265 CRF.", + "format": "int32" + }, + "EncoderPreset": { + "type": "string", + "description": "Gets or sets the encoder preset.", + "nullable": true + }, + "DeinterlaceDoubleRate": { + "type": "boolean", + "description": "Gets or sets a value indicating whether the framerate is doubled when deinterlacing." + }, + "DeinterlaceMethod": { + "type": "string", + "description": "Gets or sets the deinterlace method.", + "nullable": true + }, + "EnableDecodingColorDepth10Hevc": { + "type": "boolean", + "description": "Gets or sets a value indicating whether 10bit HEVC decoding is enabled." + }, + "EnableDecodingColorDepth10Vp9": { + "type": "boolean", + "description": "Gets or sets a value indicating whether 10bit VP9 decoding is enabled." + }, + "EnableEnhancedNvdecDecoder": { + "type": "boolean", + "description": "Gets or sets a value indicating whether the enhanced NVDEC is enabled." + }, + "PreferSystemNativeHwDecoder": { + "type": "boolean", + "description": "Gets or sets a value indicating whether the system native hardware decoder should be used." + }, + "EnableIntelLowPowerH264HwEncoder": { + "type": "boolean", + "description": "Gets or sets a value indicating whether the Intel H264 low-power hardware encoder should be used." + }, + "EnableIntelLowPowerHevcHwEncoder": { + "type": "boolean", + "description": "Gets or sets a value indicating whether the Intel HEVC low-power hardware encoder should be used." + }, + "EnableHardwareEncoding": { + "type": "boolean", + "description": "Gets or sets a value indicating whether hardware encoding is enabled." + }, + "AllowHevcEncoding": { + "type": "boolean", + "description": "Gets or sets a value indicating whether HEVC encoding is enabled." + }, + "AllowAv1Encoding": { + "type": "boolean", + "description": "Gets or sets a value indicating whether AV1 encoding is enabled." + }, + "EnableSubtitleExtraction": { + "type": "boolean", + "description": "Gets or sets a value indicating whether subtitle extraction is enabled." + }, + "HardwareDecodingCodecs": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the codecs hardware encoding is used for.", + "nullable": true + }, + "AllowOnDemandMetadataBasedKeyframeExtractionForExtensions": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the file extensions on-demand metadata based keyframe extraction is enabled for.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class EncodingOptions." + }, + "EndPointInfo": { + "type": "object", + "properties": { + "IsLocal": { + "type": "boolean" + }, + "IsInNetwork": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "EpisodeVisualization": { + "type": "object", + "properties": { + "Id": { + "type": "string", + "format": "uuid" + }, + "Name": { + "type": "string" + } + }, + "additionalProperties": false + }, + "ExternalIdInfo": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the display name of the external id provider (IE: IMDB, MusicBrainz, etc)." + }, + "Key": { + "type": "string", + "description": "Gets or sets the unique key for this id. This key should be unique across all providers." + }, + "Type": { + "enum": [ + "Album", + "AlbumArtist", + "Artist", + "BoxSet", + "Episode", + "Movie", + "OtherArtist", + "Person", + "ReleaseGroup", + "Season", + "Series", + "Track", + "Book" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ExternalIdMediaType" + } + ], + "description": "Gets or sets the specific media type for this id. This is used to distinguish between the different\r\nexternal id types for providers with multiple ids.\r\nA null value indicates there is no specific media type associated with the external id, or this is the\r\ndefault id for the external provider so there is no need to specify a type.", + "nullable": true + }, + "UrlFormatString": { + "type": "string", + "description": "Gets or sets the URL format string.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Represents the external id information for serialization to the client." + }, + "ExternalIdMediaType": { + "enum": [ + "Album", + "AlbumArtist", + "Artist", + "BoxSet", + "Episode", + "Movie", + "OtherArtist", + "Person", + "ReleaseGroup", + "Season", + "Series", + "Track", + "Book" + ], + "type": "string", + "description": "The specific media type of an MediaBrowser.Model.Providers.ExternalIdInfo." + }, + "ExternalUrl": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + }, + "Url": { + "type": "string", + "description": "Gets or sets the type of the item.", + "nullable": true + } + }, + "additionalProperties": false + }, + "ExtraType": { + "enum": [ + "Unknown", + "Clip", + "Trailer", + "BehindTheScenes", + "DeletedScene", + "Interview", + "Scene", + "Sample", + "ThemeSong", + "ThemeVideo", + "Featurette", + "Short" + ], + "type": "string" + }, + "FileSystemEntryInfo": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets the name." + }, + "Path": { + "type": "string", + "description": "Gets the path." + }, + "Type": { + "enum": ["File", "Directory", "NetworkComputer", "NetworkShare"], + "allOf": [ + { + "$ref": "#/components/schemas/FileSystemEntryType" + } + ], + "description": "Gets the type." + } + }, + "additionalProperties": false, + "description": "Class FileSystemEntryInfo." + }, + "FileSystemEntryType": { + "enum": ["File", "Directory", "NetworkComputer", "NetworkShare"], + "type": "string", + "description": "Enum FileSystemEntryType." + }, + "FontFile": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + }, + "Size": { + "type": "integer", + "description": "Gets or sets the size.", + "format": "int64" + }, + "DateCreated": { + "type": "string", + "description": "Gets or sets the date created.", + "format": "date-time" + }, + "DateModified": { + "type": "string", + "description": "Gets or sets the date modified.", + "format": "date-time" + } + }, + "additionalProperties": false, + "description": "Class FontFile." + }, + "ForceKeepAliveMessage": { + "type": "object", + "properties": { + "Data": { + "type": "integer", + "description": "Gets or sets the data.", + "format": "int32" + }, + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "ForceKeepAlive", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Force keep alive websocket messages." + }, + "ForgotPasswordAction": { + "enum": ["ContactAdmin", "PinCode", "InNetworkRequired"], + "type": "string" + }, + "ForgotPasswordDto": { + "required": ["EnteredUsername"], + "type": "object", + "properties": { + "EnteredUsername": { + "type": "string", + "description": "Gets or sets the entered username to have its password reset." + } + }, + "additionalProperties": false, + "description": "Forgot Password request body DTO." + }, + "ForgotPasswordPinDto": { + "required": ["Pin"], + "type": "object", + "properties": { + "Pin": { + "type": "string", + "description": "Gets or sets the entered pin to have the password reset." + } + }, + "additionalProperties": false, + "description": "Forgot Password Pin enter request body DTO." + }, + "ForgotPasswordResult": { + "type": "object", + "properties": { + "Action": { + "enum": ["ContactAdmin", "PinCode", "InNetworkRequired"], + "allOf": [ + { + "$ref": "#/components/schemas/ForgotPasswordAction" + } + ], + "description": "Gets or sets the action." + }, + "PinFile": { + "type": "string", + "description": "Gets or sets the pin file.", + "nullable": true + }, + "PinExpirationDate": { + "type": "string", + "description": "Gets or sets the pin expiration date.", + "format": "date-time", + "nullable": true + } + }, + "additionalProperties": false + }, + "GeneralCommand": { + "type": "object", + "properties": { + "Name": { + "enum": [ + "MoveUp", + "MoveDown", + "MoveLeft", + "MoveRight", + "PageUp", + "PageDown", + "PreviousLetter", + "NextLetter", + "ToggleOsd", + "ToggleContextMenu", + "Select", + "Back", + "TakeScreenshot", + "SendKey", + "SendString", + "GoHome", + "GoToSettings", + "VolumeUp", + "VolumeDown", + "Mute", + "Unmute", + "ToggleMute", + "SetVolume", + "SetAudioStreamIndex", + "SetSubtitleStreamIndex", + "ToggleFullscreen", + "DisplayContent", + "GoToSearch", + "DisplayMessage", + "SetRepeatMode", + "ChannelUp", + "ChannelDown", + "Guide", + "ToggleStats", + "PlayMediaSource", + "PlayTrailers", + "SetShuffleQueue", + "PlayState", + "PlayNext", + "ToggleOsdMenu", + "Play", + "SetMaxStreamingBitrate", + "SetPlaybackOrder" + ], + "allOf": [ + { + "$ref": "#/components/schemas/GeneralCommandType" + } + ], + "description": "This exists simply to identify a set of known commands." + }, + "ControllingUserId": { + "type": "string", + "format": "uuid" + }, + "Arguments": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + } + } + }, + "additionalProperties": false + }, + "GeneralCommandMessage": { + "type": "object", + "properties": { + "Data": { + "allOf": [ + { + "$ref": "#/components/schemas/GeneralCommand" + } + ], + "description": "Gets or sets the data.", + "nullable": true + }, + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "GeneralCommand", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "General command websocket message." + }, + "GeneralCommandType": { + "enum": [ + "MoveUp", + "MoveDown", + "MoveLeft", + "MoveRight", + "PageUp", + "PageDown", + "PreviousLetter", + "NextLetter", + "ToggleOsd", + "ToggleContextMenu", + "Select", + "Back", + "TakeScreenshot", + "SendKey", + "SendString", + "GoHome", + "GoToSettings", + "VolumeUp", + "VolumeDown", + "Mute", + "Unmute", + "ToggleMute", + "SetVolume", + "SetAudioStreamIndex", + "SetSubtitleStreamIndex", + "ToggleFullscreen", + "DisplayContent", + "GoToSearch", + "DisplayMessage", + "SetRepeatMode", + "ChannelUp", + "ChannelDown", + "Guide", + "ToggleStats", + "PlayMediaSource", + "PlayTrailers", + "SetShuffleQueue", + "PlayState", + "PlayNext", + "ToggleOsdMenu", + "Play", + "SetMaxStreamingBitrate", + "SetPlaybackOrder" + ], + "type": "string", + "description": "This exists simply to identify a set of known commands." + }, + "GetProgramsDto": { + "type": "object", + "properties": { + "ChannelIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "description": "Gets or sets the channels to return guide information for." + }, + "UserId": { + "type": "string", + "description": "Gets or sets optional. Filter by user id.", + "format": "uuid", + "nullable": true + }, + "MinStartDate": { + "type": "string", + "description": "Gets or sets the minimum premiere start date.\r\nOptional.", + "format": "date-time", + "nullable": true + }, + "HasAired": { + "type": "boolean", + "description": "Gets or sets filter by programs that have completed airing, or not.\r\nOptional.", + "nullable": true + }, + "IsAiring": { + "type": "boolean", + "description": "Gets or sets filter by programs that are currently airing, or not.\r\nOptional.", + "nullable": true + }, + "MaxStartDate": { + "type": "string", + "description": "Gets or sets the maximum premiere start date.\r\nOptional.", + "format": "date-time", + "nullable": true + }, + "MinEndDate": { + "type": "string", + "description": "Gets or sets the minimum premiere end date.\r\nOptional.", + "format": "date-time", + "nullable": true + }, + "MaxEndDate": { + "type": "string", + "description": "Gets or sets the maximum premiere end date.\r\nOptional.", + "format": "date-time", + "nullable": true + }, + "IsMovie": { + "type": "boolean", + "description": "Gets or sets filter for movies.\r\nOptional.", + "nullable": true + }, + "IsSeries": { + "type": "boolean", + "description": "Gets or sets filter for series.\r\nOptional.", + "nullable": true + }, + "IsNews": { + "type": "boolean", + "description": "Gets or sets filter for news.\r\nOptional.", + "nullable": true + }, + "IsKids": { + "type": "boolean", + "description": "Gets or sets filter for kids.\r\nOptional.", + "nullable": true + }, + "IsSports": { + "type": "boolean", + "description": "Gets or sets filter for sports.\r\nOptional.", + "nullable": true + }, + "StartIndex": { + "type": "integer", + "description": "Gets or sets the record index to start at. All items with a lower index will be dropped from the results.\r\nOptional.", + "format": "int32", + "nullable": true + }, + "Limit": { + "type": "integer", + "description": "Gets or sets the maximum number of records to return.\r\nOptional.", + "format": "int32", + "nullable": true + }, + "SortBy": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemSortBy" + }, + "description": "Gets or sets specify one or more sort orders, comma delimited. Options: Name, StartDate.\r\nOptional." + }, + "SortOrder": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SortOrder" + }, + "description": "Gets or sets sort Order - Ascending,Descending." + }, + "Genres": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the genres to return guide information for." + }, + "GenreIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "description": "Gets or sets the genre ids to return guide information for." + }, + "EnableImages": { + "type": "boolean", + "description": "Gets or sets include image information in output.\r\nOptional.", + "nullable": true + }, + "EnableTotalRecordCount": { + "type": "boolean", + "description": "Gets or sets a value indicating whether retrieve total record count." + }, + "ImageTypeLimit": { + "type": "integer", + "description": "Gets or sets the max number of images to return, per image type.\r\nOptional.", + "format": "int32", + "nullable": true + }, + "EnableImageTypes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + }, + "description": "Gets or sets the image types to include in the output.\r\nOptional." + }, + "EnableUserData": { + "type": "boolean", + "description": "Gets or sets include user data.\r\nOptional.", + "nullable": true + }, + "SeriesTimerId": { + "type": "string", + "description": "Gets or sets filter by series timer id.\r\nOptional.", + "nullable": true + }, + "LibrarySeriesId": { + "type": "string", + "description": "Gets or sets filter by library series id.\r\nOptional.", + "format": "uuid" + }, + "Fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFields" + }, + "description": "Gets or sets specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines.\r\nOptional." + } + }, + "additionalProperties": false, + "description": "Get programs dto." + }, + "GroupInfoDto": { + "type": "object", + "properties": { + "GroupId": { + "type": "string", + "description": "Gets the group identifier.", + "format": "uuid" + }, + "GroupName": { + "type": "string", + "description": "Gets the group name." + }, + "State": { + "enum": ["Idle", "Waiting", "Paused", "Playing"], + "allOf": [ + { + "$ref": "#/components/schemas/GroupStateType" + } + ], + "description": "Gets the group state." + }, + "Participants": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets the participants." + }, + "LastUpdatedAt": { + "type": "string", + "description": "Gets the date when this DTO has been created.", + "format": "date-time" + } + }, + "additionalProperties": false, + "description": "Class GroupInfoDto." + }, + "GroupInfoDtoGroupUpdate": { + "type": "object", + "properties": { + "GroupId": { + "type": "string", + "description": "Gets the group identifier.", + "format": "uuid", + "readOnly": true + }, + "Type": { + "enum": [ + "UserJoined", + "UserLeft", + "GroupJoined", + "GroupLeft", + "StateUpdate", + "PlayQueue", + "NotInGroup", + "GroupDoesNotExist", + "CreateGroupDenied", + "JoinGroupDenied", + "LibraryAccessDenied" + ], + "allOf": [ + { + "$ref": "#/components/schemas/GroupUpdateType" + } + ], + "description": "Gets the update type." + }, + "Data": { + "allOf": [ + { + "$ref": "#/components/schemas/GroupInfoDto" + } + ], + "description": "Gets the update data." + } + }, + "additionalProperties": false, + "description": "Class GroupUpdate." + }, + "GroupQueueMode": { + "enum": ["Queue", "QueueNext"], + "type": "string", + "description": "Enum GroupQueueMode." + }, + "GroupRepeatMode": { + "enum": ["RepeatOne", "RepeatAll", "RepeatNone"], + "type": "string", + "description": "Enum GroupRepeatMode." + }, + "GroupShuffleMode": { + "enum": ["Sorted", "Shuffle"], + "type": "string", + "description": "Enum GroupShuffleMode." + }, + "GroupStateType": { + "enum": ["Idle", "Waiting", "Paused", "Playing"], + "type": "string", + "description": "Enum GroupState." + }, + "GroupStateUpdate": { + "type": "object", + "properties": { + "State": { + "enum": ["Idle", "Waiting", "Paused", "Playing"], + "allOf": [ + { + "$ref": "#/components/schemas/GroupStateType" + } + ], + "description": "Gets the state of the group." + }, + "Reason": { + "enum": [ + "Play", + "SetPlaylistItem", + "RemoveFromPlaylist", + "MovePlaylistItem", + "Queue", + "Unpause", + "Pause", + "Stop", + "Seek", + "Buffer", + "Ready", + "NextItem", + "PreviousItem", + "SetRepeatMode", + "SetShuffleMode", + "Ping", + "IgnoreWait" + ], + "allOf": [ + { + "$ref": "#/components/schemas/PlaybackRequestType" + } + ], + "description": "Gets the reason of the state change." + } + }, + "additionalProperties": false, + "description": "Class GroupStateUpdate." + }, + "GroupStateUpdateGroupUpdate": { + "type": "object", + "properties": { + "GroupId": { + "type": "string", + "description": "Gets the group identifier.", + "format": "uuid", + "readOnly": true + }, + "Type": { + "enum": [ + "UserJoined", + "UserLeft", + "GroupJoined", + "GroupLeft", + "StateUpdate", + "PlayQueue", + "NotInGroup", + "GroupDoesNotExist", + "CreateGroupDenied", + "JoinGroupDenied", + "LibraryAccessDenied" + ], + "allOf": [ + { + "$ref": "#/components/schemas/GroupUpdateType" + } + ], + "description": "Gets the update type." + }, + "Data": { + "allOf": [ + { + "$ref": "#/components/schemas/GroupStateUpdate" + } + ], + "description": "Gets the update data." + } + }, + "additionalProperties": false, + "description": "Class GroupUpdate." + }, + "GroupUpdate": { + "type": "object", + "oneOf": [ + { + "$ref": "#/components/schemas/GroupInfoDtoGroupUpdate" + }, + { + "$ref": "#/components/schemas/GroupStateUpdateGroupUpdate" + }, + { + "$ref": "#/components/schemas/StringGroupUpdate" + }, + { + "$ref": "#/components/schemas/PlayQueueUpdateGroupUpdate" + } + ], + "properties": { + "GroupId": { + "type": "string", + "description": "Gets the group identifier.", + "format": "uuid", + "readOnly": true + }, + "Type": { + "enum": [ + "UserJoined", + "UserLeft", + "GroupJoined", + "GroupLeft", + "StateUpdate", + "PlayQueue", + "NotInGroup", + "GroupDoesNotExist", + "CreateGroupDenied", + "JoinGroupDenied", + "LibraryAccessDenied" + ], + "allOf": [ + { + "$ref": "#/components/schemas/GroupUpdateType" + } + ], + "description": "Gets the update type." + } + }, + "additionalProperties": false, + "description": "Group update without data.", + "discriminator": { + "propertyName": "Type", + "mapping": { + "UserJoined": "#/components/schemas/StringGroupUpdate", + "UserLeft": "#/components/schemas/StringGroupUpdate", + "GroupJoined": "#/components/schemas/GroupInfoDtoGroupUpdate", + "GroupLeft": "#/components/schemas/StringGroupUpdate", + "StateUpdate": "#/components/schemas/GroupStateUpdateGroupUpdate", + "PlayQueue": "#/components/schemas/PlayQueueUpdateGroupUpdate", + "NotInGroup": "#/components/schemas/StringGroupUpdate", + "GroupDoesNotExist": "#/components/schemas/StringGroupUpdate", + "LibraryAccessDenied": "#/components/schemas/StringGroupUpdate" + } + } + }, + "GroupUpdateType": { + "enum": [ + "UserJoined", + "UserLeft", + "GroupJoined", + "GroupLeft", + "StateUpdate", + "PlayQueue", + "NotInGroup", + "GroupDoesNotExist", + "CreateGroupDenied", + "JoinGroupDenied", + "LibraryAccessDenied" + ], + "type": "string", + "description": "Enum GroupUpdateType." + }, + "GuideInfo": { + "type": "object", + "properties": { + "StartDate": { + "type": "string", + "description": "Gets or sets the start date.", + "format": "date-time" + }, + "EndDate": { + "type": "string", + "description": "Gets or sets the end date.", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "HardwareEncodingType": { + "enum": [ + "AMF", + "QSV", + "NVENC", + "V4L2M2M", + "VAAPI", + "VideoToolBox", + "RKMPP" + ], + "type": "string", + "description": "Enum HardwareEncodingType." + }, + "IgnoreWaitRequestDto": { + "type": "object", + "properties": { + "IgnoreWait": { + "type": "boolean", + "description": "Gets or sets a value indicating whether the client should be ignored." + } + }, + "additionalProperties": false, + "description": "Class IgnoreWaitRequestDto." + }, + "ImageFormat": { + "enum": ["Bmp", "Gif", "Jpg", "Png", "Webp", "Svg"], + "type": "string", + "description": "Enum ImageOutputFormat." + }, + "ImageInfo": { + "type": "object", + "properties": { + "ImageType": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Gets or sets the type of the image." + }, + "ImageIndex": { + "type": "integer", + "description": "Gets or sets the index of the image.", + "format": "int32", + "nullable": true + }, + "ImageTag": { + "type": "string", + "description": "Gets or sets the image tag.", + "nullable": true + }, + "Path": { + "type": "string", + "description": "Gets or sets the path.", + "nullable": true + }, + "BlurHash": { + "type": "string", + "description": "Gets or sets the blurhash.", + "nullable": true + }, + "Height": { + "type": "integer", + "description": "Gets or sets the height.", + "format": "int32", + "nullable": true + }, + "Width": { + "type": "integer", + "description": "Gets or sets the width.", + "format": "int32", + "nullable": true + }, + "Size": { + "type": "integer", + "description": "Gets or sets the size.", + "format": "int64" + } + }, + "additionalProperties": false, + "description": "Class ImageInfo." + }, + "ImageOption": { + "type": "object", + "properties": { + "Type": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Gets or sets the type." + }, + "Limit": { + "type": "integer", + "description": "Gets or sets the limit.", + "format": "int32" + }, + "MinWidth": { + "type": "integer", + "description": "Gets or sets the minimum width.", + "format": "int32" + } + }, + "additionalProperties": false + }, + "ImageOrientation": { + "enum": [ + "TopLeft", + "TopRight", + "BottomRight", + "BottomLeft", + "LeftTop", + "RightTop", + "RightBottom", + "LeftBottom" + ], + "type": "string" + }, + "ImageProviderInfo": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets the name." + }, + "SupportedImages": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + }, + "description": "Gets the supported image types." + } + }, + "additionalProperties": false, + "description": "Class ImageProviderInfo." + }, + "ImageResolution": { + "enum": [ + "MatchSource", + "P144", + "P240", + "P360", + "P480", + "P720", + "P1080", + "P1440", + "P2160" + ], + "type": "string", + "description": "Enum ImageResolution." + }, + "ImageSavingConvention": { + "enum": ["Legacy", "Compatible"], + "type": "string" + }, + "ImageType": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "type": "string", + "description": "Enum ImageType." + }, + "InboundKeepAliveMessage": { + "type": "object", + "properties": { + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "KeepAlive", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Keep alive websocket messages." + }, + "InboundWebSocketMessage": { + "type": "object", + "oneOf": [ + { + "$ref": "#/components/schemas/ActivityLogEntryStartMessage" + }, + { + "$ref": "#/components/schemas/ActivityLogEntryStopMessage" + }, + { + "$ref": "#/components/schemas/InboundKeepAliveMessage" + }, + { + "$ref": "#/components/schemas/ScheduledTasksInfoStartMessage" + }, + { + "$ref": "#/components/schemas/ScheduledTasksInfoStopMessage" + }, + { + "$ref": "#/components/schemas/SessionsStartMessage" + }, + { + "$ref": "#/components/schemas/SessionsStopMessage" + } + ], + "description": "Represents the list of possible inbound websocket types", + "discriminator": { + "propertyName": "MessageType", + "mapping": { + "ActivityLogEntryStart": "#/components/schemas/ActivityLogEntryStartMessage", + "ActivityLogEntryStop": "#/components/schemas/ActivityLogEntryStopMessage", + "KeepAlive": "#/components/schemas/InboundKeepAliveMessage", + "ScheduledTasksInfoStart": "#/components/schemas/ScheduledTasksInfoStartMessage", + "ScheduledTasksInfoStop": "#/components/schemas/ScheduledTasksInfoStopMessage", + "SessionsStart": "#/components/schemas/SessionsStartMessage", + "SessionsStop": "#/components/schemas/SessionsStopMessage" + } + } + }, + "InstallationInfo": { + "type": "object", + "properties": { + "Guid": { + "type": "string", + "description": "Gets or sets the Id.", + "format": "uuid" + }, + "Name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + }, + "Version": { + "type": "string", + "description": "Gets or sets the version.", + "nullable": true + }, + "Changelog": { + "type": "string", + "description": "Gets or sets the changelog for this version.", + "nullable": true + }, + "SourceUrl": { + "type": "string", + "description": "Gets or sets the source URL.", + "nullable": true + }, + "Checksum": { + "type": "string", + "description": "Gets or sets a checksum for the binary.", + "nullable": true + }, + "PackageInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/PackageInfo" + } + ], + "description": "Gets or sets package information for the installation.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class InstallationInfo." + }, + "Intro": { + "type": "object", + "properties": { + "EpisodeId": { + "type": "string", + "format": "uuid" + }, + "Valid": { + "type": "boolean", + "readOnly": true + }, + "IntroStart": { + "type": "number", + "format": "double" + }, + "IntroEnd": { + "type": "number", + "format": "double" + }, + "ShowSkipPromptAt": { + "type": "number", + "format": "double" + }, + "HideSkipPromptAt": { + "type": "number", + "format": "double" + } + }, + "additionalProperties": false + }, + "IntroWithMetadata": { + "type": "object", + "properties": { + "EpisodeId": { + "type": "string", + "format": "uuid" + }, + "Valid": { + "type": "boolean", + "readOnly": true + }, + "IntroStart": { + "type": "number", + "format": "double" + }, + "IntroEnd": { + "type": "number", + "format": "double" + }, + "ShowSkipPromptAt": { + "type": "number", + "format": "double" + }, + "HideSkipPromptAt": { + "type": "number", + "format": "double" + }, + "Series": { + "type": "string" + }, + "Season": { + "type": "integer", + "format": "int32" + }, + "Title": { + "type": "string" + } + }, + "additionalProperties": false + }, + "IPlugin": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets the name of the plugin.", + "nullable": true, + "readOnly": true + }, + "Description": { + "type": "string", + "description": "Gets the Description.", + "nullable": true, + "readOnly": true + }, + "Id": { + "type": "string", + "description": "Gets the unique id.", + "format": "uuid", + "readOnly": true + }, + "Version": { + "type": "string", + "description": "Gets the plugin version.", + "nullable": true, + "readOnly": true + }, + "AssemblyFilePath": { + "type": "string", + "description": "Gets the path to the assembly file.", + "nullable": true, + "readOnly": true + }, + "CanUninstall": { + "type": "boolean", + "description": "Gets a value indicating whether the plugin can be uninstalled.", + "readOnly": true + }, + "DataFolderPath": { + "type": "string", + "description": "Gets the full path to the data folder, where the plugin can store any miscellaneous files needed.", + "nullable": true, + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Defines the MediaBrowser.Common.Plugins.IPlugin." + }, + "IsoType": { + "enum": ["Dvd", "BluRay"], + "type": "string", + "description": "Enum IsoType." + }, + "ItemCounts": { + "type": "object", + "properties": { + "MovieCount": { + "type": "integer", + "description": "Gets or sets the movie count.", + "format": "int32" + }, + "SeriesCount": { + "type": "integer", + "description": "Gets or sets the series count.", + "format": "int32" + }, + "EpisodeCount": { + "type": "integer", + "description": "Gets or sets the episode count.", + "format": "int32" + }, + "ArtistCount": { + "type": "integer", + "description": "Gets or sets the artist count.", + "format": "int32" + }, + "ProgramCount": { + "type": "integer", + "description": "Gets or sets the program count.", + "format": "int32" + }, + "TrailerCount": { + "type": "integer", + "description": "Gets or sets the trailer count.", + "format": "int32" + }, + "SongCount": { + "type": "integer", + "description": "Gets or sets the song count.", + "format": "int32" + }, + "AlbumCount": { + "type": "integer", + "description": "Gets or sets the album count.", + "format": "int32" + }, + "MusicVideoCount": { + "type": "integer", + "description": "Gets or sets the music video count.", + "format": "int32" + }, + "BoxSetCount": { + "type": "integer", + "description": "Gets or sets the box set count.", + "format": "int32" + }, + "BookCount": { + "type": "integer", + "description": "Gets or sets the book count.", + "format": "int32" + }, + "ItemCount": { + "type": "integer", + "description": "Gets or sets the item count.", + "format": "int32" + } + }, + "additionalProperties": false, + "description": "Class LibrarySummary." + }, + "ItemFields": { + "enum": [ + "AirTime", + "CanDelete", + "CanDownload", + "ChannelInfo", + "Chapters", + "Trickplay", + "ChildCount", + "CumulativeRunTimeTicks", + "CustomRating", + "DateCreated", + "DateLastMediaAdded", + "DisplayPreferencesId", + "Etag", + "ExternalUrls", + "Genres", + "HomePageUrl", + "ItemCounts", + "MediaSourceCount", + "MediaSources", + "OriginalTitle", + "Overview", + "ParentId", + "Path", + "People", + "PlayAccess", + "ProductionLocations", + "ProviderIds", + "PrimaryImageAspectRatio", + "RecursiveItemCount", + "Settings", + "ScreenshotImageTags", + "SeriesPrimaryImage", + "SeriesStudio", + "SortName", + "SpecialEpisodeNumbers", + "Studios", + "Taglines", + "Tags", + "RemoteTrailers", + "MediaStreams", + "SeasonUserData", + "ServiceName", + "ThemeSongIds", + "ThemeVideoIds", + "ExternalEtag", + "PresentationUniqueKey", + "InheritedParentalRatingValue", + "ExternalSeriesId", + "SeriesPresentationUniqueKey", + "DateLastRefreshed", + "DateLastSaved", + "RefreshState", + "ChannelImage", + "EnableMediaSourceDisplay", + "Width", + "Height", + "ExtraIds", + "LocalTrailerCount", + "IsHD", + "SpecialFeatureCount" + ], + "type": "string", + "description": "Used to control the data that gets attached to DtoBaseItems." + }, + "ItemFilter": { + "enum": [ + "IsFolder", + "IsNotFolder", + "IsUnplayed", + "IsPlayed", + "IsFavorite", + "IsResumable", + "Likes", + "Dislikes", + "IsFavoriteOrLikes" + ], + "type": "string", + "description": "Enum ItemFilter." + }, + "Items": { + "type": "object", + "properties": { + "movies": { + "type": "integer", + "format": "int32" + }, + "episodes": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "ItemSortBy": { + "enum": [ + "Default", + "AiredEpisodeOrder", + "Album", + "AlbumArtist", + "Artist", + "DateCreated", + "OfficialRating", + "DatePlayed", + "PremiereDate", + "StartDate", + "SortName", + "Name", + "Random", + "Runtime", + "CommunityRating", + "ProductionYear", + "PlayCount", + "CriticRating", + "IsFolder", + "IsUnplayed", + "IsPlayed", + "SeriesSortName", + "VideoBitRate", + "AirTime", + "Studio", + "IsFavoriteOrLiked", + "DateLastContentAdded", + "SeriesDatePlayed", + "ParentIndexNumber", + "IndexNumber", + "SimilarityScore", + "SearchScore" + ], + "type": "string", + "description": "These represent sort orders." + }, + "JoinGroupRequestDto": { + "type": "object", + "properties": { + "GroupId": { + "type": "string", + "description": "Gets or sets the group identifier.", + "format": "uuid" + } + }, + "additionalProperties": false, + "description": "Class JoinGroupRequestDto." + }, + "KeepUntil": { + "enum": [ + "UntilDeleted", + "UntilSpaceNeeded", + "UntilWatched", + "UntilDate" + ], + "type": "string" + }, + "LibraryChangedMessage": { + "type": "object", + "properties": { + "Data": { + "allOf": [ + { + "$ref": "#/components/schemas/LibraryUpdateInfo" + } + ], + "description": "Gets or sets the data.", + "nullable": true + }, + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "LibraryChanged", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Library changed message." + }, + "LibraryOptionInfoDto": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets name.", + "nullable": true + }, + "DefaultEnabled": { + "type": "boolean", + "description": "Gets or sets a value indicating whether default enabled." + } + }, + "additionalProperties": false, + "description": "Library option info dto." + }, + "LibraryOptions": { + "type": "object", + "properties": { + "Enabled": { + "type": "boolean" + }, + "EnablePhotos": { + "type": "boolean" + }, + "EnableRealtimeMonitor": { + "type": "boolean" + }, + "EnableLUFSScan": { + "type": "boolean" + }, + "EnableChapterImageExtraction": { + "type": "boolean" + }, + "ExtractChapterImagesDuringLibraryScan": { + "type": "boolean" + }, + "EnableTrickplayImageExtraction": { + "type": "boolean" + }, + "ExtractTrickplayImagesDuringLibraryScan": { + "type": "boolean" + }, + "PathInfos": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MediaPathInfo" + } + }, + "SaveLocalMetadata": { + "type": "boolean" + }, + "EnableInternetProviders": { + "type": "boolean", + "deprecated": true + }, + "EnableAutomaticSeriesGrouping": { + "type": "boolean" + }, + "EnableEmbeddedTitles": { + "type": "boolean" + }, + "EnableEmbeddedExtrasTitles": { + "type": "boolean" + }, + "EnableEmbeddedEpisodeInfos": { + "type": "boolean" + }, + "AutomaticRefreshIntervalDays": { + "type": "integer", + "format": "int32" + }, + "PreferredMetadataLanguage": { + "type": "string", + "description": "Gets or sets the preferred metadata language.", + "nullable": true + }, + "MetadataCountryCode": { + "type": "string", + "description": "Gets or sets the metadata country code.", + "nullable": true + }, + "SeasonZeroDisplayName": { + "type": "string" + }, + "MetadataSavers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "DisabledLocalMetadataReaders": { + "type": "array", + "items": { + "type": "string" + } + }, + "LocalMetadataReaderOrder": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "DisabledSubtitleFetchers": { + "type": "array", + "items": { + "type": "string" + } + }, + "SubtitleFetcherOrder": { + "type": "array", + "items": { + "type": "string" + } + }, + "SkipSubtitlesIfEmbeddedSubtitlesPresent": { + "type": "boolean" + }, + "SkipSubtitlesIfAudioTrackMatches": { + "type": "boolean" + }, + "SubtitleDownloadLanguages": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "RequirePerfectSubtitleMatch": { + "type": "boolean" + }, + "SaveSubtitlesWithMedia": { + "type": "boolean" + }, + "SaveLyricsWithMedia": { + "type": "boolean", + "default": false + }, + "AutomaticallyAddToCollection": { + "type": "boolean" + }, + "AllowEmbeddedSubtitles": { + "enum": ["AllowAll", "AllowText", "AllowImage", "AllowNone"], + "allOf": [ + { + "$ref": "#/components/schemas/EmbeddedSubtitleOptions" + } + ], + "description": "An enum representing the options to disable embedded subs." + }, + "TypeOptions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypeOptions" + } + } + }, + "additionalProperties": false + }, + "LibraryOptionsResultDto": { + "type": "object", + "properties": { + "MetadataSavers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LibraryOptionInfoDto" + }, + "description": "Gets or sets the metadata savers." + }, + "MetadataReaders": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LibraryOptionInfoDto" + }, + "description": "Gets or sets the metadata readers." + }, + "SubtitleFetchers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LibraryOptionInfoDto" + }, + "description": "Gets or sets the subtitle fetchers." + }, + "TypeOptions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LibraryTypeOptionsDto" + }, + "description": "Gets or sets the type options." + } + }, + "additionalProperties": false, + "description": "Library options result dto." + }, + "LibraryTypeOptionsDto": { + "type": "object", + "properties": { + "Type": { + "type": "string", + "description": "Gets or sets the type.", + "nullable": true + }, + "MetadataFetchers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LibraryOptionInfoDto" + }, + "description": "Gets or sets the metadata fetchers." + }, + "ImageFetchers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LibraryOptionInfoDto" + }, + "description": "Gets or sets the image fetchers." + }, + "SupportedImageTypes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageType" + }, + "description": "Gets or sets the supported image types." + }, + "DefaultImageOptions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageOption" + }, + "description": "Gets or sets the default image options." + } + }, + "additionalProperties": false, + "description": "Library type options dto." + }, + "LibraryUpdateInfo": { + "type": "object", + "properties": { + "FoldersAddedTo": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the folders added to." + }, + "FoldersRemovedFrom": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the folders removed from." + }, + "ItemsAdded": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the items added." + }, + "ItemsRemoved": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the items removed." + }, + "ItemsUpdated": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the items updated." + }, + "CollectionFolders": { + "type": "array", + "items": { + "type": "string" + } + }, + "IsEmpty": { + "type": "boolean", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Class LibraryUpdateInfo." + }, + "ListingsProviderInfo": { + "type": "object", + "properties": { + "Id": { + "type": "string", + "nullable": true + }, + "Type": { + "type": "string", + "nullable": true + }, + "Username": { + "type": "string", + "nullable": true + }, + "Password": { + "type": "string", + "nullable": true + }, + "ListingsId": { + "type": "string", + "nullable": true + }, + "ZipCode": { + "type": "string", + "nullable": true + }, + "Country": { + "type": "string", + "nullable": true + }, + "Path": { + "type": "string", + "nullable": true + }, + "EnabledTuners": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "EnableAllTuners": { + "type": "boolean" + }, + "NewsCategories": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "SportsCategories": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "KidsCategories": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "MovieCategories": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "ChannelMappings": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NameValuePair" + }, + "nullable": true + }, + "MoviePrefix": { + "type": "string", + "nullable": true + }, + "PreferredLanguage": { + "type": "string", + "nullable": true + }, + "UserAgent": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "LiveStreamResponse": { + "type": "object", + "properties": { + "MediaSource": { + "allOf": [ + { + "$ref": "#/components/schemas/MediaSourceInfo" + } + ] + } + }, + "additionalProperties": false + }, + "LiveTvInfo": { + "type": "object", + "properties": { + "Services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LiveTvServiceInfo" + }, + "description": "Gets or sets the services." + }, + "IsEnabled": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is enabled." + }, + "EnabledUsers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the enabled users." + } + }, + "additionalProperties": false + }, + "LiveTvOptions": { + "type": "object", + "properties": { + "GuideDays": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "RecordingPath": { + "type": "string", + "nullable": true + }, + "MovieRecordingPath": { + "type": "string", + "nullable": true + }, + "SeriesRecordingPath": { + "type": "string", + "nullable": true + }, + "EnableRecordingSubfolders": { + "type": "boolean" + }, + "EnableOriginalAudioWithEncodedRecordings": { + "type": "boolean" + }, + "TunerHosts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TunerHostInfo" + }, + "nullable": true + }, + "ListingProviders": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ListingsProviderInfo" + }, + "nullable": true + }, + "PrePaddingSeconds": { + "type": "integer", + "format": "int32" + }, + "PostPaddingSeconds": { + "type": "integer", + "format": "int32" + }, + "MediaLocationsCreated": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "RecordingPostProcessor": { + "type": "string", + "nullable": true + }, + "RecordingPostProcessorArguments": { + "type": "string", + "nullable": true + }, + "SaveRecordingNFO": { + "type": "boolean" + }, + "SaveRecordingImages": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "LiveTvServiceInfo": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + }, + "HomePageUrl": { + "type": "string", + "description": "Gets or sets the home page URL.", + "nullable": true + }, + "Status": { + "enum": ["Ok", "Unavailable"], + "allOf": [ + { + "$ref": "#/components/schemas/LiveTvServiceStatus" + } + ], + "description": "Gets or sets the status." + }, + "StatusMessage": { + "type": "string", + "description": "Gets or sets the status message.", + "nullable": true + }, + "Version": { + "type": "string", + "description": "Gets or sets the version.", + "nullable": true + }, + "HasUpdateAvailable": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance has update available." + }, + "IsVisible": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is visible." + }, + "Tuners": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class ServiceInfo." + }, + "LiveTvServiceStatus": { + "enum": ["Ok", "Unavailable"], + "type": "string" + }, + "LocalizationOption": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "nullable": true + }, + "Value": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "LocationType": { + "enum": ["FileSystem", "Remote", "Virtual", "Offline"], + "type": "string", + "description": "Enum LocationType." + }, + "LogFile": { + "type": "object", + "properties": { + "DateCreated": { + "type": "string", + "description": "Gets or sets the date created.", + "format": "date-time" + }, + "DateModified": { + "type": "string", + "description": "Gets or sets the date modified.", + "format": "date-time" + }, + "Size": { + "type": "integer", + "description": "Gets or sets the size.", + "format": "int64" + }, + "Name": { + "type": "string", + "description": "Gets or sets the name." + } + }, + "additionalProperties": false + }, + "LogLevel": { + "enum": [ + "Trace", + "Debug", + "Information", + "Warning", + "Error", + "Critical", + "None" + ], + "type": "string" + }, + "LyricDto": { + "type": "object", + "properties": { + "Metadata": { + "allOf": [ + { + "$ref": "#/components/schemas/LyricMetadata" + } + ], + "description": "Gets or sets Metadata for the lyrics." + }, + "Lyrics": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LyricLine" + }, + "description": "Gets or sets a collection of individual lyric lines." + } + }, + "additionalProperties": false, + "description": "LyricResponse model." + }, + "LyricLine": { + "type": "object", + "properties": { + "Text": { + "type": "string", + "description": "Gets the text of this lyric line." + }, + "Start": { + "type": "integer", + "description": "Gets the start time in ticks.", + "format": "int64", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Lyric model." + }, + "LyricMetadata": { + "type": "object", + "properties": { + "Artist": { + "type": "string", + "description": "Gets or sets the song artist.", + "nullable": true + }, + "Album": { + "type": "string", + "description": "Gets or sets the album this song is on.", + "nullable": true + }, + "Title": { + "type": "string", + "description": "Gets or sets the title of the song.", + "nullable": true + }, + "Author": { + "type": "string", + "description": "Gets or sets the author of the lyric data.", + "nullable": true + }, + "Length": { + "type": "integer", + "description": "Gets or sets the length of the song in ticks.", + "format": "int64", + "nullable": true + }, + "By": { + "type": "string", + "description": "Gets or sets who the LRC file was created by.", + "nullable": true + }, + "Offset": { + "type": "integer", + "description": "Gets or sets the lyric offset compared to audio in ticks.", + "format": "int64", + "nullable": true + }, + "Creator": { + "type": "string", + "description": "Gets or sets the software used to create the LRC file.", + "nullable": true + }, + "Version": { + "type": "string", + "description": "Gets or sets the version of the creator used.", + "nullable": true + }, + "IsSynced": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this lyric is synced.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "LyricMetadata model." + }, + "MediaAttachment": { + "type": "object", + "properties": { + "Codec": { + "type": "string", + "description": "Gets or sets the codec.", + "nullable": true + }, + "CodecTag": { + "type": "string", + "description": "Gets or sets the codec tag.", + "nullable": true + }, + "Comment": { + "type": "string", + "description": "Gets or sets the comment.", + "nullable": true + }, + "Index": { + "type": "integer", + "description": "Gets or sets the index.", + "format": "int32" + }, + "FileName": { + "type": "string", + "description": "Gets or sets the filename.", + "nullable": true + }, + "MimeType": { + "type": "string", + "description": "Gets or sets the MIME type.", + "nullable": true + }, + "DeliveryUrl": { + "type": "string", + "description": "Gets or sets the delivery URL.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class MediaAttachment." + }, + "MediaPathDto": { + "required": ["Name"], + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name of the library." + }, + "Path": { + "type": "string", + "description": "Gets or sets the path to add.", + "nullable": true + }, + "PathInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/MediaPathInfo" + } + ], + "description": "Gets or sets the path info.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Media Path dto." + }, + "MediaPathInfo": { + "type": "object", + "properties": { + "Path": { + "type": "string" + }, + "NetworkPath": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "MediaProtocol": { + "enum": ["File", "Http", "Rtmp", "Rtsp", "Udp", "Rtp", "Ftp"], + "type": "string" + }, + "MediaSourceInfo": { + "type": "object", + "properties": { + "Protocol": { + "enum": ["File", "Http", "Rtmp", "Rtsp", "Udp", "Rtp", "Ftp"], + "allOf": [ + { + "$ref": "#/components/schemas/MediaProtocol" + } + ] + }, + "Id": { + "type": "string", + "nullable": true + }, + "Path": { + "type": "string", + "nullable": true + }, + "EncoderPath": { + "type": "string", + "nullable": true + }, + "EncoderProtocol": { + "enum": ["File", "Http", "Rtmp", "Rtsp", "Udp", "Rtp", "Ftp"], + "allOf": [ + { + "$ref": "#/components/schemas/MediaProtocol" + } + ], + "nullable": true + }, + "Type": { + "enum": ["Default", "Grouping", "Placeholder"], + "allOf": [ + { + "$ref": "#/components/schemas/MediaSourceType" + } + ] + }, + "Container": { + "type": "string", + "nullable": true + }, + "Size": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "Name": { + "type": "string", + "nullable": true + }, + "IsRemote": { + "type": "boolean", + "description": "Gets or sets a value indicating whether the media is remote.\r\nDifferentiate internet url vs local network." + }, + "ETag": { + "type": "string", + "nullable": true + }, + "RunTimeTicks": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "ReadAtNativeFramerate": { + "type": "boolean" + }, + "IgnoreDts": { + "type": "boolean" + }, + "IgnoreIndex": { + "type": "boolean" + }, + "GenPtsInput": { + "type": "boolean" + }, + "SupportsTranscoding": { + "type": "boolean" + }, + "SupportsDirectStream": { + "type": "boolean" + }, + "SupportsDirectPlay": { + "type": "boolean" + }, + "IsInfiniteStream": { + "type": "boolean" + }, + "RequiresOpening": { + "type": "boolean" + }, + "OpenToken": { + "type": "string", + "nullable": true + }, + "RequiresClosing": { + "type": "boolean" + }, + "LiveStreamId": { + "type": "string", + "nullable": true + }, + "BufferMs": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "RequiresLooping": { + "type": "boolean" + }, + "SupportsProbing": { + "type": "boolean" + }, + "VideoType": { + "enum": ["VideoFile", "Iso", "Dvd", "BluRay"], + "allOf": [ + { + "$ref": "#/components/schemas/VideoType" + } + ], + "nullable": true + }, + "IsoType": { + "enum": ["Dvd", "BluRay"], + "allOf": [ + { + "$ref": "#/components/schemas/IsoType" + } + ], + "nullable": true + }, + "Video3DFormat": { + "enum": [ + "HalfSideBySide", + "FullSideBySide", + "FullTopAndBottom", + "HalfTopAndBottom", + "MVC" + ], + "allOf": [ + { + "$ref": "#/components/schemas/Video3DFormat" + } + ], + "nullable": true + }, + "MediaStreams": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MediaStream" + }, + "nullable": true + }, + "MediaAttachments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MediaAttachment" + }, + "nullable": true + }, + "Formats": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "Bitrate": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "Timestamp": { + "enum": ["None", "Zero", "Valid"], + "allOf": [ + { + "$ref": "#/components/schemas/TransportStreamTimestamp" + } + ], + "nullable": true + }, + "RequiredHttpHeaders": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "nullable": true + }, + "TranscodingUrl": { + "type": "string", + "nullable": true + }, + "TranscodingSubProtocol": { + "enum": ["http", "hls"], + "allOf": [ + { + "$ref": "#/components/schemas/MediaStreamProtocol" + } + ], + "description": "Media streaming protocol.\r\nLowercase for backwards compatibility." + }, + "TranscodingContainer": { + "type": "string", + "nullable": true + }, + "AnalyzeDurationMs": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "DefaultAudioStreamIndex": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "DefaultSubtitleStreamIndex": { + "type": "integer", + "format": "int32", + "nullable": true + } + }, + "additionalProperties": false + }, + "MediaSourceType": { + "enum": ["Default", "Grouping", "Placeholder"], + "type": "string" + }, + "MediaStream": { + "type": "object", + "properties": { + "Codec": { + "type": "string", + "description": "Gets or sets the codec.", + "nullable": true + }, + "CodecTag": { + "type": "string", + "description": "Gets or sets the codec tag.", + "nullable": true + }, + "Language": { + "type": "string", + "description": "Gets or sets the language.", + "nullable": true + }, + "ColorRange": { + "type": "string", + "description": "Gets or sets the color range.", + "nullable": true + }, + "ColorSpace": { + "type": "string", + "description": "Gets or sets the color space.", + "nullable": true + }, + "ColorTransfer": { + "type": "string", + "description": "Gets or sets the color transfer.", + "nullable": true + }, + "ColorPrimaries": { + "type": "string", + "description": "Gets or sets the color primaries.", + "nullable": true + }, + "DvVersionMajor": { + "type": "integer", + "description": "Gets or sets the Dolby Vision version major.", + "format": "int32", + "nullable": true + }, + "DvVersionMinor": { + "type": "integer", + "description": "Gets or sets the Dolby Vision version minor.", + "format": "int32", + "nullable": true + }, + "DvProfile": { + "type": "integer", + "description": "Gets or sets the Dolby Vision profile.", + "format": "int32", + "nullable": true + }, + "DvLevel": { + "type": "integer", + "description": "Gets or sets the Dolby Vision level.", + "format": "int32", + "nullable": true + }, + "RpuPresentFlag": { + "type": "integer", + "description": "Gets or sets the Dolby Vision rpu present flag.", + "format": "int32", + "nullable": true + }, + "ElPresentFlag": { + "type": "integer", + "description": "Gets or sets the Dolby Vision el present flag.", + "format": "int32", + "nullable": true + }, + "BlPresentFlag": { + "type": "integer", + "description": "Gets or sets the Dolby Vision bl present flag.", + "format": "int32", + "nullable": true + }, + "DvBlSignalCompatibilityId": { + "type": "integer", + "description": "Gets or sets the Dolby Vision bl signal compatibility id.", + "format": "int32", + "nullable": true + }, + "Comment": { + "type": "string", + "description": "Gets or sets the comment.", + "nullable": true + }, + "TimeBase": { + "type": "string", + "description": "Gets or sets the time base.", + "nullable": true + }, + "CodecTimeBase": { + "type": "string", + "description": "Gets or sets the codec time base.", + "nullable": true + }, + "Title": { + "type": "string", + "description": "Gets or sets the title.", + "nullable": true + }, + "VideoRange": { + "enum": ["Unknown", "SDR", "HDR"], + "allOf": [ + { + "$ref": "#/components/schemas/VideoRange" + } + ], + "description": "An enum representing video ranges.", + "readOnly": true + }, + "VideoRangeType": { + "enum": [ + "Unknown", + "SDR", + "HDR10", + "HLG", + "DOVI", + "DOVIWithHDR10", + "DOVIWithHLG", + "DOVIWithSDR", + "HDR10Plus" + ], + "allOf": [ + { + "$ref": "#/components/schemas/VideoRangeType" + } + ], + "description": "An enum representing types of video ranges.", + "readOnly": true + }, + "VideoDoViTitle": { + "type": "string", + "description": "Gets the video dovi title.", + "nullable": true, + "readOnly": true + }, + "AudioSpatialFormat": { + "enum": ["None", "DolbyAtmos", "DTSX"], + "allOf": [ + { + "$ref": "#/components/schemas/AudioSpatialFormat" + } + ], + "description": "An enum representing formats of spatial audio.", + "default": "None", + "readOnly": true + }, + "LocalizedUndefined": { + "type": "string", + "nullable": true + }, + "LocalizedDefault": { + "type": "string", + "nullable": true + }, + "LocalizedForced": { + "type": "string", + "nullable": true + }, + "LocalizedExternal": { + "type": "string", + "nullable": true + }, + "LocalizedHearingImpaired": { + "type": "string", + "nullable": true + }, + "DisplayTitle": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "NalLengthSize": { + "type": "string", + "nullable": true + }, + "IsInterlaced": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is interlaced." + }, + "IsAVC": { + "type": "boolean", + "nullable": true + }, + "ChannelLayout": { + "type": "string", + "description": "Gets or sets the channel layout.", + "nullable": true + }, + "BitRate": { + "type": "integer", + "description": "Gets or sets the bit rate.", + "format": "int32", + "nullable": true + }, + "BitDepth": { + "type": "integer", + "description": "Gets or sets the bit depth.", + "format": "int32", + "nullable": true + }, + "RefFrames": { + "type": "integer", + "description": "Gets or sets the reference frames.", + "format": "int32", + "nullable": true + }, + "PacketLength": { + "type": "integer", + "description": "Gets or sets the length of the packet.", + "format": "int32", + "nullable": true + }, + "Channels": { + "type": "integer", + "description": "Gets or sets the channels.", + "format": "int32", + "nullable": true + }, + "SampleRate": { + "type": "integer", + "description": "Gets or sets the sample rate.", + "format": "int32", + "nullable": true + }, + "IsDefault": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is default." + }, + "IsForced": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is forced." + }, + "IsHearingImpaired": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is for the hearing impaired." + }, + "Height": { + "type": "integer", + "description": "Gets or sets the height.", + "format": "int32", + "nullable": true + }, + "Width": { + "type": "integer", + "description": "Gets or sets the width.", + "format": "int32", + "nullable": true + }, + "AverageFrameRate": { + "type": "number", + "description": "Gets or sets the average frame rate.", + "format": "float", + "nullable": true + }, + "RealFrameRate": { + "type": "number", + "description": "Gets or sets the real frame rate.", + "format": "float", + "nullable": true + }, + "Profile": { + "type": "string", + "description": "Gets or sets the profile.", + "nullable": true + }, + "Type": { + "enum": [ + "Audio", + "Video", + "Subtitle", + "EmbeddedImage", + "Data", + "Lyric" + ], + "allOf": [ + { + "$ref": "#/components/schemas/MediaStreamType" + } + ], + "description": "Gets or sets the type." + }, + "AspectRatio": { + "type": "string", + "description": "Gets or sets the aspect ratio.", + "nullable": true + }, + "Index": { + "type": "integer", + "description": "Gets or sets the index.", + "format": "int32" + }, + "Score": { + "type": "integer", + "description": "Gets or sets the score.", + "format": "int32", + "nullable": true + }, + "IsExternal": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is external." + }, + "DeliveryMethod": { + "enum": ["Encode", "Embed", "External", "Hls", "Drop"], + "allOf": [ + { + "$ref": "#/components/schemas/SubtitleDeliveryMethod" + } + ], + "description": "Gets or sets the method.", + "nullable": true + }, + "DeliveryUrl": { + "type": "string", + "description": "Gets or sets the delivery URL.", + "nullable": true + }, + "IsExternalUrl": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is external URL.", + "nullable": true + }, + "IsTextSubtitleStream": { + "type": "boolean", + "readOnly": true + }, + "SupportsExternalStream": { + "type": "boolean", + "description": "Gets or sets a value indicating whether [supports external stream]." + }, + "Path": { + "type": "string", + "description": "Gets or sets the filename.", + "nullable": true + }, + "PixelFormat": { + "type": "string", + "description": "Gets or sets the pixel format.", + "nullable": true + }, + "Level": { + "type": "number", + "description": "Gets or sets the level.", + "format": "double", + "nullable": true + }, + "IsAnamorphic": { + "type": "boolean", + "description": "Gets or sets whether this instance is anamorphic.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class MediaStream." + }, + "MediaStreamProtocol": { + "enum": ["http", "hls"], + "type": "string", + "description": "Media streaming protocol.\r\nLowercase for backwards compatibility." + }, + "MediaStreamType": { + "enum": [ + "Audio", + "Video", + "Subtitle", + "EmbeddedImage", + "Data", + "Lyric" + ], + "type": "string", + "description": "Enum MediaStreamType." + }, + "MediaType": { + "enum": ["Unknown", "Video", "Audio", "Photo", "Book"], + "type": "string", + "description": "Media types." + }, + "MediaUpdateInfoDto": { + "type": "object", + "properties": { + "Updates": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MediaUpdateInfoPathDto" + }, + "description": "Gets or sets the list of updates." + } + }, + "additionalProperties": false, + "description": "Media Update Info Dto." + }, + "MediaUpdateInfoPathDto": { + "type": "object", + "properties": { + "Path": { + "type": "string", + "description": "Gets or sets media path.", + "nullable": true + }, + "UpdateType": { + "type": "string", + "description": "Gets or sets media update type.\r\nCreated, Modified, Deleted.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "The media update info path." + }, + "MediaUrl": { + "type": "object", + "properties": { + "Url": { + "type": "string", + "nullable": true + }, + "Name": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "MessageCommand": { + "required": ["Text"], + "type": "object", + "properties": { + "Header": { + "type": "string", + "nullable": true + }, + "Text": { + "type": "string" + }, + "TimeoutMs": { + "type": "integer", + "format": "int64", + "nullable": true + } + }, + "additionalProperties": false + }, + "MetadataConfiguration": { + "type": "object", + "properties": { + "UseFileCreationTimeForDateAdded": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "MetadataEditorInfo": { + "type": "object", + "properties": { + "ParentalRatingOptions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ParentalRating" + } + }, + "Countries": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CountryInfo" + } + }, + "Cultures": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CultureDto" + } + }, + "ExternalIdInfos": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ExternalIdInfo" + } + }, + "ContentType": { + "enum": [ + "unknown", + "movies", + "tvshows", + "music", + "musicvideos", + "trailers", + "homevideos", + "boxsets", + "books", + "photos", + "livetv", + "playlists", + "folders" + ], + "allOf": [ + { + "$ref": "#/components/schemas/CollectionType" + } + ], + "nullable": true + }, + "ContentTypeOptions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NameValuePair" + } + } + }, + "additionalProperties": false + }, + "MetadataField": { + "enum": [ + "Cast", + "Genres", + "ProductionLocations", + "Studios", + "Tags", + "Name", + "Overview", + "Runtime", + "OfficialRating" + ], + "type": "string", + "description": "Enum MetadataFields." + }, + "MetadataOptions": { + "type": "object", + "properties": { + "ItemType": { + "type": "string", + "nullable": true + }, + "DisabledMetadataSavers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "LocalMetadataReaderOrder": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "DisabledMetadataFetchers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "MetadataFetcherOrder": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "DisabledImageFetchers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "ImageFetcherOrder": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class MetadataOptions." + }, + "MetadataRefreshMode": { + "enum": ["None", "ValidationOnly", "Default", "FullRefresh"], + "type": "string" + }, + "MovePlaylistItemRequestDto": { + "type": "object", + "properties": { + "PlaylistItemId": { + "type": "string", + "description": "Gets or sets the playlist identifier of the item.", + "format": "uuid" + }, + "NewIndex": { + "type": "integer", + "description": "Gets or sets the new position.", + "format": "int32" + } + }, + "additionalProperties": false, + "description": "Class MovePlaylistItemRequestDto." + }, + "MovieInfo": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + }, + "OriginalTitle": { + "type": "string", + "description": "Gets or sets the original title.", + "nullable": true + }, + "Path": { + "type": "string", + "description": "Gets or sets the path.", + "nullable": true + }, + "MetadataLanguage": { + "type": "string", + "description": "Gets or sets the metadata language.", + "nullable": true + }, + "MetadataCountryCode": { + "type": "string", + "description": "Gets or sets the metadata country code.", + "nullable": true + }, + "ProviderIds": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "description": "Gets or sets the provider ids.", + "nullable": true + }, + "Year": { + "type": "integer", + "description": "Gets or sets the year.", + "format": "int32", + "nullable": true + }, + "IndexNumber": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "ParentIndexNumber": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "PremiereDate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "IsAutomated": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "MovieInfoRemoteSearchQuery": { + "type": "object", + "properties": { + "SearchInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/MovieInfo" + } + ], + "nullable": true + }, + "ItemId": { + "type": "string", + "format": "uuid" + }, + "SearchProviderName": { + "type": "string", + "description": "Gets or sets the provider name to search within if set.", + "nullable": true + }, + "IncludeDisabledProviders": { + "type": "boolean", + "description": "Gets or sets a value indicating whether disabled providers should be included." + } + }, + "additionalProperties": false + }, + "MusicVideoInfo": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + }, + "OriginalTitle": { + "type": "string", + "description": "Gets or sets the original title.", + "nullable": true + }, + "Path": { + "type": "string", + "description": "Gets or sets the path.", + "nullable": true + }, + "MetadataLanguage": { + "type": "string", + "description": "Gets or sets the metadata language.", + "nullable": true + }, + "MetadataCountryCode": { + "type": "string", + "description": "Gets or sets the metadata country code.", + "nullable": true + }, + "ProviderIds": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "description": "Gets or sets the provider ids.", + "nullable": true + }, + "Year": { + "type": "integer", + "description": "Gets or sets the year.", + "format": "int32", + "nullable": true + }, + "IndexNumber": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "ParentIndexNumber": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "PremiereDate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "IsAutomated": { + "type": "boolean" + }, + "Artists": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "MusicVideoInfoRemoteSearchQuery": { + "type": "object", + "properties": { + "SearchInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/MusicVideoInfo" + } + ], + "nullable": true + }, + "ItemId": { + "type": "string", + "format": "uuid" + }, + "SearchProviderName": { + "type": "string", + "description": "Gets or sets the provider name to search within if set.", + "nullable": true + }, + "IncludeDisabledProviders": { + "type": "boolean", + "description": "Gets or sets a value indicating whether disabled providers should be included." + } + }, + "additionalProperties": false + }, + "NameGuidPair": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "nullable": true + }, + "Id": { + "type": "string", + "format": "uuid" + } + }, + "additionalProperties": false + }, + "NameIdPair": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + }, + "Id": { + "type": "string", + "description": "Gets or sets the identifier.", + "nullable": true + } + }, + "additionalProperties": false + }, + "NameValuePair": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + }, + "Value": { + "type": "string", + "description": "Gets or sets the value.", + "nullable": true + } + }, + "additionalProperties": false + }, + "NetworkConfiguration": { + "type": "object", + "properties": { + "BaseUrl": { + "type": "string", + "description": "Gets or sets a value used to specify the URL prefix that your Jellyfin instance can be accessed at." + }, + "EnableHttps": { + "type": "boolean", + "description": "Gets or sets a value indicating whether to use HTTPS." + }, + "RequireHttps": { + "type": "boolean", + "description": "Gets or sets a value indicating whether the server should force connections over HTTPS." + }, + "CertificatePath": { + "type": "string", + "description": "Gets or sets the filesystem path of an X.509 certificate to use for SSL." + }, + "CertificatePassword": { + "type": "string", + "description": "Gets or sets the password required to access the X.509 certificate data in the file specified by MediaBrowser.Common.Net.NetworkConfiguration.CertificatePath." + }, + "InternalHttpPort": { + "type": "integer", + "description": "Gets or sets the internal HTTP server port.", + "format": "int32" + }, + "InternalHttpsPort": { + "type": "integer", + "description": "Gets or sets the internal HTTPS server port.", + "format": "int32" + }, + "PublicHttpPort": { + "type": "integer", + "description": "Gets or sets the public HTTP port.", + "format": "int32" + }, + "PublicHttpsPort": { + "type": "integer", + "description": "Gets or sets the public HTTPS port.", + "format": "int32" + }, + "AutoDiscovery": { + "type": "boolean", + "description": "Gets or sets a value indicating whether Autodiscovery is enabled." + }, + "EnableUPnP": { + "type": "boolean", + "description": "Gets or sets a value indicating whether to enable automatic port forwarding." + }, + "EnableIPv4": { + "type": "boolean", + "description": "Gets or sets a value indicating whether IPv6 is enabled." + }, + "EnableIPv6": { + "type": "boolean", + "description": "Gets or sets a value indicating whether IPv6 is enabled." + }, + "EnableRemoteAccess": { + "type": "boolean", + "description": "Gets or sets a value indicating whether access from outside of the LAN is permitted." + }, + "LocalNetworkSubnets": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the subnets that are deemed to make up the LAN." + }, + "LocalNetworkAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the interface addresses which Jellyfin will bind to. If empty, all interfaces will be used." + }, + "KnownProxies": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the known proxies." + }, + "IgnoreVirtualInterfaces": { + "type": "boolean", + "description": "Gets or sets a value indicating whether address names that match MediaBrowser.Common.Net.NetworkConfiguration.VirtualInterfaceNames should be ignored for the purposes of binding." + }, + "VirtualInterfaceNames": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets a value indicating the interface name prefixes that should be ignored. The list can be comma separated and values are case-insensitive. ." + }, + "EnablePublishedServerUriByRequest": { + "type": "boolean", + "description": "Gets or sets a value indicating whether the published server uri is based on information in HTTP requests." + }, + "PublishedServerUriBySubnet": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the PublishedServerUriBySubnet\r\nGets or sets PublishedServerUri to advertise for specific subnets." + }, + "RemoteIPFilter": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the filter for remote IP connectivity. Used in conjunction with ." + }, + "IsRemoteIPFilterBlacklist": { + "type": "boolean", + "description": "Gets or sets a value indicating whether contains a blacklist or a whitelist. Default is a whitelist." + } + }, + "additionalProperties": false, + "description": "Defines the MediaBrowser.Common.Net.NetworkConfiguration." + }, + "NewGroupRequestDto": { + "type": "object", + "properties": { + "GroupName": { + "type": "string", + "description": "Gets or sets the group name." + } + }, + "additionalProperties": false, + "description": "Class NewGroupRequestDto." + }, + "NextItemRequestDto": { + "type": "object", + "properties": { + "PlaylistItemId": { + "type": "string", + "description": "Gets or sets the playing item identifier.", + "format": "uuid" + } + }, + "additionalProperties": false, + "description": "Class NextItemRequestDto." + }, + "NotFoundObjects": { + "type": "object", + "properties": { + "movies": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TraktMovie" + }, + "nullable": true + }, + "shows": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TraktShow" + }, + "nullable": true + }, + "episodes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TraktEpisode" + }, + "nullable": true + }, + "seasons": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TraktSeason" + }, + "nullable": true + }, + "people": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TraktPerson" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "OpenLiveStreamDto": { + "type": "object", + "properties": { + "OpenToken": { + "type": "string", + "description": "Gets or sets the open token.", + "nullable": true + }, + "UserId": { + "type": "string", + "description": "Gets or sets the user id.", + "format": "uuid", + "nullable": true + }, + "PlaySessionId": { + "type": "string", + "description": "Gets or sets the play session id.", + "nullable": true + }, + "MaxStreamingBitrate": { + "type": "integer", + "description": "Gets or sets the max streaming bitrate.", + "format": "int32", + "nullable": true + }, + "StartTimeTicks": { + "type": "integer", + "description": "Gets or sets the start time in ticks.", + "format": "int64", + "nullable": true + }, + "AudioStreamIndex": { + "type": "integer", + "description": "Gets or sets the audio stream index.", + "format": "int32", + "nullable": true + }, + "SubtitleStreamIndex": { + "type": "integer", + "description": "Gets or sets the subtitle stream index.", + "format": "int32", + "nullable": true + }, + "MaxAudioChannels": { + "type": "integer", + "description": "Gets or sets the max audio channels.", + "format": "int32", + "nullable": true + }, + "ItemId": { + "type": "string", + "description": "Gets or sets the item id.", + "format": "uuid", + "nullable": true + }, + "EnableDirectPlay": { + "type": "boolean", + "description": "Gets or sets a value indicating whether to enable direct play.", + "nullable": true + }, + "EnableDirectStream": { + "type": "boolean", + "description": "Gets or sets a value indicating whether to enale direct stream.", + "nullable": true + }, + "DeviceProfile": { + "allOf": [ + { + "$ref": "#/components/schemas/DeviceProfile" + } + ], + "description": "Gets or sets the device profile.", + "nullable": true + }, + "DirectPlayProtocols": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MediaProtocol" + }, + "description": "Gets or sets the device play protocols." + } + }, + "additionalProperties": false, + "description": "Open live stream dto." + }, + "OutboundKeepAliveMessage": { + "type": "object", + "properties": { + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "KeepAlive", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Keep alive websocket messages." + }, + "OutboundWebSocketMessage": { + "type": "object", + "oneOf": [ + { + "$ref": "#/components/schemas/ActivityLogEntryMessage" + }, + { + "$ref": "#/components/schemas/ForceKeepAliveMessage" + }, + { + "$ref": "#/components/schemas/GeneralCommandMessage" + }, + { + "$ref": "#/components/schemas/LibraryChangedMessage" + }, + { + "$ref": "#/components/schemas/OutboundKeepAliveMessage" + }, + { + "$ref": "#/components/schemas/PlayMessage" + }, + { + "$ref": "#/components/schemas/PlaystateMessage" + }, + { + "$ref": "#/components/schemas/PluginInstallationCancelledMessage" + }, + { + "$ref": "#/components/schemas/PluginInstallationCompletedMessage" + }, + { + "$ref": "#/components/schemas/PluginInstallationFailedMessage" + }, + { + "$ref": "#/components/schemas/PluginInstallingMessage" + }, + { + "$ref": "#/components/schemas/PluginUninstalledMessage" + }, + { + "$ref": "#/components/schemas/RefreshProgressMessage" + }, + { + "$ref": "#/components/schemas/RestartRequiredMessage" + }, + { + "$ref": "#/components/schemas/ScheduledTaskEndedMessage" + }, + { + "$ref": "#/components/schemas/ScheduledTasksInfoMessage" + }, + { + "$ref": "#/components/schemas/SeriesTimerCancelledMessage" + }, + { + "$ref": "#/components/schemas/SeriesTimerCreatedMessage" + }, + { + "$ref": "#/components/schemas/ServerRestartingMessage" + }, + { + "$ref": "#/components/schemas/ServerShuttingDownMessage" + }, + { + "$ref": "#/components/schemas/SessionsMessage" + }, + { + "$ref": "#/components/schemas/SyncPlayCommandMessage" + }, + { + "$ref": "#/components/schemas/SyncPlayGroupUpdateCommandMessage" + }, + { + "$ref": "#/components/schemas/TimerCancelledMessage" + }, + { + "$ref": "#/components/schemas/TimerCreatedMessage" + }, + { + "$ref": "#/components/schemas/UserDataChangedMessage" + }, + { + "$ref": "#/components/schemas/UserDeletedMessage" + }, + { + "$ref": "#/components/schemas/UserUpdatedMessage" + } + ], + "description": "Represents the list of possible outbound websocket types", + "discriminator": { + "propertyName": "MessageType", + "mapping": { + "ActivityLogEntry": "#/components/schemas/ActivityLogEntryMessage", + "ForceKeepAlive": "#/components/schemas/ForceKeepAliveMessage", + "GeneralCommand": "#/components/schemas/GeneralCommandMessage", + "LibraryChanged": "#/components/schemas/LibraryChangedMessage", + "KeepAlive": "#/components/schemas/OutboundKeepAliveMessage", + "Play": "#/components/schemas/PlayMessage", + "Playstate": "#/components/schemas/PlaystateMessage", + "PackageInstallationCancelled": "#/components/schemas/PluginInstallationCancelledMessage", + "PackageInstallationCompleted": "#/components/schemas/PluginInstallationCompletedMessage", + "PackageInstallationFailed": "#/components/schemas/PluginInstallationFailedMessage", + "PackageInstalling": "#/components/schemas/PluginInstallingMessage", + "PackageUninstalled": "#/components/schemas/PluginUninstalledMessage", + "RefreshProgress": "#/components/schemas/RefreshProgressMessage", + "RestartRequired": "#/components/schemas/RestartRequiredMessage", + "ScheduledTaskEnded": "#/components/schemas/ScheduledTaskEndedMessage", + "ScheduledTasksInfo": "#/components/schemas/ScheduledTasksInfoMessage", + "SeriesTimerCancelled": "#/components/schemas/SeriesTimerCancelledMessage", + "SeriesTimerCreated": "#/components/schemas/SeriesTimerCreatedMessage", + "ServerRestarting": "#/components/schemas/ServerRestartingMessage", + "ServerShuttingDown": "#/components/schemas/ServerShuttingDownMessage", + "Sessions": "#/components/schemas/SessionsMessage", + "SyncPlayCommand": "#/components/schemas/SyncPlayCommandMessage", + "SyncPlayGroupUpdate": "#/components/schemas/SyncPlayGroupUpdateCommandMessage", + "TimerCancelled": "#/components/schemas/TimerCancelledMessage", + "TimerCreated": "#/components/schemas/TimerCreatedMessage", + "UserDataChanged": "#/components/schemas/UserDataChangedMessage", + "UserDeleted": "#/components/schemas/UserDeletedMessage", + "UserUpdated": "#/components/schemas/UserUpdatedMessage" + } + } + }, + "PackageInfo": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Gets or sets the name." + }, + "description": { + "type": "string", + "description": "Gets or sets a long description of the plugin containing features or helpful explanations." + }, + "overview": { + "type": "string", + "description": "Gets or sets a short overview of what the plugin does." + }, + "owner": { + "type": "string", + "description": "Gets or sets the owner." + }, + "category": { + "type": "string", + "description": "Gets or sets the category." + }, + "guid": { + "type": "string", + "description": "Gets or sets the guid of the assembly associated with this plugin.\r\nThis is used to identify the proper item for automatic updates.", + "format": "uuid" + }, + "versions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VersionInfo" + }, + "description": "Gets or sets the versions." + }, + "imageUrl": { + "type": "string", + "description": "Gets or sets the image url for the package.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class PackageInfo." + }, + "ParentalRating": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + }, + "Value": { + "type": "integer", + "description": "Gets or sets the value.", + "format": "int32", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class ParentalRating." + }, + "PathSubstitution": { + "type": "object", + "properties": { + "From": { + "type": "string", + "description": "Gets or sets the value to substitute." + }, + "To": { + "type": "string", + "description": "Gets or sets the value to substitution with." + } + }, + "additionalProperties": false, + "description": "Defines the MediaBrowser.Model.Configuration.PathSubstitution." + }, + "PersonKind": { + "enum": [ + "Unknown", + "Actor", + "Director", + "Composer", + "Writer", + "GuestStar", + "Producer", + "Conductor", + "Lyricist", + "Arranger", + "Engineer", + "Mixer", + "Remixer", + "Creator", + "Artist", + "AlbumArtist", + "Author", + "Illustrator", + "Penciller", + "Inker", + "Colorist", + "Letterer", + "CoverArtist", + "Editor", + "Translator" + ], + "type": "string", + "description": "The person kind." + }, + "PersonLookupInfo": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + }, + "OriginalTitle": { + "type": "string", + "description": "Gets or sets the original title.", + "nullable": true + }, + "Path": { + "type": "string", + "description": "Gets or sets the path.", + "nullable": true + }, + "MetadataLanguage": { + "type": "string", + "description": "Gets or sets the metadata language.", + "nullable": true + }, + "MetadataCountryCode": { + "type": "string", + "description": "Gets or sets the metadata country code.", + "nullable": true + }, + "ProviderIds": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "description": "Gets or sets the provider ids.", + "nullable": true + }, + "Year": { + "type": "integer", + "description": "Gets or sets the year.", + "format": "int32", + "nullable": true + }, + "IndexNumber": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "ParentIndexNumber": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "PremiereDate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "IsAutomated": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "PersonLookupInfoRemoteSearchQuery": { + "type": "object", + "properties": { + "SearchInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/PersonLookupInfo" + } + ], + "nullable": true + }, + "ItemId": { + "type": "string", + "format": "uuid" + }, + "SearchProviderName": { + "type": "string", + "description": "Gets or sets the provider name to search within if set.", + "nullable": true + }, + "IncludeDisabledProviders": { + "type": "boolean", + "description": "Gets or sets a value indicating whether disabled providers should be included." + } + }, + "additionalProperties": false + }, + "PingRequestDto": { + "type": "object", + "properties": { + "Ping": { + "type": "integer", + "description": "Gets or sets the ping time.", + "format": "int64" + } + }, + "additionalProperties": false, + "description": "Class PingRequestDto." + }, + "PinRedeemResult": { + "type": "object", + "properties": { + "Success": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this MediaBrowser.Model.Users.PinRedeemResult is success." + }, + "UsersReset": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the users reset." + } + }, + "additionalProperties": false + }, + "PlayAccess": { + "enum": ["Full", "None"], + "type": "string" + }, + "PlaybackErrorCode": { + "enum": ["NotAllowed", "NoCompatibleStream", "RateLimitExceeded"], + "type": "string" + }, + "PlaybackInfoDto": { + "type": "object", + "properties": { + "UserId": { + "type": "string", + "description": "Gets or sets the playback userId.", + "format": "uuid", + "nullable": true + }, + "MaxStreamingBitrate": { + "type": "integer", + "description": "Gets or sets the max streaming bitrate.", + "format": "int32", + "nullable": true + }, + "StartTimeTicks": { + "type": "integer", + "description": "Gets or sets the start time in ticks.", + "format": "int64", + "nullable": true + }, + "AudioStreamIndex": { + "type": "integer", + "description": "Gets or sets the audio stream index.", + "format": "int32", + "nullable": true + }, + "SubtitleStreamIndex": { + "type": "integer", + "description": "Gets or sets the subtitle stream index.", + "format": "int32", + "nullable": true + }, + "MaxAudioChannels": { + "type": "integer", + "description": "Gets or sets the max audio channels.", + "format": "int32", + "nullable": true + }, + "MediaSourceId": { + "type": "string", + "description": "Gets or sets the media source id.", + "nullable": true + }, + "LiveStreamId": { + "type": "string", + "description": "Gets or sets the live stream id.", + "nullable": true + }, + "DeviceProfile": { + "allOf": [ + { + "$ref": "#/components/schemas/DeviceProfile" + } + ], + "description": "Gets or sets the device profile.", + "nullable": true + }, + "EnableDirectPlay": { + "type": "boolean", + "description": "Gets or sets a value indicating whether to enable direct play.", + "nullable": true + }, + "EnableDirectStream": { + "type": "boolean", + "description": "Gets or sets a value indicating whether to enable direct stream.", + "nullable": true + }, + "EnableTranscoding": { + "type": "boolean", + "description": "Gets or sets a value indicating whether to enable transcoding.", + "nullable": true + }, + "AllowVideoStreamCopy": { + "type": "boolean", + "description": "Gets or sets a value indicating whether to enable video stream copy.", + "nullable": true + }, + "AllowAudioStreamCopy": { + "type": "boolean", + "description": "Gets or sets a value indicating whether to allow audio stream copy.", + "nullable": true + }, + "AutoOpenLiveStream": { + "type": "boolean", + "description": "Gets or sets a value indicating whether to auto open the live stream.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Plabyback info dto." + }, + "PlaybackInfoResponse": { + "type": "object", + "properties": { + "MediaSources": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MediaSourceInfo" + }, + "description": "Gets or sets the media sources." + }, + "PlaySessionId": { + "type": "string", + "description": "Gets or sets the play session identifier.", + "nullable": true + }, + "ErrorCode": { + "enum": ["NotAllowed", "NoCompatibleStream", "RateLimitExceeded"], + "allOf": [ + { + "$ref": "#/components/schemas/PlaybackErrorCode" + } + ], + "description": "Gets or sets the error code.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class PlaybackInfoResponse." + }, + "PlaybackOrder": { + "enum": ["Default", "Shuffle"], + "type": "string", + "description": "Enum PlaybackOrder." + }, + "PlaybackProgressInfo": { + "type": "object", + "properties": { + "CanSeek": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance can seek." + }, + "Item": { + "allOf": [ + { + "$ref": "#/components/schemas/BaseItemDto" + } + ], + "description": "Gets or sets the item.", + "nullable": true + }, + "ItemId": { + "type": "string", + "description": "Gets or sets the item identifier.", + "format": "uuid" + }, + "SessionId": { + "type": "string", + "description": "Gets or sets the session id.", + "nullable": true + }, + "MediaSourceId": { + "type": "string", + "description": "Gets or sets the media version identifier.", + "nullable": true + }, + "AudioStreamIndex": { + "type": "integer", + "description": "Gets or sets the index of the audio stream.", + "format": "int32", + "nullable": true + }, + "SubtitleStreamIndex": { + "type": "integer", + "description": "Gets or sets the index of the subtitle stream.", + "format": "int32", + "nullable": true + }, + "IsPaused": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is paused." + }, + "IsMuted": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is muted." + }, + "PositionTicks": { + "type": "integer", + "description": "Gets or sets the position ticks.", + "format": "int64", + "nullable": true + }, + "PlaybackStartTimeTicks": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "VolumeLevel": { + "type": "integer", + "description": "Gets or sets the volume level.", + "format": "int32", + "nullable": true + }, + "Brightness": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "AspectRatio": { + "type": "string", + "nullable": true + }, + "PlayMethod": { + "enum": ["Transcode", "DirectStream", "DirectPlay"], + "allOf": [ + { + "$ref": "#/components/schemas/PlayMethod" + } + ], + "description": "Gets or sets the play method." + }, + "LiveStreamId": { + "type": "string", + "description": "Gets or sets the live stream identifier.", + "nullable": true + }, + "PlaySessionId": { + "type": "string", + "description": "Gets or sets the play session identifier.", + "nullable": true + }, + "RepeatMode": { + "enum": ["RepeatNone", "RepeatAll", "RepeatOne"], + "allOf": [ + { + "$ref": "#/components/schemas/RepeatMode" + } + ], + "description": "Gets or sets the repeat mode." + }, + "PlaybackOrder": { + "enum": ["Default", "Shuffle"], + "allOf": [ + { + "$ref": "#/components/schemas/PlaybackOrder" + } + ], + "description": "Gets or sets the playback order." + }, + "NowPlayingQueue": { + "type": "array", + "items": { + "$ref": "#/components/schemas/QueueItem" + }, + "nullable": true + }, + "PlaylistItemId": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class PlaybackProgressInfo." + }, + "PlaybackRequestType": { + "enum": [ + "Play", + "SetPlaylistItem", + "RemoveFromPlaylist", + "MovePlaylistItem", + "Queue", + "Unpause", + "Pause", + "Stop", + "Seek", + "Buffer", + "Ready", + "NextItem", + "PreviousItem", + "SetRepeatMode", + "SetShuffleMode", + "Ping", + "IgnoreWait" + ], + "type": "string", + "description": "Enum PlaybackRequestType." + }, + "PlaybackStartInfo": { + "type": "object", + "properties": { + "CanSeek": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance can seek." + }, + "Item": { + "allOf": [ + { + "$ref": "#/components/schemas/BaseItemDto" + } + ], + "description": "Gets or sets the item.", + "nullable": true + }, + "ItemId": { + "type": "string", + "description": "Gets or sets the item identifier.", + "format": "uuid" + }, + "SessionId": { + "type": "string", + "description": "Gets or sets the session id.", + "nullable": true + }, + "MediaSourceId": { + "type": "string", + "description": "Gets or sets the media version identifier.", + "nullable": true + }, + "AudioStreamIndex": { + "type": "integer", + "description": "Gets or sets the index of the audio stream.", + "format": "int32", + "nullable": true + }, + "SubtitleStreamIndex": { + "type": "integer", + "description": "Gets or sets the index of the subtitle stream.", + "format": "int32", + "nullable": true + }, + "IsPaused": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is paused." + }, + "IsMuted": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is muted." + }, + "PositionTicks": { + "type": "integer", + "description": "Gets or sets the position ticks.", + "format": "int64", + "nullable": true + }, + "PlaybackStartTimeTicks": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "VolumeLevel": { + "type": "integer", + "description": "Gets or sets the volume level.", + "format": "int32", + "nullable": true + }, + "Brightness": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "AspectRatio": { + "type": "string", + "nullable": true + }, + "PlayMethod": { + "enum": ["Transcode", "DirectStream", "DirectPlay"], + "allOf": [ + { + "$ref": "#/components/schemas/PlayMethod" + } + ], + "description": "Gets or sets the play method." + }, + "LiveStreamId": { + "type": "string", + "description": "Gets or sets the live stream identifier.", + "nullable": true + }, + "PlaySessionId": { + "type": "string", + "description": "Gets or sets the play session identifier.", + "nullable": true + }, + "RepeatMode": { + "enum": ["RepeatNone", "RepeatAll", "RepeatOne"], + "allOf": [ + { + "$ref": "#/components/schemas/RepeatMode" + } + ], + "description": "Gets or sets the repeat mode." + }, + "PlaybackOrder": { + "enum": ["Default", "Shuffle"], + "allOf": [ + { + "$ref": "#/components/schemas/PlaybackOrder" + } + ], + "description": "Gets or sets the playback order." + }, + "NowPlayingQueue": { + "type": "array", + "items": { + "$ref": "#/components/schemas/QueueItem" + }, + "nullable": true + }, + "PlaylistItemId": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class PlaybackStartInfo." + }, + "PlaybackStopInfo": { + "type": "object", + "properties": { + "Item": { + "allOf": [ + { + "$ref": "#/components/schemas/BaseItemDto" + } + ], + "description": "Gets or sets the item.", + "nullable": true + }, + "ItemId": { + "type": "string", + "description": "Gets or sets the item identifier.", + "format": "uuid" + }, + "SessionId": { + "type": "string", + "description": "Gets or sets the session id.", + "nullable": true + }, + "MediaSourceId": { + "type": "string", + "description": "Gets or sets the media version identifier.", + "nullable": true + }, + "PositionTicks": { + "type": "integer", + "description": "Gets or sets the position ticks.", + "format": "int64", + "nullable": true + }, + "LiveStreamId": { + "type": "string", + "description": "Gets or sets the live stream identifier.", + "nullable": true + }, + "PlaySessionId": { + "type": "string", + "description": "Gets or sets the play session identifier.", + "nullable": true + }, + "Failed": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this MediaBrowser.Model.Session.PlaybackStopInfo is failed." + }, + "NextMediaType": { + "type": "string", + "nullable": true + }, + "PlaylistItemId": { + "type": "string", + "nullable": true + }, + "NowPlayingQueue": { + "type": "array", + "items": { + "$ref": "#/components/schemas/QueueItem" + }, + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class PlaybackStopInfo." + }, + "PlayCommand": { + "enum": [ + "PlayNow", + "PlayNext", + "PlayLast", + "PlayInstantMix", + "PlayShuffle" + ], + "type": "string", + "description": "Enum PlayCommand." + }, + "PlayerStateInfo": { + "type": "object", + "properties": { + "PositionTicks": { + "type": "integer", + "description": "Gets or sets the now playing position ticks.", + "format": "int64", + "nullable": true + }, + "CanSeek": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance can seek." + }, + "IsPaused": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is paused." + }, + "IsMuted": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is muted." + }, + "VolumeLevel": { + "type": "integer", + "description": "Gets or sets the volume level.", + "format": "int32", + "nullable": true + }, + "AudioStreamIndex": { + "type": "integer", + "description": "Gets or sets the index of the now playing audio stream.", + "format": "int32", + "nullable": true + }, + "SubtitleStreamIndex": { + "type": "integer", + "description": "Gets or sets the index of the now playing subtitle stream.", + "format": "int32", + "nullable": true + }, + "MediaSourceId": { + "type": "string", + "description": "Gets or sets the now playing media version identifier.", + "nullable": true + }, + "PlayMethod": { + "enum": ["Transcode", "DirectStream", "DirectPlay"], + "allOf": [ + { + "$ref": "#/components/schemas/PlayMethod" + } + ], + "description": "Gets or sets the play method.", + "nullable": true + }, + "RepeatMode": { + "enum": ["RepeatNone", "RepeatAll", "RepeatOne"], + "allOf": [ + { + "$ref": "#/components/schemas/RepeatMode" + } + ], + "description": "Gets or sets the repeat mode." + }, + "PlaybackOrder": { + "enum": ["Default", "Shuffle"], + "allOf": [ + { + "$ref": "#/components/schemas/PlaybackOrder" + } + ], + "description": "Gets or sets the playback order." + }, + "LiveStreamId": { + "type": "string", + "description": "Gets or sets the now playing live stream identifier.", + "nullable": true + } + }, + "additionalProperties": false + }, + "PlaylistCreationResult": { + "type": "object", + "properties": { + "Id": { + "type": "string" + } + }, + "additionalProperties": false + }, + "PlaylistUserPermissions": { + "type": "object", + "properties": { + "UserId": { + "type": "string", + "description": "Gets or sets the user id.", + "format": "uuid" + }, + "CanEdit": { + "type": "boolean", + "description": "Gets or sets a value indicating whether the user has edit permissions." + } + }, + "additionalProperties": false, + "description": "Class to hold data on user permissions for playlists." + }, + "PlayMessage": { + "type": "object", + "properties": { + "Data": { + "allOf": [ + { + "$ref": "#/components/schemas/PlayRequest" + } + ], + "description": "Gets or sets the data.", + "nullable": true + }, + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "Play", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Play command websocket message." + }, + "PlayMethod": { + "enum": ["Transcode", "DirectStream", "DirectPlay"], + "type": "string" + }, + "PlayQueueUpdate": { + "type": "object", + "properties": { + "Reason": { + "enum": [ + "NewPlaylist", + "SetCurrentItem", + "RemoveItems", + "MoveItem", + "Queue", + "QueueNext", + "NextItem", + "PreviousItem", + "RepeatMode", + "ShuffleMode" + ], + "allOf": [ + { + "$ref": "#/components/schemas/PlayQueueUpdateReason" + } + ], + "description": "Gets the request type that originated this update." + }, + "LastUpdate": { + "type": "string", + "description": "Gets the UTC time of the last change to the playing queue.", + "format": "date-time" + }, + "Playlist": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SyncPlayQueueItem" + }, + "description": "Gets the playlist." + }, + "PlayingItemIndex": { + "type": "integer", + "description": "Gets the playing item index in the playlist.", + "format": "int32" + }, + "StartPositionTicks": { + "type": "integer", + "description": "Gets the start position ticks.", + "format": "int64" + }, + "IsPlaying": { + "type": "boolean", + "description": "Gets a value indicating whether the current item is playing." + }, + "ShuffleMode": { + "enum": ["Sorted", "Shuffle"], + "allOf": [ + { + "$ref": "#/components/schemas/GroupShuffleMode" + } + ], + "description": "Gets the shuffle mode." + }, + "RepeatMode": { + "enum": ["RepeatOne", "RepeatAll", "RepeatNone"], + "allOf": [ + { + "$ref": "#/components/schemas/GroupRepeatMode" + } + ], + "description": "Gets the repeat mode." + } + }, + "additionalProperties": false, + "description": "Class PlayQueueUpdate." + }, + "PlayQueueUpdateGroupUpdate": { + "type": "object", + "properties": { + "GroupId": { + "type": "string", + "description": "Gets the group identifier.", + "format": "uuid", + "readOnly": true + }, + "Type": { + "enum": [ + "UserJoined", + "UserLeft", + "GroupJoined", + "GroupLeft", + "StateUpdate", + "PlayQueue", + "NotInGroup", + "GroupDoesNotExist", + "CreateGroupDenied", + "JoinGroupDenied", + "LibraryAccessDenied" + ], + "allOf": [ + { + "$ref": "#/components/schemas/GroupUpdateType" + } + ], + "description": "Gets the update type." + }, + "Data": { + "allOf": [ + { + "$ref": "#/components/schemas/PlayQueueUpdate" + } + ], + "description": "Gets the update data." + } + }, + "additionalProperties": false, + "description": "Class GroupUpdate." + }, + "PlayQueueUpdateReason": { + "enum": [ + "NewPlaylist", + "SetCurrentItem", + "RemoveItems", + "MoveItem", + "Queue", + "QueueNext", + "NextItem", + "PreviousItem", + "RepeatMode", + "ShuffleMode" + ], + "type": "string", + "description": "Enum PlayQueueUpdateReason." + }, + "PlayRequest": { + "type": "object", + "properties": { + "ItemIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "description": "Gets or sets the item ids.", + "nullable": true + }, + "StartPositionTicks": { + "type": "integer", + "description": "Gets or sets the start position ticks that the first item should be played at.", + "format": "int64", + "nullable": true + }, + "PlayCommand": { + "enum": [ + "PlayNow", + "PlayNext", + "PlayLast", + "PlayInstantMix", + "PlayShuffle" + ], + "allOf": [ + { + "$ref": "#/components/schemas/PlayCommand" + } + ], + "description": "Gets or sets the play command." + }, + "ControllingUserId": { + "type": "string", + "description": "Gets or sets the controlling user identifier.", + "format": "uuid" + }, + "SubtitleStreamIndex": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "AudioStreamIndex": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "MediaSourceId": { + "type": "string", + "nullable": true + }, + "StartIndex": { + "type": "integer", + "format": "int32", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class PlayRequest." + }, + "PlayRequestDto": { + "type": "object", + "properties": { + "PlayingQueue": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "description": "Gets or sets the playing queue." + }, + "PlayingItemPosition": { + "type": "integer", + "description": "Gets or sets the position of the playing item in the queue.", + "format": "int32" + }, + "StartPositionTicks": { + "type": "integer", + "description": "Gets or sets the start position ticks.", + "format": "int64" + } + }, + "additionalProperties": false, + "description": "Class PlayRequestDto." + }, + "PlaystateCommand": { + "enum": [ + "Stop", + "Pause", + "Unpause", + "NextTrack", + "PreviousTrack", + "Seek", + "Rewind", + "FastForward", + "PlayPause" + ], + "type": "string", + "description": "Enum PlaystateCommand." + }, + "PlaystateMessage": { + "type": "object", + "properties": { + "Data": { + "allOf": [ + { + "$ref": "#/components/schemas/PlaystateRequest" + } + ], + "description": "Gets or sets the data.", + "nullable": true + }, + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "Playstate", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Playstate message." + }, + "PlaystateRequest": { + "type": "object", + "properties": { + "Command": { + "enum": [ + "Stop", + "Pause", + "Unpause", + "NextTrack", + "PreviousTrack", + "Seek", + "Rewind", + "FastForward", + "PlayPause" + ], + "allOf": [ + { + "$ref": "#/components/schemas/PlaystateCommand" + } + ], + "description": "Enum PlaystateCommand." + }, + "SeekPositionTicks": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "ControllingUserId": { + "type": "string", + "description": "Gets or sets the controlling user identifier.", + "nullable": true + } + }, + "additionalProperties": false + }, + "PluginInfo": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name." + }, + "Version": { + "type": "string", + "description": "Gets or sets the version." + }, + "ConfigurationFileName": { + "type": "string", + "description": "Gets or sets the name of the configuration file.", + "nullable": true + }, + "Description": { + "type": "string", + "description": "Gets or sets the description." + }, + "Id": { + "type": "string", + "description": "Gets or sets the unique id.", + "format": "uuid" + }, + "CanUninstall": { + "type": "boolean", + "description": "Gets or sets a value indicating whether the plugin can be uninstalled." + }, + "HasImage": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this plugin has a valid image." + }, + "Status": { + "enum": [ + "Active", + "Restart", + "Deleted", + "Superceded", + "Malfunctioned", + "NotSupported", + "Disabled" + ], + "allOf": [ + { + "$ref": "#/components/schemas/PluginStatus" + } + ], + "description": "Gets or sets a value indicating the status of the plugin." + } + }, + "additionalProperties": false, + "description": "This is a serializable stub class that is used by the api to provide information about installed plugins." + }, + "PluginInstallationCancelledMessage": { + "type": "object", + "properties": { + "Data": { + "allOf": [ + { + "$ref": "#/components/schemas/InstallationInfo" + } + ], + "description": "Gets or sets the data.", + "nullable": true + }, + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "PackageInstallationCancelled", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Plugin installation cancelled message." + }, + "PluginInstallationCompletedMessage": { + "type": "object", + "properties": { + "Data": { + "allOf": [ + { + "$ref": "#/components/schemas/InstallationInfo" + } + ], + "description": "Gets or sets the data.", + "nullable": true + }, + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "PackageInstallationCompleted", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Plugin installation completed message." + }, + "PluginInstallationFailedMessage": { + "type": "object", + "properties": { + "Data": { + "allOf": [ + { + "$ref": "#/components/schemas/InstallationInfo" + } + ], + "description": "Gets or sets the data.", + "nullable": true + }, + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "PackageInstallationFailed", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Plugin installation failed message." + }, + "PluginInstallingMessage": { + "type": "object", + "properties": { + "Data": { + "allOf": [ + { + "$ref": "#/components/schemas/InstallationInfo" + } + ], + "description": "Gets or sets the data.", + "nullable": true + }, + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "PackageInstalling", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Package installing message." + }, + "PluginStatus": { + "enum": [ + "Active", + "Restart", + "Deleted", + "Superceded", + "Malfunctioned", + "NotSupported", + "Disabled" + ], + "type": "string", + "description": "Plugin load status." + }, + "PluginUninstalledMessage": { + "type": "object", + "properties": { + "Data": { + "allOf": [ + { + "$ref": "#/components/schemas/PluginInfo" + } + ], + "description": "Gets or sets the data.", + "nullable": true + }, + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "PackageUninstalled", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Plugin uninstalled message." + }, + "PreviousItemRequestDto": { + "type": "object", + "properties": { + "PlaylistItemId": { + "type": "string", + "description": "Gets or sets the playing item identifier.", + "format": "uuid" + } + }, + "additionalProperties": false, + "description": "Class PreviousItemRequestDto." + }, + "ProblemDetails": { + "type": "object", + "properties": { + "type": { + "type": "string", + "nullable": true + }, + "title": { + "type": "string", + "nullable": true + }, + "status": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "detail": { + "type": "string", + "nullable": true + }, + "instance": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": {} + }, + "ProcessPriorityClass": { + "enum": [ + "Normal", + "Idle", + "High", + "RealTime", + "BelowNormal", + "AboveNormal" + ], + "type": "string" + }, + "ProfileCondition": { + "type": "object", + "properties": { + "Condition": { + "enum": [ + "Equals", + "NotEquals", + "LessThanEqual", + "GreaterThanEqual", + "EqualsAny" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ProfileConditionType" + } + ] + }, + "Property": { + "enum": [ + "AudioChannels", + "AudioBitrate", + "AudioProfile", + "Width", + "Height", + "Has64BitOffsets", + "PacketLength", + "VideoBitDepth", + "VideoBitrate", + "VideoFramerate", + "VideoLevel", + "VideoProfile", + "VideoTimestamp", + "IsAnamorphic", + "RefFrames", + "NumAudioStreams", + "NumVideoStreams", + "IsSecondaryAudio", + "VideoCodecTag", + "IsAvc", + "IsInterlaced", + "AudioSampleRate", + "AudioBitDepth", + "VideoRangeType" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ProfileConditionValue" + } + ] + }, + "Value": { + "type": "string", + "nullable": true + }, + "IsRequired": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "ProfileConditionType": { + "enum": [ + "Equals", + "NotEquals", + "LessThanEqual", + "GreaterThanEqual", + "EqualsAny" + ], + "type": "string" + }, + "ProfileConditionValue": { + "enum": [ + "AudioChannels", + "AudioBitrate", + "AudioProfile", + "Width", + "Height", + "Has64BitOffsets", + "PacketLength", + "VideoBitDepth", + "VideoBitrate", + "VideoFramerate", + "VideoLevel", + "VideoProfile", + "VideoTimestamp", + "IsAnamorphic", + "RefFrames", + "NumAudioStreams", + "NumVideoStreams", + "IsSecondaryAudio", + "VideoCodecTag", + "IsAvc", + "IsInterlaced", + "AudioSampleRate", + "AudioBitDepth", + "VideoRangeType" + ], + "type": "string" + }, + "ProgramAudio": { + "enum": ["Mono", "Stereo", "Dolby", "DolbyDigital", "Thx", "Atmos"], + "type": "string" + }, + "PublicSystemInfo": { + "type": "object", + "properties": { + "LocalAddress": { + "type": "string", + "description": "Gets or sets the local address.", + "nullable": true + }, + "ServerName": { + "type": "string", + "description": "Gets or sets the name of the server.", + "nullable": true + }, + "Version": { + "type": "string", + "description": "Gets or sets the server version.", + "nullable": true + }, + "ProductName": { + "type": "string", + "description": "Gets or sets the product name. This is the AssemblyProduct name.", + "nullable": true + }, + "OperatingSystem": { + "type": "string", + "description": "Gets or sets the operating system.", + "nullable": true, + "deprecated": true + }, + "Id": { + "type": "string", + "description": "Gets or sets the id.", + "nullable": true + }, + "StartupWizardCompleted": { + "type": "boolean", + "description": "Gets or sets a value indicating whether the startup wizard is completed.", + "nullable": true + } + }, + "additionalProperties": false + }, + "QueryFilters": { + "type": "object", + "properties": { + "Genres": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NameGuidPair" + }, + "nullable": true + }, + "Tags": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "QueryFiltersLegacy": { + "type": "object", + "properties": { + "Genres": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "Tags": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "OfficialRatings": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "Years": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "QueueItem": { + "type": "object", + "properties": { + "Id": { + "type": "string", + "format": "uuid" + }, + "PlaylistItemId": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "QueueRequestDto": { + "type": "object", + "properties": { + "ItemIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "description": "Gets or sets the items to enqueue." + }, + "Mode": { + "enum": ["Queue", "QueueNext"], + "allOf": [ + { + "$ref": "#/components/schemas/GroupQueueMode" + } + ], + "description": "Gets or sets the mode in which to add the new items." + } + }, + "additionalProperties": false, + "description": "Class QueueRequestDto." + }, + "QuickConnectDto": { + "required": ["Secret"], + "type": "object", + "properties": { + "Secret": { + "type": "string", + "description": "Gets or sets the quick connect secret." + } + }, + "additionalProperties": false, + "description": "The quick connect request body." + }, + "QuickConnectResult": { + "type": "object", + "properties": { + "Authenticated": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this request is authorized." + }, + "Secret": { + "type": "string", + "description": "Gets the secret value used to uniquely identify this request. Can be used to retrieve authentication information." + }, + "Code": { + "type": "string", + "description": "Gets the user facing code used so the user can quickly differentiate this request from others." + }, + "DeviceId": { + "type": "string", + "description": "Gets the requesting device id." + }, + "DeviceName": { + "type": "string", + "description": "Gets the requesting device name." + }, + "AppName": { + "type": "string", + "description": "Gets the requesting app name." + }, + "AppVersion": { + "type": "string", + "description": "Gets the requesting app version." + }, + "DateAdded": { + "type": "string", + "description": "Gets or sets the DateTime that this request was created.", + "format": "date-time" + } + }, + "additionalProperties": false, + "description": "Stores the state of an quick connect request." + }, + "RatingType": { + "enum": ["Score", "Likes"], + "type": "string" + }, + "ReadyRequestDto": { + "type": "object", + "properties": { + "When": { + "type": "string", + "description": "Gets or sets when the request has been made by the client.", + "format": "date-time" + }, + "PositionTicks": { + "type": "integer", + "description": "Gets or sets the position ticks.", + "format": "int64" + }, + "IsPlaying": { + "type": "boolean", + "description": "Gets or sets a value indicating whether the client playback is unpaused." + }, + "PlaylistItemId": { + "type": "string", + "description": "Gets or sets the playlist item identifier of the playing item.", + "format": "uuid" + } + }, + "additionalProperties": false, + "description": "Class ReadyRequest." + }, + "RecommendationDto": { + "type": "object", + "properties": { + "Items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemDto" + }, + "nullable": true + }, + "RecommendationType": { + "enum": [ + "SimilarToRecentlyPlayed", + "SimilarToLikedItem", + "HasDirectorFromRecentlyPlayed", + "HasActorFromRecentlyPlayed", + "HasLikedDirector", + "HasLikedActor" + ], + "allOf": [ + { + "$ref": "#/components/schemas/RecommendationType" + } + ] + }, + "BaselineItemName": { + "type": "string", + "nullable": true + }, + "CategoryId": { + "type": "string", + "format": "uuid" + } + }, + "additionalProperties": false + }, + "RecommendationType": { + "enum": [ + "SimilarToRecentlyPlayed", + "SimilarToLikedItem", + "HasDirectorFromRecentlyPlayed", + "HasActorFromRecentlyPlayed", + "HasLikedDirector", + "HasLikedActor" + ], + "type": "string" + }, + "RecordingStatus": { + "enum": [ + "New", + "InProgress", + "Completed", + "Cancelled", + "ConflictedOk", + "ConflictedNotOk", + "Error" + ], + "type": "string" + }, + "RefreshProgressMessage": { + "type": "object", + "properties": { + "Data": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "description": "Gets or sets the data.", + "nullable": true + }, + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "RefreshProgress", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Refresh progress message." + }, + "RemoteImageInfo": { + "type": "object", + "properties": { + "ProviderName": { + "type": "string", + "description": "Gets or sets the name of the provider.", + "nullable": true + }, + "Url": { + "type": "string", + "description": "Gets or sets the URL.", + "nullable": true + }, + "ThumbnailUrl": { + "type": "string", + "description": "Gets or sets a url used for previewing a smaller version.", + "nullable": true + }, + "Height": { + "type": "integer", + "description": "Gets or sets the height.", + "format": "int32", + "nullable": true + }, + "Width": { + "type": "integer", + "description": "Gets or sets the width.", + "format": "int32", + "nullable": true + }, + "CommunityRating": { + "type": "number", + "description": "Gets or sets the community rating.", + "format": "double", + "nullable": true + }, + "VoteCount": { + "type": "integer", + "description": "Gets or sets the vote count.", + "format": "int32", + "nullable": true + }, + "Language": { + "type": "string", + "description": "Gets or sets the language.", + "nullable": true + }, + "Type": { + "enum": [ + "Primary", + "Art", + "Backdrop", + "Banner", + "Logo", + "Thumb", + "Disc", + "Box", + "Screenshot", + "Menu", + "Chapter", + "BoxRear", + "Profile" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageType" + } + ], + "description": "Gets or sets the type." + }, + "RatingType": { + "enum": ["Score", "Likes"], + "allOf": [ + { + "$ref": "#/components/schemas/RatingType" + } + ], + "description": "Gets or sets the type of the rating." + } + }, + "additionalProperties": false, + "description": "Class RemoteImageInfo." + }, + "RemoteImageResult": { + "type": "object", + "properties": { + "Images": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteImageInfo" + }, + "description": "Gets or sets the images.", + "nullable": true + }, + "TotalRecordCount": { + "type": "integer", + "description": "Gets or sets the total record count.", + "format": "int32" + }, + "Providers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the providers.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class RemoteImageResult." + }, + "RemoteLyricInfoDto": { + "type": "object", + "properties": { + "Id": { + "type": "string", + "description": "Gets or sets the id for the lyric." + }, + "ProviderName": { + "type": "string", + "description": "Gets the provider name." + }, + "Lyrics": { + "allOf": [ + { + "$ref": "#/components/schemas/LyricDto" + } + ], + "description": "Gets the lyrics." + } + }, + "additionalProperties": false, + "description": "The remote lyric info dto." + }, + "RemoteSearchResult": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + }, + "ProviderIds": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "description": "Gets or sets the provider ids.", + "nullable": true + }, + "ProductionYear": { + "type": "integer", + "description": "Gets or sets the year.", + "format": "int32", + "nullable": true + }, + "IndexNumber": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "IndexNumberEnd": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "ParentIndexNumber": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "PremiereDate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "ImageUrl": { + "type": "string", + "nullable": true + }, + "SearchProviderName": { + "type": "string", + "nullable": true + }, + "Overview": { + "type": "string", + "nullable": true + }, + "AlbumArtist": { + "allOf": [ + { + "$ref": "#/components/schemas/RemoteSearchResult" + } + ], + "nullable": true + }, + "Artists": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RemoteSearchResult" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "RemoteSubtitleInfo": { + "type": "object", + "properties": { + "ThreeLetterISOLanguageName": { + "type": "string", + "nullable": true + }, + "Id": { + "type": "string", + "nullable": true + }, + "ProviderName": { + "type": "string", + "nullable": true + }, + "Name": { + "type": "string", + "nullable": true + }, + "Format": { + "type": "string", + "nullable": true + }, + "Author": { + "type": "string", + "nullable": true + }, + "Comment": { + "type": "string", + "nullable": true + }, + "DateCreated": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "CommunityRating": { + "type": "number", + "format": "float", + "nullable": true + }, + "FrameRate": { + "type": "number", + "format": "float", + "nullable": true + }, + "DownloadCount": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "IsHashMatch": { + "type": "boolean", + "nullable": true + }, + "AiTranslated": { + "type": "boolean", + "nullable": true + }, + "MachineTranslated": { + "type": "boolean", + "nullable": true + }, + "Forced": { + "type": "boolean", + "nullable": true + }, + "HearingImpaired": { + "type": "boolean", + "nullable": true + } + }, + "additionalProperties": false + }, + "RemoveFromPlaylistRequestDto": { + "type": "object", + "properties": { + "PlaylistItemIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "description": "Gets or sets the playlist identifiers of the items. Ignored when clearing the playlist." + }, + "ClearPlaylist": { + "type": "boolean", + "description": "Gets or sets a value indicating whether the entire playlist should be cleared." + }, + "ClearPlayingItem": { + "type": "boolean", + "description": "Gets or sets a value indicating whether the playing item should be removed as well. Used only when clearing the playlist." + } + }, + "additionalProperties": false, + "description": "Class RemoveFromPlaylistRequestDto." + }, + "RepeatMode": { + "enum": ["RepeatNone", "RepeatAll", "RepeatOne"], + "type": "string" + }, + "ReportPlaybackOptions": { + "type": "object", + "properties": { + "MaxDataAge": { + "type": "integer", + "format": "int32" + }, + "BackupPath": { + "type": "string" + }, + "MaxBackupFiles": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "RepositoryInfo": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + }, + "Url": { + "type": "string", + "description": "Gets or sets the URL.", + "nullable": true + }, + "Enabled": { + "type": "boolean", + "description": "Gets or sets a value indicating whether the repository is enabled." + } + }, + "additionalProperties": false, + "description": "Class RepositoryInfo." + }, + "RestartRequiredMessage": { + "type": "object", + "properties": { + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "RestartRequired", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Restart required." + }, + "ScheduledTaskEndedMessage": { + "type": "object", + "properties": { + "Data": { + "allOf": [ + { + "$ref": "#/components/schemas/TaskResult" + } + ], + "description": "Gets or sets the data.", + "nullable": true + }, + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "ScheduledTaskEnded", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Scheduled task ended message." + }, + "ScheduledTasksInfoMessage": { + "type": "object", + "properties": { + "Data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TaskInfo" + }, + "description": "Gets or sets the data.", + "nullable": true + }, + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "ScheduledTasksInfo", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Scheduled tasks info message." + }, + "ScheduledTasksInfoStartMessage": { + "type": "object", + "properties": { + "Data": { + "type": "string", + "description": "Gets or sets the data.", + "nullable": true + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "ScheduledTasksInfoStart", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Scheduled tasks info start message.\r\nData is the timing data encoded as \"$initialDelay,$interval\" in ms." + }, + "ScheduledTasksInfoStopMessage": { + "type": "object", + "properties": { + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "ScheduledTasksInfoStop", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Scheduled tasks info stop message." + }, + "ScrollDirection": { + "enum": ["Horizontal", "Vertical"], + "type": "string", + "description": "An enum representing the axis that should be scrolled." + }, + "SearchHint": { + "type": "object", + "properties": { + "ItemId": { + "type": "string", + "description": "Gets or sets the item id.", + "format": "uuid", + "deprecated": true + }, + "Id": { + "type": "string", + "description": "Gets or sets the item id.", + "format": "uuid" + }, + "Name": { + "type": "string", + "description": "Gets or sets the name." + }, + "MatchedTerm": { + "type": "string", + "description": "Gets or sets the matched term.", + "nullable": true + }, + "IndexNumber": { + "type": "integer", + "description": "Gets or sets the index number.", + "format": "int32", + "nullable": true + }, + "ProductionYear": { + "type": "integer", + "description": "Gets or sets the production year.", + "format": "int32", + "nullable": true + }, + "ParentIndexNumber": { + "type": "integer", + "description": "Gets or sets the parent index number.", + "format": "int32", + "nullable": true + }, + "PrimaryImageTag": { + "type": "string", + "description": "Gets or sets the image tag.", + "nullable": true + }, + "ThumbImageTag": { + "type": "string", + "description": "Gets or sets the thumb image tag.", + "nullable": true + }, + "ThumbImageItemId": { + "type": "string", + "description": "Gets or sets the thumb image item identifier.", + "nullable": true + }, + "BackdropImageTag": { + "type": "string", + "description": "Gets or sets the backdrop image tag.", + "nullable": true + }, + "BackdropImageItemId": { + "type": "string", + "description": "Gets or sets the backdrop image item identifier.", + "nullable": true + }, + "Type": { + "enum": [ + "AggregateFolder", + "Audio", + "AudioBook", + "BasePluginFolder", + "Book", + "BoxSet", + "Channel", + "ChannelFolderItem", + "CollectionFolder", + "Episode", + "Folder", + "Genre", + "ManualPlaylistsFolder", + "Movie", + "LiveTvChannel", + "LiveTvProgram", + "MusicAlbum", + "MusicArtist", + "MusicGenre", + "MusicVideo", + "Person", + "Photo", + "PhotoAlbum", + "Playlist", + "PlaylistsFolder", + "Program", + "Recording", + "Season", + "Series", + "Studio", + "Trailer", + "TvChannel", + "TvProgram", + "UserRootFolder", + "UserView", + "Video", + "Year" + ], + "allOf": [ + { + "$ref": "#/components/schemas/BaseItemKind" + } + ], + "description": "The base item kind." + }, + "IsFolder": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is folder.", + "nullable": true + }, + "RunTimeTicks": { + "type": "integer", + "description": "Gets or sets the run time ticks.", + "format": "int64", + "nullable": true + }, + "MediaType": { + "enum": ["Unknown", "Video", "Audio", "Photo", "Book"], + "allOf": [ + { + "$ref": "#/components/schemas/MediaType" + } + ], + "description": "Media types." + }, + "StartDate": { + "type": "string", + "description": "Gets or sets the start date.", + "format": "date-time", + "nullable": true + }, + "EndDate": { + "type": "string", + "description": "Gets or sets the end date.", + "format": "date-time", + "nullable": true + }, + "Series": { + "type": "string", + "description": "Gets or sets the series.", + "nullable": true + }, + "Status": { + "type": "string", + "description": "Gets or sets the status.", + "nullable": true + }, + "Album": { + "type": "string", + "description": "Gets or sets the album.", + "nullable": true + }, + "AlbumId": { + "type": "string", + "description": "Gets or sets the album id.", + "format": "uuid", + "nullable": true + }, + "AlbumArtist": { + "type": "string", + "description": "Gets or sets the album artist.", + "nullable": true + }, + "Artists": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the artists." + }, + "SongCount": { + "type": "integer", + "description": "Gets or sets the song count.", + "format": "int32", + "nullable": true + }, + "EpisodeCount": { + "type": "integer", + "description": "Gets or sets the episode count.", + "format": "int32", + "nullable": true + }, + "ChannelId": { + "type": "string", + "description": "Gets or sets the channel identifier.", + "format": "uuid", + "nullable": true + }, + "ChannelName": { + "type": "string", + "description": "Gets or sets the name of the channel.", + "nullable": true + }, + "PrimaryImageAspectRatio": { + "type": "number", + "description": "Gets or sets the primary image aspect ratio.", + "format": "double", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class SearchHintResult." + }, + "SearchHintResult": { + "type": "object", + "properties": { + "SearchHints": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SearchHint" + }, + "description": "Gets the search hints." + }, + "TotalRecordCount": { + "type": "integer", + "description": "Gets the total record count.", + "format": "int32" + } + }, + "additionalProperties": false, + "description": "Class SearchHintResult." + }, + "SeekRequestDto": { + "type": "object", + "properties": { + "PositionTicks": { + "type": "integer", + "description": "Gets or sets the position ticks.", + "format": "int64" + } + }, + "additionalProperties": false, + "description": "Class SeekRequestDto." + }, + "SendCommand": { + "type": "object", + "properties": { + "GroupId": { + "type": "string", + "description": "Gets the group identifier.", + "format": "uuid" + }, + "PlaylistItemId": { + "type": "string", + "description": "Gets the playlist identifier of the playing item.", + "format": "uuid" + }, + "When": { + "type": "string", + "description": "Gets or sets the UTC time when to execute the command.", + "format": "date-time" + }, + "PositionTicks": { + "type": "integer", + "description": "Gets the position ticks.", + "format": "int64", + "nullable": true + }, + "Command": { + "enum": ["Unpause", "Pause", "Stop", "Seek"], + "allOf": [ + { + "$ref": "#/components/schemas/SendCommandType" + } + ], + "description": "Gets the command." + }, + "EmittedAt": { + "type": "string", + "description": "Gets the UTC time when this command has been emitted.", + "format": "date-time" + } + }, + "additionalProperties": false, + "description": "Class SendCommand." + }, + "SendCommandType": { + "enum": ["Unpause", "Pause", "Stop", "Seek"], + "type": "string", + "description": "Enum SendCommandType." + }, + "SeriesInfo": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + }, + "OriginalTitle": { + "type": "string", + "description": "Gets or sets the original title.", + "nullable": true + }, + "Path": { + "type": "string", + "description": "Gets or sets the path.", + "nullable": true + }, + "MetadataLanguage": { + "type": "string", + "description": "Gets or sets the metadata language.", + "nullable": true + }, + "MetadataCountryCode": { + "type": "string", + "description": "Gets or sets the metadata country code.", + "nullable": true + }, + "ProviderIds": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "description": "Gets or sets the provider ids.", + "nullable": true + }, + "Year": { + "type": "integer", + "description": "Gets or sets the year.", + "format": "int32", + "nullable": true + }, + "IndexNumber": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "ParentIndexNumber": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "PremiereDate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "IsAutomated": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "SeriesInfoRemoteSearchQuery": { + "type": "object", + "properties": { + "SearchInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/SeriesInfo" + } + ], + "nullable": true + }, + "ItemId": { + "type": "string", + "format": "uuid" + }, + "SearchProviderName": { + "type": "string", + "description": "Gets or sets the provider name to search within if set.", + "nullable": true + }, + "IncludeDisabledProviders": { + "type": "boolean", + "description": "Gets or sets a value indicating whether disabled providers should be included." + } + }, + "additionalProperties": false + }, + "SeriesStatus": { + "enum": ["Continuing", "Ended", "Unreleased"], + "type": "string", + "description": "The status of a series." + }, + "SeriesTimerCancelledMessage": { + "type": "object", + "properties": { + "Data": { + "allOf": [ + { + "$ref": "#/components/schemas/TimerEventInfo" + } + ], + "description": "Gets or sets the data.", + "nullable": true + }, + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "SeriesTimerCancelled", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Series timer cancelled message." + }, + "SeriesTimerCreatedMessage": { + "type": "object", + "properties": { + "Data": { + "allOf": [ + { + "$ref": "#/components/schemas/TimerEventInfo" + } + ], + "description": "Gets or sets the data.", + "nullable": true + }, + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "SeriesTimerCreated", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Series timer created message." + }, + "SeriesTimerInfoDto": { + "type": "object", + "properties": { + "Id": { + "type": "string", + "description": "Gets or sets the Id of the recording.", + "nullable": true + }, + "Type": { + "type": "string", + "nullable": true + }, + "ServerId": { + "type": "string", + "description": "Gets or sets the server identifier.", + "nullable": true + }, + "ExternalId": { + "type": "string", + "description": "Gets or sets the external identifier.", + "nullable": true + }, + "ChannelId": { + "type": "string", + "description": "Gets or sets the channel id of the recording.", + "format": "uuid" + }, + "ExternalChannelId": { + "type": "string", + "description": "Gets or sets the external channel identifier.", + "nullable": true + }, + "ChannelName": { + "type": "string", + "description": "Gets or sets the channel name of the recording.", + "nullable": true + }, + "ChannelPrimaryImageTag": { + "type": "string", + "nullable": true + }, + "ProgramId": { + "type": "string", + "description": "Gets or sets the program identifier.", + "nullable": true + }, + "ExternalProgramId": { + "type": "string", + "description": "Gets or sets the external program identifier.", + "nullable": true + }, + "Name": { + "type": "string", + "description": "Gets or sets the name of the recording.", + "nullable": true + }, + "Overview": { + "type": "string", + "description": "Gets or sets the description of the recording.", + "nullable": true + }, + "StartDate": { + "type": "string", + "description": "Gets or sets the start date of the recording, in UTC.", + "format": "date-time" + }, + "EndDate": { + "type": "string", + "description": "Gets or sets the end date of the recording, in UTC.", + "format": "date-time" + }, + "ServiceName": { + "type": "string", + "description": "Gets or sets the name of the service.", + "nullable": true + }, + "Priority": { + "type": "integer", + "description": "Gets or sets the priority.", + "format": "int32" + }, + "PrePaddingSeconds": { + "type": "integer", + "description": "Gets or sets the pre padding seconds.", + "format": "int32" + }, + "PostPaddingSeconds": { + "type": "integer", + "description": "Gets or sets the post padding seconds.", + "format": "int32" + }, + "IsPrePaddingRequired": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is pre padding required." + }, + "ParentBackdropItemId": { + "type": "string", + "description": "Gets or sets the Id of the Parent that has a backdrop if the item does not have one.", + "nullable": true + }, + "ParentBackdropImageTags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the parent backdrop image tags.", + "nullable": true + }, + "IsPostPaddingRequired": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is post padding required." + }, + "KeepUntil": { + "enum": [ + "UntilDeleted", + "UntilSpaceNeeded", + "UntilWatched", + "UntilDate" + ], + "allOf": [ + { + "$ref": "#/components/schemas/KeepUntil" + } + ] + }, + "RecordAnyTime": { + "type": "boolean", + "description": "Gets or sets a value indicating whether [record any time]." + }, + "SkipEpisodesInLibrary": { + "type": "boolean" + }, + "RecordAnyChannel": { + "type": "boolean", + "description": "Gets or sets a value indicating whether [record any channel]." + }, + "KeepUpTo": { + "type": "integer", + "format": "int32" + }, + "RecordNewOnly": { + "type": "boolean", + "description": "Gets or sets a value indicating whether [record new only]." + }, + "Days": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DayOfWeek" + }, + "description": "Gets or sets the days.", + "nullable": true + }, + "DayPattern": { + "enum": ["Daily", "Weekdays", "Weekends"], + "allOf": [ + { + "$ref": "#/components/schemas/DayPattern" + } + ], + "description": "Gets or sets the day pattern.", + "nullable": true + }, + "ImageTags": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Gets or sets the image tags.", + "nullable": true + }, + "ParentThumbItemId": { + "type": "string", + "description": "Gets or sets the parent thumb item id.", + "nullable": true + }, + "ParentThumbImageTag": { + "type": "string", + "description": "Gets or sets the parent thumb image tag.", + "nullable": true + }, + "ParentPrimaryImageItemId": { + "type": "string", + "description": "Gets or sets the parent primary image item identifier.", + "nullable": true + }, + "ParentPrimaryImageTag": { + "type": "string", + "description": "Gets or sets the parent primary image tag.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class SeriesTimerInfoDto." + }, + "SeriesTimerInfoDtoQueryResult": { + "type": "object", + "properties": { + "Items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SeriesTimerInfoDto" + }, + "description": "Gets or sets the items.", + "nullable": true + }, + "TotalRecordCount": { + "type": "integer", + "description": "Gets or sets the total number of records available.", + "format": "int32" + }, + "StartIndex": { + "type": "integer", + "description": "Gets or sets the index of the first record in Items.", + "format": "int32" + } + }, + "additionalProperties": false + }, + "ServerConfiguration": { + "type": "object", + "properties": { + "LogFileRetentionDays": { + "type": "integer", + "description": "Gets or sets the number of days we should retain log files.", + "format": "int32" + }, + "IsStartupWizardCompleted": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is first run." + }, + "CachePath": { + "type": "string", + "description": "Gets or sets the cache path.", + "nullable": true + }, + "PreviousVersion": { + "type": "string", + "description": "Gets or sets the last known version that was ran using the configuration.", + "nullable": true + }, + "PreviousVersionStr": { + "type": "string", + "description": "Gets or sets the stringified PreviousVersion to be stored/loaded,\r\nbecause System.Version itself isn't xml-serializable.", + "nullable": true + }, + "EnableMetrics": { + "type": "boolean", + "description": "Gets or sets a value indicating whether to enable prometheus metrics exporting." + }, + "EnableNormalizedItemByNameIds": { + "type": "boolean" + }, + "IsPortAuthorized": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is port authorized." + }, + "QuickConnectAvailable": { + "type": "boolean", + "description": "Gets or sets a value indicating whether quick connect is available for use on this server." + }, + "EnableCaseSensitiveItemIds": { + "type": "boolean", + "description": "Gets or sets a value indicating whether [enable case sensitive item ids]." + }, + "DisableLiveTvChannelUserDataName": { + "type": "boolean" + }, + "MetadataPath": { + "type": "string", + "description": "Gets or sets the metadata path." + }, + "MetadataNetworkPath": { + "type": "string" + }, + "PreferredMetadataLanguage": { + "type": "string", + "description": "Gets or sets the preferred metadata language." + }, + "MetadataCountryCode": { + "type": "string", + "description": "Gets or sets the metadata country code." + }, + "SortReplaceCharacters": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets characters to be replaced with a ' ' in strings to create a sort name." + }, + "SortRemoveCharacters": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets characters to be removed from strings to create a sort name." + }, + "SortRemoveWords": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets words to be removed from strings to create a sort name." + }, + "MinResumePct": { + "type": "integer", + "description": "Gets or sets the minimum percentage of an item that must be played in order for playstate to be updated.", + "format": "int32" + }, + "MaxResumePct": { + "type": "integer", + "description": "Gets or sets the maximum percentage of an item that can be played while still saving playstate. If this percentage is crossed playstate will be reset to the beginning and the item will be marked watched.", + "format": "int32" + }, + "MinResumeDurationSeconds": { + "type": "integer", + "description": "Gets or sets the minimum duration that an item must have in order to be eligible for playstate updates..", + "format": "int32" + }, + "MinAudiobookResume": { + "type": "integer", + "description": "Gets or sets the minimum minutes of a book that must be played in order for playstate to be updated.", + "format": "int32" + }, + "MaxAudiobookResume": { + "type": "integer", + "description": "Gets or sets the remaining minutes of a book that can be played while still saving playstate. If this percentage is crossed playstate will be reset to the beginning and the item will be marked watched.", + "format": "int32" + }, + "InactiveSessionThreshold": { + "type": "integer", + "description": "Gets or sets the threshold in minutes after a inactive session gets closed automatically.\r\nIf set to 0 the check for inactive sessions gets disabled.", + "format": "int32" + }, + "LibraryMonitorDelay": { + "type": "integer", + "description": "Gets or sets the delay in seconds that we will wait after a file system change to try and discover what has been added/removed\r\nSome delay is necessary with some items because their creation is not atomic. It involves the creation of several\r\ndifferent directories and files.", + "format": "int32" + }, + "LibraryUpdateDuration": { + "type": "integer", + "description": "Gets or sets the duration in seconds that we will wait after a library updated event before executing the library changed notification.", + "format": "int32" + }, + "ImageSavingConvention": { + "enum": ["Legacy", "Compatible"], + "allOf": [ + { + "$ref": "#/components/schemas/ImageSavingConvention" + } + ], + "description": "Gets or sets the image saving convention." + }, + "MetadataOptions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MetadataOptions" + } + }, + "SkipDeserializationForBasicTypes": { + "type": "boolean" + }, + "ServerName": { + "type": "string" + }, + "UICulture": { + "type": "string" + }, + "SaveMetadataHidden": { + "type": "boolean" + }, + "ContentTypes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NameValuePair" + } + }, + "RemoteClientBitrateLimit": { + "type": "integer", + "format": "int32" + }, + "EnableFolderView": { + "type": "boolean" + }, + "EnableGroupingIntoCollections": { + "type": "boolean" + }, + "DisplaySpecialsWithinSeasons": { + "type": "boolean" + }, + "CodecsUsed": { + "type": "array", + "items": { + "type": "string" + } + }, + "PluginRepositories": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RepositoryInfo" + } + }, + "EnableExternalContentInSuggestions": { + "type": "boolean" + }, + "ImageExtractionTimeoutMs": { + "type": "integer", + "format": "int32" + }, + "PathSubstitutions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PathSubstitution" + } + }, + "EnableSlowResponseWarning": { + "type": "boolean", + "description": "Gets or sets a value indicating whether slow server responses should be logged as a warning." + }, + "SlowResponseThresholdMs": { + "type": "integer", + "description": "Gets or sets the threshold for the slow response time warning in ms.", + "format": "int64" + }, + "CorsHosts": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the cors hosts." + }, + "ActivityLogRetentionDays": { + "type": "integer", + "description": "Gets or sets the number of days we should retain activity logs.", + "format": "int32", + "nullable": true + }, + "LibraryScanFanoutConcurrency": { + "type": "integer", + "description": "Gets or sets the how the library scan fans out.", + "format": "int32" + }, + "LibraryMetadataRefreshConcurrency": { + "type": "integer", + "description": "Gets or sets the how many metadata refreshes can run concurrently.", + "format": "int32" + }, + "RemoveOldPlugins": { + "type": "boolean", + "description": "Gets or sets a value indicating whether older plugins should automatically be deleted from the plugin folder." + }, + "AllowClientLogUpload": { + "type": "boolean", + "description": "Gets or sets a value indicating whether clients should be allowed to upload logs." + }, + "DummyChapterDuration": { + "type": "integer", + "description": "Gets or sets the dummy chapter duration in seconds, use 0 (zero) or less to disable generation alltogether.", + "format": "int32" + }, + "ChapterImageResolution": { + "enum": [ + "MatchSource", + "P144", + "P240", + "P360", + "P480", + "P720", + "P1080", + "P1440", + "P2160" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ImageResolution" + } + ], + "description": "Gets or sets the chapter image resolution." + }, + "ParallelImageEncodingLimit": { + "type": "integer", + "description": "Gets or sets the limit for parallel image encoding.", + "format": "int32" + }, + "CastReceiverApplications": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CastReceiverApplication" + }, + "description": "Gets or sets the list of cast receiver applications." + }, + "TrickplayOptions": { + "allOf": [ + { + "$ref": "#/components/schemas/TrickplayOptions" + } + ], + "description": "Gets or sets the trickplay options." + } + }, + "additionalProperties": false, + "description": "Represents the server configuration." + }, + "ServerDiscoveryInfo": { + "type": "object", + "properties": { + "Address": { + "type": "string", + "description": "Gets the address." + }, + "Id": { + "type": "string", + "description": "Gets the server identifier." + }, + "Name": { + "type": "string", + "description": "Gets the name." + }, + "EndpointAddress": { + "type": "string", + "description": "Gets the endpoint address.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "The server discovery info model." + }, + "ServerRestartingMessage": { + "type": "object", + "properties": { + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "ServerRestarting", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Server restarting down message." + }, + "ServerShuttingDownMessage": { + "type": "object", + "properties": { + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "ServerShuttingDown", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Server shutting down message." + }, + "SessionInfo": { + "type": "object", + "properties": { + "PlayState": { + "allOf": [ + { + "$ref": "#/components/schemas/PlayerStateInfo" + } + ], + "nullable": true + }, + "AdditionalUsers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SessionUserInfo" + }, + "nullable": true + }, + "Capabilities": { + "allOf": [ + { + "$ref": "#/components/schemas/ClientCapabilities" + } + ], + "nullable": true + }, + "RemoteEndPoint": { + "type": "string", + "description": "Gets or sets the remote end point.", + "nullable": true + }, + "PlayableMediaTypes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MediaType" + }, + "description": "Gets the playable media types.", + "nullable": true, + "readOnly": true + }, + "Id": { + "type": "string", + "description": "Gets or sets the id.", + "nullable": true + }, + "UserId": { + "type": "string", + "description": "Gets or sets the user id.", + "format": "uuid" + }, + "UserName": { + "type": "string", + "description": "Gets or sets the username.", + "nullable": true + }, + "Client": { + "type": "string", + "description": "Gets or sets the type of the client.", + "nullable": true + }, + "LastActivityDate": { + "type": "string", + "description": "Gets or sets the last activity date.", + "format": "date-time" + }, + "LastPlaybackCheckIn": { + "type": "string", + "description": "Gets or sets the last playback check in.", + "format": "date-time" + }, + "LastPausedDate": { + "type": "string", + "description": "Gets or sets the last paused date.", + "format": "date-time", + "nullable": true + }, + "DeviceName": { + "type": "string", + "description": "Gets or sets the name of the device.", + "nullable": true + }, + "DeviceType": { + "type": "string", + "description": "Gets or sets the type of the device.", + "nullable": true + }, + "NowPlayingItem": { + "allOf": [ + { + "$ref": "#/components/schemas/BaseItemDto" + } + ], + "description": "Gets or sets the now playing item.", + "nullable": true + }, + "NowViewingItem": { + "allOf": [ + { + "$ref": "#/components/schemas/BaseItemDto" + } + ], + "description": "This is strictly used as a data transfer object from the api layer.\r\nThis holds information about a BaseItem in a format that is convenient for the client.", + "nullable": true + }, + "DeviceId": { + "type": "string", + "description": "Gets or sets the device id.", + "nullable": true + }, + "ApplicationVersion": { + "type": "string", + "description": "Gets or sets the application version.", + "nullable": true + }, + "TranscodingInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/TranscodingInfo" + } + ], + "nullable": true + }, + "IsActive": { + "type": "boolean", + "description": "Gets a value indicating whether this instance is active.", + "readOnly": true + }, + "SupportsMediaControl": { + "type": "boolean", + "readOnly": true + }, + "SupportsRemoteControl": { + "type": "boolean", + "readOnly": true + }, + "NowPlayingQueue": { + "type": "array", + "items": { + "$ref": "#/components/schemas/QueueItem" + }, + "nullable": true + }, + "NowPlayingQueueFullItems": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemDto" + }, + "nullable": true + }, + "HasCustomDeviceName": { + "type": "boolean" + }, + "PlaylistItemId": { + "type": "string", + "nullable": true + }, + "ServerId": { + "type": "string", + "nullable": true + }, + "UserPrimaryImageTag": { + "type": "string", + "nullable": true + }, + "SupportedCommands": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GeneralCommandType" + }, + "description": "Gets the supported commands.", + "nullable": true, + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Class SessionInfo." + }, + "SessionMessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "type": "string", + "description": "The different kinds of messages that are used in the WebSocket api." + }, + "SessionsMessage": { + "type": "object", + "properties": { + "Data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SessionInfo" + }, + "description": "Gets or sets the data.", + "nullable": true + }, + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "Sessions", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Sessions message." + }, + "SessionsStartMessage": { + "type": "object", + "properties": { + "Data": { + "type": "string", + "description": "Gets or sets the data.", + "nullable": true + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "SessionsStart", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Sessions start message.\r\nData is the timing data encoded as \"$initialDelay,$interval\" in ms." + }, + "SessionsStopMessage": { + "type": "object", + "properties": { + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "SessionsStop", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Sessions stop message." + }, + "SessionUserInfo": { + "type": "object", + "properties": { + "UserId": { + "type": "string", + "description": "Gets or sets the user identifier.", + "format": "uuid" + }, + "UserName": { + "type": "string", + "description": "Gets or sets the name of the user.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class SessionUserInfo." + }, + "SetChannelMappingDto": { + "required": ["ProviderChannelId", "ProviderId", "TunerChannelId"], + "type": "object", + "properties": { + "ProviderId": { + "type": "string", + "description": "Gets or sets the provider id." + }, + "TunerChannelId": { + "type": "string", + "description": "Gets or sets the tuner channel id." + }, + "ProviderChannelId": { + "type": "string", + "description": "Gets or sets the provider channel id." + } + }, + "additionalProperties": false, + "description": "Set channel mapping dto." + }, + "SetPlaylistItemRequestDto": { + "type": "object", + "properties": { + "PlaylistItemId": { + "type": "string", + "description": "Gets or sets the playlist identifier of the playing item.", + "format": "uuid" + } + }, + "additionalProperties": false, + "description": "Class SetPlaylistItemRequestDto." + }, + "SetRepeatModeRequestDto": { + "type": "object", + "properties": { + "Mode": { + "enum": ["RepeatOne", "RepeatAll", "RepeatNone"], + "allOf": [ + { + "$ref": "#/components/schemas/GroupRepeatMode" + } + ], + "description": "Gets or sets the repeat mode." + } + }, + "additionalProperties": false, + "description": "Class SetRepeatModeRequestDto." + }, + "SetShuffleModeRequestDto": { + "type": "object", + "properties": { + "Mode": { + "enum": ["Sorted", "Shuffle"], + "allOf": [ + { + "$ref": "#/components/schemas/GroupShuffleMode" + } + ], + "description": "Gets or sets the shuffle mode." + } + }, + "additionalProperties": false, + "description": "Class SetShuffleModeRequestDto." + }, + "SongInfo": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + }, + "OriginalTitle": { + "type": "string", + "description": "Gets or sets the original title.", + "nullable": true + }, + "Path": { + "type": "string", + "description": "Gets or sets the path.", + "nullable": true + }, + "MetadataLanguage": { + "type": "string", + "description": "Gets or sets the metadata language.", + "nullable": true + }, + "MetadataCountryCode": { + "type": "string", + "description": "Gets or sets the metadata country code.", + "nullable": true + }, + "ProviderIds": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "description": "Gets or sets the provider ids.", + "nullable": true + }, + "Year": { + "type": "integer", + "description": "Gets or sets the year.", + "format": "int32", + "nullable": true + }, + "IndexNumber": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "ParentIndexNumber": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "PremiereDate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "IsAutomated": { + "type": "boolean" + }, + "AlbumArtists": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "Album": { + "type": "string", + "nullable": true + }, + "Artists": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "SortOrder": { + "enum": ["Ascending", "Descending"], + "type": "string", + "description": "An enum representing the sorting order." + }, + "SpecialViewOptionDto": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets view option name.", + "nullable": true + }, + "Id": { + "type": "string", + "description": "Gets or sets view option id.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Special view option dto." + }, + "StartupConfigurationDto": { + "type": "object", + "properties": { + "UICulture": { + "type": "string", + "description": "Gets or sets UI language culture.", + "nullable": true + }, + "MetadataCountryCode": { + "type": "string", + "description": "Gets or sets the metadata country code.", + "nullable": true + }, + "PreferredMetadataLanguage": { + "type": "string", + "description": "Gets or sets the preferred language for the metadata.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "The startup configuration DTO." + }, + "StartupRemoteAccessDto": { + "required": ["EnableAutomaticPortMapping", "EnableRemoteAccess"], + "type": "object", + "properties": { + "EnableRemoteAccess": { + "type": "boolean", + "description": "Gets or sets a value indicating whether enable remote access." + }, + "EnableAutomaticPortMapping": { + "type": "boolean", + "description": "Gets or sets a value indicating whether enable automatic port mapping." + } + }, + "additionalProperties": false, + "description": "Startup remote access dto." + }, + "StartupUserDto": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the username.", + "nullable": true + }, + "Password": { + "type": "string", + "description": "Gets or sets the user's password.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "The startup user DTO." + }, + "StringGroupUpdate": { + "type": "object", + "properties": { + "GroupId": { + "type": "string", + "description": "Gets the group identifier.", + "format": "uuid", + "readOnly": true + }, + "Type": { + "enum": [ + "UserJoined", + "UserLeft", + "GroupJoined", + "GroupLeft", + "StateUpdate", + "PlayQueue", + "NotInGroup", + "GroupDoesNotExist", + "CreateGroupDenied", + "JoinGroupDenied", + "LibraryAccessDenied" + ], + "allOf": [ + { + "$ref": "#/components/schemas/GroupUpdateType" + } + ], + "description": "Gets the update type." + }, + "Data": { + "type": "string", + "description": "Gets the update data." + } + }, + "additionalProperties": false, + "description": "Class GroupUpdate." + }, + "SubtitleDeliveryMethod": { + "enum": ["Encode", "Embed", "External", "Hls", "Drop"], + "type": "string", + "description": "Delivery method to use during playback of a specific subtitle format." + }, + "SubtitleOptions": { + "type": "object", + "properties": { + "SkipIfEmbeddedSubtitlesPresent": { + "type": "boolean" + }, + "SkipIfAudioTrackMatches": { + "type": "boolean" + }, + "DownloadLanguages": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "DownloadMovieSubtitles": { + "type": "boolean" + }, + "DownloadEpisodeSubtitles": { + "type": "boolean" + }, + "OpenSubtitlesUsername": { + "type": "string", + "nullable": true + }, + "OpenSubtitlesPasswordHash": { + "type": "string", + "nullable": true + }, + "IsOpenSubtitleVipAccount": { + "type": "boolean" + }, + "RequirePerfectMatch": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "SubtitlePlaybackMode": { + "enum": ["Default", "Always", "OnlyForced", "None", "Smart"], + "type": "string", + "description": "An enum representing a subtitle playback mode." + }, + "SubtitleProfile": { + "type": "object", + "properties": { + "Format": { + "type": "string", + "nullable": true + }, + "Method": { + "enum": ["Encode", "Embed", "External", "Hls", "Drop"], + "allOf": [ + { + "$ref": "#/components/schemas/SubtitleDeliveryMethod" + } + ], + "description": "Delivery method to use during playback of a specific subtitle format." + }, + "DidlMode": { + "type": "string", + "nullable": true + }, + "Language": { + "type": "string", + "nullable": true + }, + "Container": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "SyncPlayCommandMessage": { + "type": "object", + "properties": { + "Data": { + "allOf": [ + { + "$ref": "#/components/schemas/SendCommand" + } + ], + "description": "Gets or sets the data.", + "nullable": true + }, + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "SyncPlayCommand", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Sync play command." + }, + "SyncPlayGroupUpdateCommandMessage": { + "type": "object", + "properties": { + "Data": { + "allOf": [ + { + "$ref": "#/components/schemas/GroupUpdate" + } + ], + "description": "Gets or sets the data.", + "nullable": true + }, + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "SyncPlayGroupUpdate", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Untyped sync play command." + }, + "SyncPlayQueueItem": { + "type": "object", + "properties": { + "ItemId": { + "type": "string", + "description": "Gets the item identifier.", + "format": "uuid" + }, + "PlaylistItemId": { + "type": "string", + "description": "Gets the playlist identifier of the item.", + "format": "uuid", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Class QueueItem." + }, + "SyncPlayUserAccessType": { + "enum": ["CreateAndJoinGroups", "JoinGroups", "None"], + "type": "string", + "description": "Enum SyncPlayUserAccessType." + }, + "SystemInfo": { + "type": "object", + "properties": { + "LocalAddress": { + "type": "string", + "description": "Gets or sets the local address.", + "nullable": true + }, + "ServerName": { + "type": "string", + "description": "Gets or sets the name of the server.", + "nullable": true + }, + "Version": { + "type": "string", + "description": "Gets or sets the server version.", + "nullable": true + }, + "ProductName": { + "type": "string", + "description": "Gets or sets the product name. This is the AssemblyProduct name.", + "nullable": true + }, + "OperatingSystem": { + "type": "string", + "description": "Gets or sets the operating system.", + "nullable": true, + "deprecated": true + }, + "Id": { + "type": "string", + "description": "Gets or sets the id.", + "nullable": true + }, + "StartupWizardCompleted": { + "type": "boolean", + "description": "Gets or sets a value indicating whether the startup wizard is completed.", + "nullable": true + }, + "OperatingSystemDisplayName": { + "type": "string", + "description": "Gets or sets the display name of the operating system.", + "nullable": true, + "deprecated": true + }, + "PackageName": { + "type": "string", + "description": "Gets or sets the package name.", + "nullable": true + }, + "HasPendingRestart": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance has pending restart." + }, + "IsShuttingDown": { + "type": "boolean" + }, + "SupportsLibraryMonitor": { + "type": "boolean", + "description": "Gets or sets a value indicating whether [supports library monitor]." + }, + "WebSocketPortNumber": { + "type": "integer", + "description": "Gets or sets the web socket port number.", + "format": "int32" + }, + "CompletedInstallations": { + "type": "array", + "items": { + "$ref": "#/components/schemas/InstallationInfo" + }, + "description": "Gets or sets the completed installations.", + "nullable": true + }, + "CanSelfRestart": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance can self restart.", + "default": true, + "deprecated": true + }, + "CanLaunchWebBrowser": { + "type": "boolean", + "default": false, + "deprecated": true + }, + "ProgramDataPath": { + "type": "string", + "description": "Gets or sets the program data path.", + "nullable": true + }, + "WebPath": { + "type": "string", + "description": "Gets or sets the web UI resources path.", + "nullable": true + }, + "ItemsByNamePath": { + "type": "string", + "description": "Gets or sets the items by name path.", + "nullable": true + }, + "CachePath": { + "type": "string", + "description": "Gets or sets the cache path.", + "nullable": true + }, + "LogPath": { + "type": "string", + "description": "Gets or sets the log path.", + "nullable": true + }, + "InternalMetadataPath": { + "type": "string", + "description": "Gets or sets the internal metadata path.", + "nullable": true + }, + "TranscodingTempPath": { + "type": "string", + "description": "Gets or sets the transcode path.", + "nullable": true + }, + "CastReceiverApplications": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CastReceiverApplication" + }, + "description": "Gets or sets the list of cast receiver applications.", + "nullable": true + }, + "HasUpdateAvailable": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance has update available.", + "default": false, + "deprecated": true + }, + "EncoderLocation": { + "type": "string", + "default": "System", + "nullable": true, + "deprecated": true + }, + "SystemArchitecture": { + "type": "string", + "default": "X64", + "nullable": true, + "deprecated": true + } + }, + "additionalProperties": false, + "description": "Class SystemInfo." + }, + "TaskCompletionStatus": { + "enum": ["Completed", "Failed", "Cancelled", "Aborted"], + "type": "string", + "description": "Enum TaskCompletionStatus." + }, + "TaskInfo": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + }, + "State": { + "enum": ["Idle", "Cancelling", "Running"], + "allOf": [ + { + "$ref": "#/components/schemas/TaskState" + } + ], + "description": "Gets or sets the state of the task." + }, + "CurrentProgressPercentage": { + "type": "number", + "description": "Gets or sets the progress.", + "format": "double", + "nullable": true + }, + "Id": { + "type": "string", + "description": "Gets or sets the id.", + "nullable": true + }, + "LastExecutionResult": { + "allOf": [ + { + "$ref": "#/components/schemas/TaskResult" + } + ], + "description": "Gets or sets the last execution result.", + "nullable": true + }, + "Triggers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TaskTriggerInfo" + }, + "description": "Gets or sets the triggers.", + "nullable": true + }, + "Description": { + "type": "string", + "description": "Gets or sets the description.", + "nullable": true + }, + "Category": { + "type": "string", + "description": "Gets or sets the category.", + "nullable": true + }, + "IsHidden": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is hidden." + }, + "Key": { + "type": "string", + "description": "Gets or sets the key.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class TaskInfo." + }, + "TaskResult": { + "type": "object", + "properties": { + "StartTimeUtc": { + "type": "string", + "description": "Gets or sets the start time UTC.", + "format": "date-time" + }, + "EndTimeUtc": { + "type": "string", + "description": "Gets or sets the end time UTC.", + "format": "date-time" + }, + "Status": { + "enum": ["Completed", "Failed", "Cancelled", "Aborted"], + "allOf": [ + { + "$ref": "#/components/schemas/TaskCompletionStatus" + } + ], + "description": "Gets or sets the status." + }, + "Name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + }, + "Key": { + "type": "string", + "description": "Gets or sets the key.", + "nullable": true + }, + "Id": { + "type": "string", + "description": "Gets or sets the id.", + "nullable": true + }, + "ErrorMessage": { + "type": "string", + "description": "Gets or sets the error message.", + "nullable": true + }, + "LongErrorMessage": { + "type": "string", + "description": "Gets or sets the long error message.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class TaskExecutionInfo." + }, + "TaskState": { + "enum": ["Idle", "Cancelling", "Running"], + "type": "string", + "description": "Enum TaskState." + }, + "TaskTriggerInfo": { + "type": "object", + "properties": { + "Type": { + "type": "string", + "description": "Gets or sets the type.", + "nullable": true + }, + "TimeOfDayTicks": { + "type": "integer", + "description": "Gets or sets the time of day.", + "format": "int64", + "nullable": true + }, + "IntervalTicks": { + "type": "integer", + "description": "Gets or sets the interval.", + "format": "int64", + "nullable": true + }, + "DayOfWeek": { + "enum": [ + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday" + ], + "allOf": [ + { + "$ref": "#/components/schemas/DayOfWeek" + } + ], + "description": "Gets or sets the day of week.", + "nullable": true + }, + "MaxRuntimeTicks": { + "type": "integer", + "description": "Gets or sets the maximum runtime ticks.", + "format": "int64", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class TaskTriggerInfo." + }, + "ThemeMediaResult": { + "type": "object", + "properties": { + "Items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BaseItemDto" + }, + "description": "Gets or sets the items.", + "nullable": true + }, + "TotalRecordCount": { + "type": "integer", + "description": "Gets or sets the total number of records available.", + "format": "int32" + }, + "StartIndex": { + "type": "integer", + "description": "Gets or sets the index of the first record in Items.", + "format": "int32" + }, + "OwnerId": { + "type": "string", + "description": "Gets or sets the owner id.", + "format": "uuid" + } + }, + "additionalProperties": false, + "description": "Class ThemeMediaResult." + }, + "TimerCancelledMessage": { + "type": "object", + "properties": { + "Data": { + "allOf": [ + { + "$ref": "#/components/schemas/TimerEventInfo" + } + ], + "description": "Gets or sets the data.", + "nullable": true + }, + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "TimerCancelled", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Timer cancelled message." + }, + "TimerCreatedMessage": { + "type": "object", + "properties": { + "Data": { + "allOf": [ + { + "$ref": "#/components/schemas/TimerEventInfo" + } + ], + "description": "Gets or sets the data.", + "nullable": true + }, + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "TimerCreated", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Timer created message." + }, + "TimerEventInfo": { + "type": "object", + "properties": { + "Id": { + "type": "string" + }, + "ProgramId": { + "type": "string", + "format": "uuid", + "nullable": true + } + }, + "additionalProperties": false + }, + "TimerInfoDto": { + "type": "object", + "properties": { + "Id": { + "type": "string", + "description": "Gets or sets the Id of the recording.", + "nullable": true + }, + "Type": { + "type": "string", + "nullable": true + }, + "ServerId": { + "type": "string", + "description": "Gets or sets the server identifier.", + "nullable": true + }, + "ExternalId": { + "type": "string", + "description": "Gets or sets the external identifier.", + "nullable": true + }, + "ChannelId": { + "type": "string", + "description": "Gets or sets the channel id of the recording.", + "format": "uuid" + }, + "ExternalChannelId": { + "type": "string", + "description": "Gets or sets the external channel identifier.", + "nullable": true + }, + "ChannelName": { + "type": "string", + "description": "Gets or sets the channel name of the recording.", + "nullable": true + }, + "ChannelPrimaryImageTag": { + "type": "string", + "nullable": true + }, + "ProgramId": { + "type": "string", + "description": "Gets or sets the program identifier.", + "nullable": true + }, + "ExternalProgramId": { + "type": "string", + "description": "Gets or sets the external program identifier.", + "nullable": true + }, + "Name": { + "type": "string", + "description": "Gets or sets the name of the recording.", + "nullable": true + }, + "Overview": { + "type": "string", + "description": "Gets or sets the description of the recording.", + "nullable": true + }, + "StartDate": { + "type": "string", + "description": "Gets or sets the start date of the recording, in UTC.", + "format": "date-time" + }, + "EndDate": { + "type": "string", + "description": "Gets or sets the end date of the recording, in UTC.", + "format": "date-time" + }, + "ServiceName": { + "type": "string", + "description": "Gets or sets the name of the service.", + "nullable": true + }, + "Priority": { + "type": "integer", + "description": "Gets or sets the priority.", + "format": "int32" + }, + "PrePaddingSeconds": { + "type": "integer", + "description": "Gets or sets the pre padding seconds.", + "format": "int32" + }, + "PostPaddingSeconds": { + "type": "integer", + "description": "Gets or sets the post padding seconds.", + "format": "int32" + }, + "IsPrePaddingRequired": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is pre padding required." + }, + "ParentBackdropItemId": { + "type": "string", + "description": "Gets or sets the Id of the Parent that has a backdrop if the item does not have one.", + "nullable": true + }, + "ParentBackdropImageTags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the parent backdrop image tags.", + "nullable": true + }, + "IsPostPaddingRequired": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is post padding required." + }, + "KeepUntil": { + "enum": [ + "UntilDeleted", + "UntilSpaceNeeded", + "UntilWatched", + "UntilDate" + ], + "allOf": [ + { + "$ref": "#/components/schemas/KeepUntil" + } + ] + }, + "Status": { + "enum": [ + "New", + "InProgress", + "Completed", + "Cancelled", + "ConflictedOk", + "ConflictedNotOk", + "Error" + ], + "allOf": [ + { + "$ref": "#/components/schemas/RecordingStatus" + } + ], + "description": "Gets or sets the status." + }, + "SeriesTimerId": { + "type": "string", + "description": "Gets or sets the series timer identifier.", + "nullable": true + }, + "ExternalSeriesTimerId": { + "type": "string", + "description": "Gets or sets the external series timer identifier.", + "nullable": true + }, + "RunTimeTicks": { + "type": "integer", + "description": "Gets or sets the run time ticks.", + "format": "int64", + "nullable": true + }, + "ProgramInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/BaseItemDto" + } + ], + "description": "Gets or sets the program information.", + "nullable": true + } + }, + "additionalProperties": false + }, + "TimerInfoDtoQueryResult": { + "type": "object", + "properties": { + "Items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TimerInfoDto" + }, + "description": "Gets or sets the items.", + "nullable": true + }, + "TotalRecordCount": { + "type": "integer", + "description": "Gets or sets the total number of records available.", + "format": "int32" + }, + "StartIndex": { + "type": "integer", + "description": "Gets or sets the index of the first record in Items.", + "format": "int32" + } + }, + "additionalProperties": false + }, + "TrailerInfo": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + }, + "OriginalTitle": { + "type": "string", + "description": "Gets or sets the original title.", + "nullable": true + }, + "Path": { + "type": "string", + "description": "Gets or sets the path.", + "nullable": true + }, + "MetadataLanguage": { + "type": "string", + "description": "Gets or sets the metadata language.", + "nullable": true + }, + "MetadataCountryCode": { + "type": "string", + "description": "Gets or sets the metadata country code.", + "nullable": true + }, + "ProviderIds": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "description": "Gets or sets the provider ids.", + "nullable": true + }, + "Year": { + "type": "integer", + "description": "Gets or sets the year.", + "format": "int32", + "nullable": true + }, + "IndexNumber": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "ParentIndexNumber": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "PremiereDate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "IsAutomated": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "TrailerInfoRemoteSearchQuery": { + "type": "object", + "properties": { + "SearchInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/TrailerInfo" + } + ], + "nullable": true + }, + "ItemId": { + "type": "string", + "format": "uuid" + }, + "SearchProviderName": { + "type": "string", + "description": "Gets or sets the provider name to search within if set.", + "nullable": true + }, + "IncludeDisabledProviders": { + "type": "boolean", + "description": "Gets or sets a value indicating whether disabled providers should be included." + } + }, + "additionalProperties": false + }, + "TraktEpisode": { + "type": "object", + "properties": { + "season": { + "type": "integer", + "format": "int32" + }, + "number": { + "type": "integer", + "format": "int32" + }, + "title": { + "type": "string", + "nullable": true + }, + "ids": { + "allOf": [ + { + "$ref": "#/components/schemas/TraktEpisodeId" + } + ], + "nullable": true + } + }, + "additionalProperties": false + }, + "TraktEpisodeId": { + "type": "object", + "properties": { + "trakt": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "slug": { + "type": "string", + "nullable": true + }, + "imdb": { + "type": "string", + "nullable": true + }, + "tmdb": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "tvdb": { + "type": "string", + "nullable": true + }, + "tvrage": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "TraktMovie": { + "type": "object", + "properties": { + "title": { + "type": "string", + "nullable": true + }, + "year": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "ids": { + "allOf": [ + { + "$ref": "#/components/schemas/TraktMovieId" + } + ], + "nullable": true + } + }, + "additionalProperties": false + }, + "TraktMovieId": { + "type": "object", + "properties": { + "trakt": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "slug": { + "type": "string", + "nullable": true + }, + "imdb": { + "type": "string", + "nullable": true + }, + "tmdb": { + "type": "integer", + "format": "int32", + "nullable": true + } + }, + "additionalProperties": false + }, + "TraktPerson": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true + }, + "ids": { + "allOf": [ + { + "$ref": "#/components/schemas/TraktPersonId" + } + ], + "nullable": true + } + }, + "additionalProperties": false + }, + "TraktPersonId": { + "type": "object", + "properties": { + "trakt": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "slug": { + "type": "string", + "nullable": true + }, + "imdb": { + "type": "string", + "nullable": true + }, + "tmdb": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "tvrage": { + "type": "integer", + "format": "int32", + "nullable": true + } + }, + "additionalProperties": false + }, + "TraktSeason": { + "type": "object", + "properties": { + "number": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "ids": { + "allOf": [ + { + "$ref": "#/components/schemas/TraktSeasonId" + } + ], + "nullable": true + } + }, + "additionalProperties": false + }, + "TraktSeasonId": { + "type": "object", + "properties": { + "trakt": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "slug": { + "type": "string", + "nullable": true + }, + "tmdb": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "tvdb": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "tvrage": { + "type": "integer", + "format": "int32", + "nullable": true + } + }, + "additionalProperties": false + }, + "TraktShow": { + "type": "object", + "properties": { + "title": { + "type": "string", + "nullable": true + }, + "year": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "ids": { + "allOf": [ + { + "$ref": "#/components/schemas/TraktShowId" + } + ], + "nullable": true + } + }, + "additionalProperties": false + }, + "TraktShowId": { + "type": "object", + "properties": { + "trakt": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "slug": { + "type": "string", + "nullable": true + }, + "imdb": { + "type": "string", + "nullable": true + }, + "tmdb": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "tvdb": { + "type": "string", + "nullable": true + }, + "tvrage": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "TraktSyncResponse": { + "type": "object", + "properties": { + "added": { + "allOf": [ + { + "$ref": "#/components/schemas/Items" + } + ], + "nullable": true + }, + "deleted": { + "allOf": [ + { + "$ref": "#/components/schemas/Items" + } + ], + "nullable": true + }, + "updated": { + "allOf": [ + { + "$ref": "#/components/schemas/Items" + } + ], + "nullable": true + }, + "not_found": { + "allOf": [ + { + "$ref": "#/components/schemas/NotFoundObjects" + } + ], + "nullable": true + } + }, + "additionalProperties": false + }, + "TranscodeReason": { + "enum": [ + "ContainerNotSupported", + "VideoCodecNotSupported", + "AudioCodecNotSupported", + "SubtitleCodecNotSupported", + "AudioIsExternal", + "SecondaryAudioNotSupported", + "VideoProfileNotSupported", + "VideoLevelNotSupported", + "VideoResolutionNotSupported", + "VideoBitDepthNotSupported", + "VideoFramerateNotSupported", + "RefFramesNotSupported", + "AnamorphicVideoNotSupported", + "InterlacedVideoNotSupported", + "AudioChannelsNotSupported", + "AudioProfileNotSupported", + "AudioSampleRateNotSupported", + "AudioBitDepthNotSupported", + "ContainerBitrateExceedsLimit", + "VideoBitrateNotSupported", + "AudioBitrateNotSupported", + "UnknownVideoStreamInfo", + "UnknownAudioStreamInfo", + "DirectPlayError", + "VideoRangeTypeNotSupported" + ], + "type": "string" + }, + "TranscodeSeekInfo": { + "enum": ["Auto", "Bytes"], + "type": "string" + }, + "TranscodingInfo": { + "type": "object", + "properties": { + "AudioCodec": { + "type": "string", + "nullable": true + }, + "VideoCodec": { + "type": "string", + "nullable": true + }, + "Container": { + "type": "string", + "nullable": true + }, + "IsVideoDirect": { + "type": "boolean" + }, + "IsAudioDirect": { + "type": "boolean" + }, + "Bitrate": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "Framerate": { + "type": "number", + "format": "float", + "nullable": true + }, + "CompletionPercentage": { + "type": "number", + "format": "double", + "nullable": true + }, + "Width": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "Height": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "AudioChannels": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "HardwareAccelerationType": { + "enum": [ + "AMF", + "QSV", + "NVENC", + "V4L2M2M", + "VAAPI", + "VideoToolBox", + "RKMPP" + ], + "allOf": [ + { + "$ref": "#/components/schemas/HardwareEncodingType" + } + ], + "nullable": true + }, + "TranscodeReasons": { + "enum": [ + "ContainerNotSupported", + "VideoCodecNotSupported", + "AudioCodecNotSupported", + "SubtitleCodecNotSupported", + "AudioIsExternal", + "SecondaryAudioNotSupported", + "VideoProfileNotSupported", + "VideoLevelNotSupported", + "VideoResolutionNotSupported", + "VideoBitDepthNotSupported", + "VideoFramerateNotSupported", + "RefFramesNotSupported", + "AnamorphicVideoNotSupported", + "InterlacedVideoNotSupported", + "AudioChannelsNotSupported", + "AudioProfileNotSupported", + "AudioSampleRateNotSupported", + "AudioBitDepthNotSupported", + "ContainerBitrateExceedsLimit", + "VideoBitrateNotSupported", + "AudioBitrateNotSupported", + "UnknownVideoStreamInfo", + "UnknownAudioStreamInfo", + "DirectPlayError", + "VideoRangeTypeNotSupported" + ], + "type": "array", + "items": { + "$ref": "#/components/schemas/TranscodeReason" + } + } + }, + "additionalProperties": false + }, + "TranscodingProfile": { + "type": "object", + "properties": { + "Container": { + "type": "string" + }, + "Type": { + "enum": ["Audio", "Video", "Photo", "Subtitle", "Lyric"], + "allOf": [ + { + "$ref": "#/components/schemas/DlnaProfileType" + } + ] + }, + "VideoCodec": { + "type": "string" + }, + "AudioCodec": { + "type": "string" + }, + "Protocol": { + "enum": ["http", "hls"], + "allOf": [ + { + "$ref": "#/components/schemas/MediaStreamProtocol" + } + ], + "description": "Media streaming protocol.\r\nLowercase for backwards compatibility." + }, + "EstimateContentLength": { + "type": "boolean", + "default": false + }, + "EnableMpegtsM2TsMode": { + "type": "boolean", + "default": false + }, + "TranscodeSeekInfo": { + "enum": ["Auto", "Bytes"], + "allOf": [ + { + "$ref": "#/components/schemas/TranscodeSeekInfo" + } + ], + "default": "Auto" + }, + "CopyTimestamps": { + "type": "boolean", + "default": false + }, + "Context": { + "enum": ["Streaming", "Static"], + "allOf": [ + { + "$ref": "#/components/schemas/EncodingContext" + } + ], + "default": "Streaming" + }, + "EnableSubtitlesInManifest": { + "type": "boolean", + "default": false + }, + "MaxAudioChannels": { + "type": "string", + "nullable": true + }, + "MinSegments": { + "type": "integer", + "format": "int32", + "default": 0 + }, + "SegmentLength": { + "type": "integer", + "format": "int32", + "default": 0 + }, + "BreakOnNonKeyFrames": { + "type": "boolean", + "default": false + }, + "Conditions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProfileCondition" + } + } + }, + "additionalProperties": false + }, + "TransportStreamTimestamp": { + "enum": ["None", "Zero", "Valid"], + "type": "string" + }, + "TrickplayInfo": { + "type": "object", + "properties": { + "Width": { + "type": "integer", + "description": "Gets or sets width of an individual thumbnail.", + "format": "int32" + }, + "Height": { + "type": "integer", + "description": "Gets or sets height of an individual thumbnail.", + "format": "int32" + }, + "TileWidth": { + "type": "integer", + "description": "Gets or sets amount of thumbnails per row.", + "format": "int32" + }, + "TileHeight": { + "type": "integer", + "description": "Gets or sets amount of thumbnails per column.", + "format": "int32" + }, + "ThumbnailCount": { + "type": "integer", + "description": "Gets or sets total amount of non-black thumbnails.", + "format": "int32" + }, + "Interval": { + "type": "integer", + "description": "Gets or sets interval in milliseconds between each trickplay thumbnail.", + "format": "int32" + }, + "Bandwidth": { + "type": "integer", + "description": "Gets or sets peak bandwith usage in bits per second.", + "format": "int32" + } + }, + "additionalProperties": false, + "description": "An entity representing the metadata for a group of trickplay tiles." + }, + "TrickplayOptions": { + "type": "object", + "properties": { + "EnableHwAcceleration": { + "type": "boolean", + "description": "Gets or sets a value indicating whether or not to use HW acceleration." + }, + "EnableHwEncoding": { + "type": "boolean", + "description": "Gets or sets a value indicating whether or not to use HW accelerated MJPEG encoding." + }, + "ScanBehavior": { + "enum": ["Blocking", "NonBlocking"], + "allOf": [ + { + "$ref": "#/components/schemas/TrickplayScanBehavior" + } + ], + "description": "Gets or sets the behavior used by trickplay provider on library scan/update." + }, + "ProcessPriority": { + "enum": [ + "Normal", + "Idle", + "High", + "RealTime", + "BelowNormal", + "AboveNormal" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ProcessPriorityClass" + } + ], + "description": "Gets or sets the process priority for the ffmpeg process." + }, + "Interval": { + "type": "integer", + "description": "Gets or sets the interval, in ms, between each new trickplay image.", + "format": "int32" + }, + "WidthResolutions": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "description": "Gets or sets the target width resolutions, in px, to generates preview images for." + }, + "TileWidth": { + "type": "integer", + "description": "Gets or sets number of tile images to allow in X dimension.", + "format": "int32" + }, + "TileHeight": { + "type": "integer", + "description": "Gets or sets number of tile images to allow in Y dimension.", + "format": "int32" + }, + "Qscale": { + "type": "integer", + "description": "Gets or sets the ffmpeg output quality level.", + "format": "int32" + }, + "JpegQuality": { + "type": "integer", + "description": "Gets or sets the jpeg quality to use for image tiles.", + "format": "int32" + }, + "ProcessThreads": { + "type": "integer", + "description": "Gets or sets the number of threads to be used by ffmpeg.", + "format": "int32" + } + }, + "additionalProperties": false, + "description": "Class TrickplayOptions." + }, + "TrickplayScanBehavior": { + "enum": ["Blocking", "NonBlocking"], + "type": "string", + "description": "Enum TrickplayScanBehavior." + }, + "TunerChannelMapping": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "nullable": true + }, + "ProviderChannelName": { + "type": "string", + "nullable": true + }, + "ProviderChannelId": { + "type": "string", + "nullable": true + }, + "Id": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "TunerHostInfo": { + "type": "object", + "properties": { + "Id": { + "type": "string", + "nullable": true + }, + "Url": { + "type": "string", + "nullable": true + }, + "Type": { + "type": "string", + "nullable": true + }, + "DeviceId": { + "type": "string", + "nullable": true + }, + "FriendlyName": { + "type": "string", + "nullable": true + }, + "ImportFavoritesOnly": { + "type": "boolean" + }, + "AllowHWTranscoding": { + "type": "boolean" + }, + "EnableStreamLooping": { + "type": "boolean" + }, + "Source": { + "type": "string", + "nullable": true + }, + "TunerCount": { + "type": "integer", + "format": "int32" + }, + "UserAgent": { + "type": "string", + "nullable": true + }, + "IgnoreDts": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "TypeOptions": { + "type": "object", + "properties": { + "Type": { + "type": "string", + "nullable": true + }, + "MetadataFetchers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "MetadataFetcherOrder": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "ImageFetchers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "ImageFetcherOrder": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "ImageOptions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageOption" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "UnratedItem": { + "enum": [ + "Movie", + "Trailer", + "Series", + "Music", + "Book", + "LiveTvChannel", + "LiveTvProgram", + "ChannelContent", + "Other" + ], + "type": "string", + "description": "An enum representing an unrated item." + }, + "UpdateLibraryOptionsDto": { + "type": "object", + "properties": { + "Id": { + "type": "string", + "description": "Gets or sets the library item id.", + "format": "uuid" + }, + "LibraryOptions": { + "allOf": [ + { + "$ref": "#/components/schemas/LibraryOptions" + } + ], + "description": "Gets or sets library options.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Update library options dto." + }, + "UpdateMediaPathRequestDto": { + "required": ["Name", "PathInfo"], + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the library name." + }, + "PathInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/MediaPathInfo" + } + ], + "description": "Gets or sets library folder path information." + } + }, + "additionalProperties": false, + "description": "Update library options dto." + }, + "UpdatePlaylistDto": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name of the new playlist.", + "nullable": true + }, + "Ids": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "description": "Gets or sets item ids of the playlist.", + "nullable": true + }, + "Users": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PlaylistUserPermissions" + }, + "description": "Gets or sets the playlist users.", + "nullable": true + }, + "IsPublic": { + "type": "boolean", + "description": "Gets or sets a value indicating whether the playlist is public.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Update existing playlist dto. Fields set to `null` will not be updated and keep their current values." + }, + "UpdatePlaylistUserDto": { + "type": "object", + "properties": { + "CanEdit": { + "type": "boolean", + "description": "Gets or sets a value indicating whether the user can edit the playlist.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Update existing playlist user dto. Fields set to `null` will not be updated and keep their current values." + }, + "UpdateUserItemDataDto": { + "type": "object", + "properties": { + "Rating": { + "type": "number", + "description": "Gets or sets the rating.", + "format": "double", + "nullable": true + }, + "PlayedPercentage": { + "type": "number", + "description": "Gets or sets the played percentage.", + "format": "double", + "nullable": true + }, + "UnplayedItemCount": { + "type": "integer", + "description": "Gets or sets the unplayed item count.", + "format": "int32", + "nullable": true + }, + "PlaybackPositionTicks": { + "type": "integer", + "description": "Gets or sets the playback position ticks.", + "format": "int64", + "nullable": true + }, + "PlayCount": { + "type": "integer", + "description": "Gets or sets the play count.", + "format": "int32", + "nullable": true + }, + "IsFavorite": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is favorite.", + "nullable": true + }, + "Likes": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this MediaBrowser.Model.Dto.UpdateUserItemDataDto is likes.", + "nullable": true + }, + "LastPlayedDate": { + "type": "string", + "description": "Gets or sets the last played date.", + "format": "date-time", + "nullable": true + }, + "Played": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this MediaBrowser.Model.Dto.UserItemDataDto is played.", + "nullable": true + }, + "Key": { + "type": "string", + "description": "Gets or sets the key.", + "nullable": true + }, + "ItemId": { + "type": "string", + "description": "Gets or sets the item identifier.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "This is used by the api to get information about a item user data." + }, + "UpdateUserPassword": { + "type": "object", + "properties": { + "CurrentPassword": { + "type": "string", + "description": "Gets or sets the current sha1-hashed password.", + "nullable": true + }, + "CurrentPw": { + "type": "string", + "description": "Gets or sets the current plain text password.", + "nullable": true + }, + "NewPw": { + "type": "string", + "description": "Gets or sets the new plain text password.", + "nullable": true + }, + "ResetPassword": { + "type": "boolean", + "description": "Gets or sets a value indicating whether to reset the password." + } + }, + "additionalProperties": false, + "description": "The update user password request body." + }, + "UploadSubtitleDto": { + "required": [ + "Data", + "Format", + "IsForced", + "IsHearingImpaired", + "Language" + ], + "type": "object", + "properties": { + "Language": { + "type": "string", + "description": "Gets or sets the subtitle language." + }, + "Format": { + "type": "string", + "description": "Gets or sets the subtitle format." + }, + "IsForced": { + "type": "boolean", + "description": "Gets or sets a value indicating whether the subtitle is forced." + }, + "IsHearingImpaired": { + "type": "boolean", + "description": "Gets or sets a value indicating whether the subtitle is for hearing impaired." + }, + "Data": { + "type": "string", + "description": "Gets or sets the subtitle data." + } + }, + "additionalProperties": false, + "description": "Upload subtitles dto." + }, + "UserConfiguration": { + "type": "object", + "properties": { + "AudioLanguagePreference": { + "type": "string", + "description": "Gets or sets the audio language preference.", + "nullable": true + }, + "PlayDefaultAudioTrack": { + "type": "boolean", + "description": "Gets or sets a value indicating whether [play default audio track]." + }, + "SubtitleLanguagePreference": { + "type": "string", + "description": "Gets or sets the subtitle language preference.", + "nullable": true + }, + "DisplayMissingEpisodes": { + "type": "boolean" + }, + "GroupedFolders": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + }, + "SubtitleMode": { + "enum": ["Default", "Always", "OnlyForced", "None", "Smart"], + "allOf": [ + { + "$ref": "#/components/schemas/SubtitlePlaybackMode" + } + ], + "description": "An enum representing a subtitle playback mode." + }, + "DisplayCollectionsView": { + "type": "boolean" + }, + "EnableLocalPassword": { + "type": "boolean" + }, + "OrderedViews": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + }, + "LatestItemsExcludes": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + }, + "MyMediaExcludes": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + }, + "HidePlayedInLatest": { + "type": "boolean" + }, + "RememberAudioSelections": { + "type": "boolean" + }, + "RememberSubtitleSelections": { + "type": "boolean" + }, + "EnableNextEpisodeAutoPlay": { + "type": "boolean" + }, + "CastReceiverId": { + "type": "string", + "description": "Gets or sets the id of the selected cast receiver.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class UserConfiguration." + }, + "UserDataChangedMessage": { + "type": "object", + "properties": { + "Data": { + "allOf": [ + { + "$ref": "#/components/schemas/UserDataChangeInfo" + } + ], + "description": "Gets or sets the data.", + "nullable": true + }, + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "UserDataChanged", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "User data changed message." + }, + "UserDataChangeInfo": { + "type": "object", + "properties": { + "UserId": { + "type": "string", + "description": "Gets or sets the user id.", + "nullable": true + }, + "UserDataList": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserItemDataDto" + }, + "description": "Gets or sets the user data list.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class UserDataChangeInfo." + }, + "UserDeletedMessage": { + "type": "object", + "properties": { + "Data": { + "type": "string", + "description": "Gets or sets the data.", + "format": "uuid" + }, + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "UserDeleted", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "User deleted message." + }, + "UserDto": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + }, + "ServerId": { + "type": "string", + "description": "Gets or sets the server identifier.", + "nullable": true + }, + "ServerName": { + "type": "string", + "description": "Gets or sets the name of the server.\r\nThis is not used by the server and is for client-side usage only.", + "nullable": true + }, + "Id": { + "type": "string", + "description": "Gets or sets the id.", + "format": "uuid" + }, + "PrimaryImageTag": { + "type": "string", + "description": "Gets or sets the primary image tag.", + "nullable": true + }, + "HasPassword": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance has password." + }, + "HasConfiguredPassword": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance has configured password." + }, + "HasConfiguredEasyPassword": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance has configured easy password.", + "deprecated": true + }, + "EnableAutoLogin": { + "type": "boolean", + "description": "Gets or sets whether async login is enabled or not.", + "nullable": true + }, + "LastLoginDate": { + "type": "string", + "description": "Gets or sets the last login date.", + "format": "date-time", + "nullable": true + }, + "LastActivityDate": { + "type": "string", + "description": "Gets or sets the last activity date.", + "format": "date-time", + "nullable": true + }, + "Configuration": { + "allOf": [ + { + "$ref": "#/components/schemas/UserConfiguration" + } + ], + "description": "Gets or sets the configuration.", + "nullable": true + }, + "Policy": { + "allOf": [ + { + "$ref": "#/components/schemas/UserPolicy" + } + ], + "description": "Gets or sets the policy.", + "nullable": true + }, + "PrimaryImageAspectRatio": { + "type": "number", + "description": "Gets or sets the primary image aspect ratio.", + "format": "double", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class UserDto." + }, + "UserInterfaceConfiguration": { + "type": "object", + "properties": { + "SkipButtonVisible": { + "type": "boolean" + }, + "SkipButtonIntroText": { + "type": "string" + }, + "SkipButtonEndCreditsText": { + "type": "string" + } + }, + "additionalProperties": false + }, + "UserItemDataDto": { + "type": "object", + "properties": { + "Rating": { + "type": "number", + "description": "Gets or sets the rating.", + "format": "double", + "nullable": true + }, + "PlayedPercentage": { + "type": "number", + "description": "Gets or sets the played percentage.", + "format": "double", + "nullable": true + }, + "UnplayedItemCount": { + "type": "integer", + "description": "Gets or sets the unplayed item count.", + "format": "int32", + "nullable": true + }, + "PlaybackPositionTicks": { + "type": "integer", + "description": "Gets or sets the playback position ticks.", + "format": "int64" + }, + "PlayCount": { + "type": "integer", + "description": "Gets or sets the play count.", + "format": "int32" + }, + "IsFavorite": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is favorite." + }, + "Likes": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this MediaBrowser.Model.Dto.UserItemDataDto is likes.", + "nullable": true + }, + "LastPlayedDate": { + "type": "string", + "description": "Gets or sets the last played date.", + "format": "date-time", + "nullable": true + }, + "Played": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this MediaBrowser.Model.Dto.UserItemDataDto is played." + }, + "Key": { + "type": "string", + "description": "Gets or sets the key.", + "nullable": true + }, + "ItemId": { + "type": "string", + "description": "Gets or sets the item identifier.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class UserItemDataDto." + }, + "UserPolicy": { + "required": ["AuthenticationProviderId", "PasswordResetProviderId"], + "type": "object", + "properties": { + "IsAdministrator": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is administrator." + }, + "IsHidden": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is hidden." + }, + "EnableCollectionManagement": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance can manage collections.", + "default": false + }, + "EnableSubtitleManagement": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance can manage subtitles.", + "default": false + }, + "EnableLyricManagement": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this user can manage lyrics.", + "default": false + }, + "IsDisabled": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this instance is disabled." + }, + "MaxParentalRating": { + "type": "integer", + "description": "Gets or sets the max parental rating.", + "format": "int32", + "nullable": true + }, + "BlockedTags": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "AllowedTags": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "EnableUserPreferenceAccess": { + "type": "boolean" + }, + "AccessSchedules": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AccessSchedule" + }, + "nullable": true + }, + "BlockUnratedItems": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UnratedItem" + }, + "nullable": true + }, + "EnableRemoteControlOfOtherUsers": { + "type": "boolean" + }, + "EnableSharedDeviceControl": { + "type": "boolean" + }, + "EnableRemoteAccess": { + "type": "boolean" + }, + "EnableLiveTvManagement": { + "type": "boolean" + }, + "EnableLiveTvAccess": { + "type": "boolean" + }, + "EnableMediaPlayback": { + "type": "boolean" + }, + "EnableAudioPlaybackTranscoding": { + "type": "boolean" + }, + "EnableVideoPlaybackTranscoding": { + "type": "boolean" + }, + "EnablePlaybackRemuxing": { + "type": "boolean" + }, + "ForceRemoteSourceTranscoding": { + "type": "boolean" + }, + "EnableContentDeletion": { + "type": "boolean" + }, + "EnableContentDeletionFromFolders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "EnableContentDownloading": { + "type": "boolean" + }, + "EnableSyncTranscoding": { + "type": "boolean", + "description": "Gets or sets a value indicating whether [enable synchronize]." + }, + "EnableMediaConversion": { + "type": "boolean" + }, + "EnabledDevices": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "EnableAllDevices": { + "type": "boolean" + }, + "EnabledChannels": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "nullable": true + }, + "EnableAllChannels": { + "type": "boolean" + }, + "EnabledFolders": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "nullable": true + }, + "EnableAllFolders": { + "type": "boolean" + }, + "InvalidLoginAttemptCount": { + "type": "integer", + "format": "int32" + }, + "LoginAttemptsBeforeLockout": { + "type": "integer", + "format": "int32" + }, + "MaxActiveSessions": { + "type": "integer", + "format": "int32" + }, + "EnablePublicSharing": { + "type": "boolean" + }, + "BlockedMediaFolders": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "nullable": true + }, + "BlockedChannels": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "nullable": true + }, + "RemoteClientBitrateLimit": { + "type": "integer", + "format": "int32" + }, + "AuthenticationProviderId": { + "type": "string" + }, + "PasswordResetProviderId": { + "type": "string" + }, + "SyncPlayAccess": { + "enum": ["CreateAndJoinGroups", "JoinGroups", "None"], + "allOf": [ + { + "$ref": "#/components/schemas/SyncPlayUserAccessType" + } + ], + "description": "Enum SyncPlayUserAccessType." + } + }, + "additionalProperties": false + }, + "UserUpdatedMessage": { + "type": "object", + "properties": { + "Data": { + "allOf": [ + { + "$ref": "#/components/schemas/UserDto" + } + ], + "description": "Gets or sets the data.", + "nullable": true + }, + "MessageId": { + "type": "string", + "description": "Gets or sets the message id.", + "format": "uuid" + }, + "MessageType": { + "enum": [ + "ForceKeepAlive", + "GeneralCommand", + "UserDataChanged", + "Sessions", + "Play", + "SyncPlayCommand", + "SyncPlayGroupUpdate", + "Playstate", + "RestartRequired", + "ServerShuttingDown", + "ServerRestarting", + "LibraryChanged", + "UserDeleted", + "UserUpdated", + "SeriesTimerCreated", + "TimerCreated", + "SeriesTimerCancelled", + "TimerCancelled", + "RefreshProgress", + "ScheduledTaskEnded", + "PackageInstallationCancelled", + "PackageInstallationFailed", + "PackageInstallationCompleted", + "PackageInstalling", + "PackageUninstalled", + "ActivityLogEntry", + "ScheduledTasksInfo", + "ActivityLogEntryStart", + "ActivityLogEntryStop", + "SessionsStart", + "SessionsStop", + "ScheduledTasksInfoStart", + "ScheduledTasksInfoStop", + "KeepAlive" + ], + "allOf": [ + { + "$ref": "#/components/schemas/SessionMessageType" + } + ], + "description": "The different kinds of messages that are used in the WebSocket api.", + "default": "UserUpdated", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "User updated message." + }, + "UtcTimeResponse": { + "type": "object", + "properties": { + "RequestReceptionTime": { + "type": "string", + "description": "Gets the UTC time when request has been received.", + "format": "date-time" + }, + "ResponseTransmissionTime": { + "type": "string", + "description": "Gets the UTC time when response has been sent.", + "format": "date-time" + } + }, + "additionalProperties": false, + "description": "Class UtcTimeResponse." + }, + "ValidatePathDto": { + "type": "object", + "properties": { + "ValidateWritable": { + "type": "boolean", + "description": "Gets or sets a value indicating whether validate if path is writable." + }, + "Path": { + "type": "string", + "description": "Gets or sets the path.", + "nullable": true + }, + "IsFile": { + "type": "boolean", + "description": "Gets or sets is path file.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Validate path object." + }, + "VersionInfo": { + "type": "object", + "properties": { + "version": { + "type": "string", + "description": "Gets or sets the version." + }, + "VersionNumber": { + "type": "string", + "description": "Gets the version as a System.Version.", + "readOnly": true + }, + "changelog": { + "type": "string", + "description": "Gets or sets the changelog for this version.", + "nullable": true + }, + "targetAbi": { + "type": "string", + "description": "Gets or sets the ABI that this version was built against.", + "nullable": true + }, + "sourceUrl": { + "type": "string", + "description": "Gets or sets the source URL.", + "nullable": true + }, + "checksum": { + "type": "string", + "description": "Gets or sets a checksum for the binary.", + "nullable": true + }, + "timestamp": { + "type": "string", + "description": "Gets or sets a timestamp of when the binary was built.", + "nullable": true + }, + "repositoryName": { + "type": "string", + "description": "Gets or sets the repository name." + }, + "repositoryUrl": { + "type": "string", + "description": "Gets or sets the repository url." + } + }, + "additionalProperties": false, + "description": "Defines the MediaBrowser.Model.Updates.VersionInfo class." + }, + "Video3DFormat": { + "enum": [ + "HalfSideBySide", + "FullSideBySide", + "FullTopAndBottom", + "HalfTopAndBottom", + "MVC" + ], + "type": "string" + }, + "VideoRange": { + "enum": ["Unknown", "SDR", "HDR"], + "type": "string", + "description": "An enum representing video ranges." + }, + "VideoRangeType": { + "enum": [ + "Unknown", + "SDR", + "HDR10", + "HLG", + "DOVI", + "DOVIWithHDR10", + "DOVIWithHLG", + "DOVIWithSDR", + "HDR10Plus" + ], + "type": "string", + "description": "An enum representing types of video ranges." + }, + "VideoType": { + "enum": ["VideoFile", "Iso", "Dvd", "BluRay"], + "type": "string", + "description": "Enum VideoType." + }, + "VirtualFolderInfo": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + }, + "Locations": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Gets or sets the locations.", + "nullable": true + }, + "CollectionType": { + "enum": [ + "movies", + "tvshows", + "music", + "musicvideos", + "homevideos", + "boxsets", + "books", + "mixed" + ], + "allOf": [ + { + "$ref": "#/components/schemas/CollectionTypeOptions" + } + ], + "description": "Gets or sets the type of the collection.", + "nullable": true + }, + "LibraryOptions": { + "allOf": [ + { + "$ref": "#/components/schemas/LibraryOptions" + } + ], + "nullable": true + }, + "ItemId": { + "type": "string", + "description": "Gets or sets the item identifier.", + "nullable": true + }, + "PrimaryImageItemId": { + "type": "string", + "description": "Gets or sets the primary image item identifier.", + "nullable": true + }, + "RefreshProgress": { + "type": "number", + "format": "double", + "nullable": true + }, + "RefreshStatus": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Used to hold information about a user's list of configured virtual folders." + }, + "WakeOnLanInfo": { + "type": "object", + "properties": { + "MacAddress": { + "type": "string", + "description": "Gets the MAC address of the device.", + "nullable": true + }, + "Port": { + "type": "integer", + "description": "Gets or sets the wake-on-LAN port.", + "format": "int32" + } + }, + "additionalProperties": false, + "description": "Provides the MAC address and port for wake-on-LAN functionality." + }, + "WebSocketMessage": { + "type": "object", + "oneOf": [ + { + "$ref": "#/components/schemas/InboundWebSocketMessage" + }, + { + "$ref": "#/components/schemas/OutboundWebSocketMessage" + } + ], + "description": "Represents the possible websocket types" + }, + "XbmcMetadataOptions": { + "type": "object", + "properties": { + "UserId": { + "type": "string", + "nullable": true + }, + "ReleaseDateFormat": { + "type": "string" + }, + "SaveImagePathsInNfo": { + "type": "boolean" + }, + "EnablePathSubstitution": { + "type": "boolean" + }, + "EnableExtraThumbsDuplication": { + "type": "boolean" + } + }, + "additionalProperties": false + } + }, + "securitySchemes": { + "CustomAuthentication": { + "type": "apiKey", + "description": "API key header parameter", + "name": "Authorization", + "in": "header" + } + } + } +} diff --git a/test/widget_test.dart b/test/widget_test.dart new file mode 100644 index 0000000..d485d0a --- /dev/null +++ b/test/widget_test.dart @@ -0,0 +1,29 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility in the flutter_test package. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:fladder/main.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(const Main()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +} diff --git a/true b/true new file mode 100644 index 0000000..1314731 --- /dev/null +++ b/true @@ -0,0 +1,5 @@ +{ + "nl": [ + "library" + ] +} diff --git a/web/favicon.png b/web/favicon.png new file mode 100644 index 0000000..2c555c8 Binary files /dev/null and b/web/favicon.png differ diff --git a/web/icons/Icon-192.png b/web/icons/Icon-192.png new file mode 100644 index 0000000..fa7e110 Binary files /dev/null and b/web/icons/Icon-192.png differ diff --git a/web/icons/Icon-512.png b/web/icons/Icon-512.png new file mode 100644 index 0000000..8c9490f Binary files /dev/null and b/web/icons/Icon-512.png differ diff --git a/web/icons/Icon-maskable-192.png b/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000..fa7e110 Binary files /dev/null and b/web/icons/Icon-maskable-192.png differ diff --git a/web/icons/Icon-maskable-512.png b/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000..8c9490f Binary files /dev/null and b/web/icons/Icon-maskable-512.png differ diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..e521687 --- /dev/null +++ b/web/index.html @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + fladder + + + + + + + + + + diff --git a/web/manifest.json b/web/manifest.json new file mode 100644 index 0000000..b2a8824 --- /dev/null +++ b/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "fladder", + "short_name": "fladder", + "start_url": ".", + "display": "standalone", + "background_color": "#5B364D", + "theme_color": "#5B364D", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} \ No newline at end of file diff --git a/windows/.gitignore b/windows/.gitignore new file mode 100644 index 0000000..d492d0d --- /dev/null +++ b/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt new file mode 100644 index 0000000..9aea5e8 --- /dev/null +++ b/windows/CMakeLists.txt @@ -0,0 +1,101 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(fladder LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "fladder") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/windows/flutter/CMakeLists.txt b/windows/flutter/CMakeLists.txt new file mode 100644 index 0000000..903f489 --- /dev/null +++ b/windows/flutter/CMakeLists.txt @@ -0,0 +1,109 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + ${FLUTTER_TARGET_PLATFORM} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000..b26f116 --- /dev/null +++ b/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,47 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void RegisterPlugins(flutter::PluginRegistry* registry) { + DesktopDropPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("DesktopDropPlugin")); + DynamicColorPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("DynamicColorPluginCApi")); + IsarFlutterLibsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("IsarFlutterLibsPlugin")); + LocalAuthPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("LocalAuthPlugin")); + MediaKitLibsWindowsVideoPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("MediaKitLibsWindowsVideoPluginCApi")); + MediaKitVideoPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("MediaKitVideoPluginCApi")); + PermissionHandlerWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); + ScreenBrightnessWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ScreenBrightnessWindowsPlugin")); + ScreenRetrieverPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ScreenRetrieverPlugin")); + SharePlusWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi")); + UrlLauncherWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("UrlLauncherWindows")); + WindowManagerPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("WindowManagerPlugin")); +} diff --git a/windows/flutter/generated_plugin_registrant.h b/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000..dc139d8 --- /dev/null +++ b/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake new file mode 100644 index 0000000..fa7bb92 --- /dev/null +++ b/windows/flutter/generated_plugins.cmake @@ -0,0 +1,37 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + desktop_drop + dynamic_color + isar_flutter_libs + local_auth_windows + media_kit_libs_windows_video + media_kit_video + permission_handler_windows + screen_brightness_windows + screen_retriever + share_plus + url_launcher_windows + window_manager +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST + media_kit_native_event_loop + smtc_windows +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/windows/runner/CMakeLists.txt b/windows/runner/CMakeLists.txt new file mode 100644 index 0000000..394917c --- /dev/null +++ b/windows/runner/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/windows/runner/Runner.rc b/windows/runner/Runner.rc new file mode 100644 index 0000000..1bc5757 --- /dev/null +++ b/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.example" "\0" + VALUE "FileDescription", "fladder" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "nl.jknaapen.fladder" "\0" + VALUE "LegalCopyright", "Copyright (C) 2023 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "fladder.exe" "\0" + VALUE "ProductName", "fladder" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/windows/runner/flutter_window.cpp b/windows/runner/flutter_window.cpp new file mode 100644 index 0000000..955ee30 --- /dev/null +++ b/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + + // Flutter can complete the first frame before the "show window" callback is + // registered. The following call ensures a frame is pending to ensure the + // window is shown. It is a no-op if the first frame hasn't completed yet. + flutter_controller_->ForceRedraw(); + + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/windows/runner/flutter_window.h b/windows/runner/flutter_window.h new file mode 100644 index 0000000..6da0652 --- /dev/null +++ b/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/windows/runner/main.cpp b/windows/runner/main.cpp new file mode 100644 index 0000000..b547f21 --- /dev/null +++ b/windows/runner/main.cpp @@ -0,0 +1,47 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) +{ + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) + { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.Create(L"Fladder", origin, size)) + { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) + { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/windows/runner/resource.h b/windows/runner/resource.h new file mode 100644 index 0000000..66a65d1 --- /dev/null +++ b/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/windows/runner/resources/app_icon.ico b/windows/runner/resources/app_icon.ico new file mode 100644 index 0000000..00abc7f Binary files /dev/null and b/windows/runner/resources/app_icon.ico differ diff --git a/windows/runner/runner.exe.manifest b/windows/runner/runner.exe.manifest new file mode 100644 index 0000000..a42ea76 --- /dev/null +++ b/windows/runner/runner.exe.manifest @@ -0,0 +1,20 @@ + + + + + PerMonitorV2 + + + + + + + + + + + + + + + diff --git a/windows/runner/utils.cpp b/windows/runner/utils.cpp new file mode 100644 index 0000000..f5bf9fa --- /dev/null +++ b/windows/runner/utils.cpp @@ -0,0 +1,64 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr); + std::string utf8_string; + if (target_length == 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, utf8_string.data(), + target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/windows/runner/utils.h b/windows/runner/utils.h new file mode 100644 index 0000000..3879d54 --- /dev/null +++ b/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/windows/runner/win32_window.cpp b/windows/runner/win32_window.cpp new file mode 100644 index 0000000..041a385 --- /dev/null +++ b/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#include "resource.h" + +namespace { + +/// Window attribute that enables dark mode window decorations. +/// +/// Redefined in case the developer's machine has a Windows SDK older than +/// version 10.0.22000.0. +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +/// Registry key for app theme preference. +/// +/// A value of 0 indicates apps should use dark mode. A non-zero or missing +/// value indicates apps should use light mode. +constexpr const wchar_t kGetPreferredBrightnessRegKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + } + FreeLibrary(user32_module); +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + UpdateTheme(window); + + return OnCreate(); +} + +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} + +void Win32Window::UpdateTheme(HWND const window) { + DWORD light_mode; + DWORD light_mode_size = sizeof(light_mode); + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + kGetPreferredBrightnessRegValue, + RRF_RT_REG_DWORD, nullptr, &light_mode, + &light_mode_size); + + if (result == ERROR_SUCCESS) { + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); + } +} diff --git a/windows/runner/win32_window.h b/windows/runner/win32_window.h new file mode 100644 index 0000000..c86632d --- /dev/null +++ b/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates a win32 window with |title| that is positioned and sized using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responsponds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + // Update the window frame's theme to match the system theme. + static void UpdateTheme(HWND const window); + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_